5makefile

时间:2023-03-09 19:50:55
5makefile

makefile编译多个可执行文件
1: 多个 C 文件编译成不同的目标文件
2: 多个 C 文件编译成 一个目标文件

注意:makefile的文件名的三种形式(优先级排序)
makefile>Makefile>GNUMakefile

简单说,makefile类似快捷键。
如:创建主函数文件mian.c 函数文件func.c
编译二进制:
gcc -g -Wall -c main.c -o mian.o
gcc -g -Wall -c func.c -o func.o
链接并生成可执行文件:
gcc -Wall main.o func.o -o main
此时可以看到只用两个文件都如此麻烦,一旦许多文件呢?或对mian.c进行修改后,还要再一次编译

解决方式:
创建一个makefile的文件:
main:main.o func.o
gcc -g -Wall mainn.o func.o -o main
main.o:main.c
gcc -g -Wall -c mainn.c func.o -o main.o
func.o:func.c
gcc -g -Wall -c func.c func.o -o func.o

执行:make
解析:
main依赖于main.o func.o,一定要就此句在第一个。因此makefile只编译第一个语句。main.o,func.o将会向下寻找。即使重新修改文件内容,只需再一次make就自动编译
如果:
main.o:main.c
gcc -g -Wall -c mainn.c func.o -o main.o
main:main.o func.o
gcc -g -Wall mainn.o func.o -o main
func.o:func.c
gcc -g -Wall -c func.c func.o -o func.o
此时,只编译
main.o:main.c
gcc -g -Wall -c mainn.c func.o -o main.o
后面两个不进行编译。

make工具
自动完成编译工作
1:修改某个文件后,只重新编译修改的文件
2:修改某个头文件后,重新编译所有包含该头文件的文件

makefile 描述了整个工程编译,链接的规则
make工具通过makefile文件来完成、维护编译工作

makefile基本规则
Target ... : dependencies ...
[ Tab ] command
...

Target: 程序生成的文件,或者要指向的动作,如clean
dependencies:目标文件依赖的文件
command:make执行的动作(以 TAB字符开始!!!)
dependencies 中文件更新时候,执行command

例子:
main:main.o add.o sub.o
gcc -Wall -g main.o sub.o add.o -o main
main.o:main.c
gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
gcc -Wall -g -c sub.c -o sub.o
clean:
rm -f main main.o add.o sub.o

make ==》按需生成文件
make ==》修改时间未改变,则不会重新编译
make ... 生成某个目标(或者伪目标clean),不加则默认生成第一个模板

显式指定伪目标
上面的makefile文件,如果目录下存在clean文件
结果: make clean失效
解决办法:需要显示指定 clean 是伪目标, 文件开头加上:.PHONY:clean
.PHONY: 表示这是一个伪目标

定义变量
makefile自动化变量
$@: 规则的目标文件名
$< : 规则的第一个依赖文件名
$^ : 规则的所有依赖文件列表

举例 add.o:add.c add.h
$@ 为 add.o
$< 为 add.c
$^ 为 add.c add.h
自定义变量
var=....... ? 使用变量 $(var)

使用变量的例子:
.PHONY:clean
OBJ=main.o add.o sub.o
main:$(OBJ)
gcc -Wall -g $^ -o $@
main.o:main.c
gcc -Wall -g -c $< -o $@
add.o:add.c add.h
gcc -Wall -g -c $< -o $@
sub.o:sub.c sub.h
gcc -Wall -g -c $< -o $@
clean:
rm -rf $(OBJ)

改进:
.PHONY:clean
BIN=main
CC=gcc
CFLAGS=-Wall -g
OBJ=main.o add.o sub.o
$(BIN):$(OBJ)
$(CC) $(CFLAGS) $^ -o $@
main.o:main.c
$(CC) $(CFLAGS) -c $< -o $@
add.o:add.c add.h
$(CC) $(CFLAGS)-c $< -o $@
sub.o:sub.c sub.h
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf *.o $(BIN)

自定义的变量一般使用大写。
注意:通过 –f 参数,指定需要用到的makefile文件make –f makefile.1 自定义使用的makefile文件

自动推导
编译器会自动推导,
同名的 .c 文件生成同名目标文件
默认使用隐含方式生成,不想使用自动推导则自行添加生成方式
cc –c –o xxx.o xxx.c

模式匹配
规则 1:
%.o:%.c
gcc -Wall -g -c $< -o $@

规则2:
.c.o:
gcc -Wall -g -c $< -o $@
规则2注意 .c.o之间不能由空格

编译目录下所有.c 文件
$(BIN):%:%.o
所有的 $(BIN) 文件生成规则:
$(BIN)中没有扩展名的文件依赖于对应扩展名为.o 的文件

编译多个可执行文件
makefile 默认生成第一个对象
要生成对个对象的话,可以使用自定义变量
.PHONY:clean all
OBJ=test1 test2
all:$(OBJ)
...
这里: all 是一个伪目标,makefile 要生成 all, 也就是 test1, test2

make常用内嵌函数
函数调用
$(function arguments)
$(wildcard 模式)
当前目录下匹配模式的文件:
获取所有.c文件
src = $(wildcard *.c)

把src的 .c替换为.o
$(src :%.c=%.o)
obj = $(src:%.c=%.o)

shell函数
执行shell命令: $(shell ls –d */) 获取所有子目录

例子改进:
.PHONY:clean all
SRC=$(wildcard *.c)
OBJ=$(SRC:%.c=%.o)
BIN=$(SRC:$.c=%)

CC=gcc
CFLAGS=-Wall -g

all:$(BIN)
%.o:%.c
$(CC) $(SFLAGS) $^ -o %@
clean:
rm -f $(BIN) $(OBJ)

多级目录makefile
SUBDIRS=test1 test2
.PHONY:default all clean $(SUBDIRS)
default:all #无参数,则生成all

all clean: #all 和 clean都依赖下面语句
$(MAKE) $(SUBDIRS) TARGET=$@ #make test1 test2 ;赋值 TARGET=all
$(SBUDIRS):
$(MAKE) -C $@ $(TARGET)
#make –C test1 all: 调用test1中make,并以all为入参。 make test1/makefile all
注意-C大写

C语言版
makefile万能模板:

.PHONY:clean all
SRC=$(wildcard *.c)
BIN=$(SRC:%.c=%)

CC=gcc
CFLAGS=-g -Wall

all:$(BIN)

clean:
rm -rf $(BIN)
~

C++版
.PHONY:all clean

SRC=$(wildcard *.c)
BIN=$(SRC:%.c=%)

CPPSRC=$(wildcard *.cpp)
CPPBIN=$(CPPSRC:%.cpp=%)

CC=gcc
CXX=g++
CFLAGS=-g -Wall
CXXFLAGS=-g -Wall -std=c++11

all:$(BIN) //$(CPPBIN)

clean:
rm -rf $(BIN) //$(CPPBIN)