Makefile | 爱编程的大丙 (subingwen.cn)https://subingwen.cn/linux/makefile/
make命令执行时需要读取Makefile文件中的规则
规则格式
#每条规则的语法格式
目标:依赖(依赖可以没有)
target1,target2...:depend1,depend2..
命令
command
make默认只会执行第一条规则,检查第一条规则中依赖文件是否都存在,如果不存在,他就去读其他规则,直到找到目标文件是该依赖文件的规则,如此反复就构建完成了.
如果只想执行其中某条规则,可以用make 目标名,还有一些潜规则
1.make发现所有的依赖都存在,目标不存在,那么就生成目标
2.make发现所有的依赖,目标都存在,但是目标生成时间早于依赖,那么就更新目标
3.make发现所有的依赖,目标都存在,但是目标生成时间晚于依赖,那么就不更新目标
calc:add.o sub.o mult.o div.o main.o
gcc add.o sub.o mult.o div.o main.o -o calc
如果一段代码这样的,所有的依赖文件和目标文件都不存在,也没有规则生成这些依赖文件,make就会执行自动推导,找当前目录下的main.c,add.c和sub.c来生成依赖文件
第一种 普通写法
calc:add.o sub.o mult.o div.o main.o
gcc add.o sub.o mult.o div.o main.o -o calc
add.o:add.c
gcc -Wall -c add.c -o add.o
sub.o:sub.c
gcc -Wall -c sub.c -o sub.o
mult.o:mult.c
gcc -Wall -c mult.c -o mult.o
div.o:div.c
gcc -Wall -c div.c -o div.o
main.o:main.c
gcc -Wall -c main.c -o main.o
clean:
rm -rf add.o sub.o mult.o div.o main.o calc
第二种 变量写法
TAR = calc
OBJ = add.o sub.o mult.o div.o main.o
CC = gcc
CFLAGS += -Wall -c
$(TAR):$(OBJ)
$(CC) $(OBJ) -o $(TAR)
add.o:add.c
$(CC) $(CFLAGS) add.c -o add.o
sub.o:sub.c
$(CC) $(CFLAGS) sub.c -o sub.o
mult.o:mult.c
$(CC) $(CFLAGS) mult.c -o mult.o
div.o:div.c
$(CC) $(CFLAGS) div.c -o div.o
main.o:main.c
$(CC) $(CFLAGS) main.c -o main.o
clean:
$(RM) -r $(OBJ) $(TAR)
make的预定义变量
变 量 名 | 含 义 | 默 认 值 |
AR | 生成静态库库文件的程序名称 | ar |
AS | 汇编编译器的名称 | as |
CC | C 语言编译器的名称 | cc |
CPP | C 语言预编译器的名称 | $(CC) -E |
CXX | C++ 语言编译器的名称 | g++ |
FC | FORTRAN 语言编译器的名称 | f77 |
RM | 删除文件程序的名称 | rm -f |
ARFLAGS | 生成静态库库文件程序的选项 | 无默认值 |
ASFLAGS | 汇编语言编译器的编译选项 | 无默认值 |
CFLAGS | C 语言编译器的编译选项 | 无默认值 |
CPPFLAGS | C 语言预编译的编译选项 | 无默认值 |
CXXFLAGS | C++ 语言编译器的编译选项 | 无默认值 |
FFLAGS | FORTRAN 语言编译器的编译选项 | 无默认值 |
第三种 自动变量写法
$@ 表示目标文件的名称,包含文件扩展名
$* 表示目标文件的名称,不包含目标文件的扩展名
$^ 依赖项中,所有不重复的依赖文件,这些文件之间以空格分开
$+ 表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能 包含重复的依赖文件
$< 表示依赖项中第一个依赖文件的名称
$? 依赖项中,所有比目标文件时间戳晚的依赖文件,依赖文件之间以空格分开
TAR = calc
OBJ = add.o sub.o mult.o div.o main.o
CC = gcc
CFLAGS += -Wall -c
$(TAR):$(OBJ)
$(CC) $^ -o $@
//$^:上一句中的依赖文件名字
//$@:上一句中的目标文件名字
add.o:add.c
$(CC) $(CFLAGS) $^ -o $@
sub.o:sub.c
$(CC) $(CFLAGS) $^ -o $@
mult.o:mult.c
$(CC) $(CFLAGS) $^ -o $@
div.o:div.c
$(CC) $(CFLAGS) $^ -o $@
main.o:main.c
$(CC) $(CFLAGS) $^ -o $@
clean:
$(RM) -r $(OBJ) $(TAR)
第四种 模式匹配写法
TAR = calc
OBJ = add.o sub.o mult.o div.o main.o
CC = gcc
CFLAGS += -Wall -c
$(TAR):$(OBJ)
$(CC) $(CFLAGS) $^ -o $@
%o:%c
$(CC) $(CFLAGS) $^ -o $@
//%:可以认为是在通配符
//根据所有需要需要的.o,推倒出所需要的.c文件
clean:
$(RM) -r $(OBJ) $(TAR)
%c %o 任意的.c或者.o文件
*.c *.o 所有的.c .o文件
TAR = calc
OBJ = add.o sub.o mult.o div.o main.o
CC = gcc
CFLAGS += -Wall -c
$(TAR):$(OBJ)
$(CC) $(OBJ) -o $(TAR)
%o:%c
$(CC) $(CFLAGS) %.c -o %.o //gcc -c $<
clean:
$(RM) -r $(OBJ)
第五种 函数写法
src = $(wildcard /home/robin/a/*.c /home/robin/b/*.c *.c)
搜索/home/robin/a/,/home/robin/b/和当前目录下的所有.c文件赋值给src变量
src = a.cpp b.cpp c.cpp e.cpp
# 把变量 src 中的所有文件名的后缀从 .cpp 替换为 .o
obj = $(patsubst %.cpp, %.o, $(src))
# obj 的值为: a.o b.o c.o e.o
TAR = main
SRC = $(wildcard *.c)
OBJ = $(patsubst %.cpp, %.o, $(src))
CC = gcc
$(TAR):$(OBJ)
$(CC) -c $^ -o $@
%o:%c
$(CC) -c $^
clean:
rm $(OBJ) $(TAR)
如果一个规则没有生成对应的目标文件,那么就称之为伪目标,
在 makefile 中声明一个伪目标需要使用 .PHONY 关键字,声明方式为: .PHONY:伪文件名称
# 添加规则, 删除生成文件 *.o 可执行程序
# 声明clean为伪文件
.PHONY:clean
clean:
# shell命令前的 - 表示强制这个指令执行, 如果执行失败,也不会终止,继续执行下一条命令
-rm $(obj) $(target)
echo "删除失败"