如果某一行是命令,则必须以一个tab键开头。命令行之间可以插入空行,此间的空行也要以tab键开头?
符号$表示使用变量或调用函数
1、make工具的退出码
makefile文件执行后有一个退出码:0 表示成功; 1 表示出错; 2 ...
2、使用“:=”操作符
使用":="操作符定义变量的值可以避免递归定义的危险。使用其定义变量时,前面的变量不能使用后面的变量,只能使用前面已定义好的变量。如果使用前面未定义的变量,则该变量的值为空。
3、追加变量的值
makefile文件允许给一个变量追加一个值,其操作符为“+=”。例:
OBJECTS = main.o fun.o bar.o utils.o OBJECTS += another.o 等价于
OBJECTS = main.o fun.o bar.o utils.o OBJECTS = $(OBJECTS) another.o
如果变量之前没有定义过,“+=”操作符会自动变成"="操作符。如果前一次为变量定义时使用的是":="操作符,“+=”会以":="作为其赋值符。
“=”赋值的变量是递归展开变量,“:=”赋值的变量是立即展开变量,“?=”条件赋值,“+=”追加赋值
OBJECTS := main.o fun.o bar.o utils.o OBJECTS += another.o 等价于
OBJECTS := main.o fun.o bar.o utils.o OBJECTS := $(OBJECTS) another.o
4、makefile实例
若某个项目的源代码按模块分类分别存储在多个目录下,每个模块的目录内都有各自的makefile文件。
project目录下:hello(目录)、include(目录)、list(目录)、Makefile(makefile文件)
project/hello目录下:hello.c makefile
project/include目录下:hello.h list.h
project/list目录下:list.c makefile
由此可以分别写出各自目录内的makefile文件。使用该makefile文件就可以将所有的源文件进行编译,并且生成一个可执行程序。
(1)hello目录下的makefile文件
1 hello: hello.o
2 gcc -o hello hello.o
3 hello.o: hello.c
4 gcc -c hello.c
5
6 .PHONY: clean
7 clean:
8 rm -rf hello hello.o
(2)list目录下的makefile文件
1 list: list.o
2 gcc -o list list.o
3 list.o: list.c
4 gcc -c list.c
5
6 .PHONY: clean
7 clean:
8 rm -rf list list.o
(3)project目录下的makefile文件
? make --directory=$$n
1 SUBDIRS := list hello # 子目录
2
3 .PHONY: all
4 all: modules
5
6 .PHONY: modules
7 modules:
8 for n in $(SUBDIRS) # 进入每一个子目录
9 do
10 exit = make --directory=$$n # 调用子目录中的makefile
11 if[ $(exit) == "1" ] # 检查makefile的退出状态码
12 then
13 exit 1
14 fi
15 done
16
17 .PHONY: clean
18 clean:
19 for n in $(SUBDIRS) # 进入每一个子目录
20 do
21 make --directory=$$n clean # 调用子目录中的makefile,并且执行clean
22 done
5、一个目录中生成多个可执行程序
使用一个称为all的伪目标来作为终极目标,它的依赖文件就是那些需要创建的可执行程序
all: build_1 build_2
.PHONY: all
build_1: test1.c test1.h
gcc -o build_1 test1.c
build_2: test2.c test2.h
gcc -o build_2 test2.c
当需要单独更新一个程序时,可以通过命令选项来明确指定需要生成的程序。如:make build_2
6、特殊目标
.PHONY:目标.PHONY的所有依赖被成为伪目标。当使用make指定此目标时(如,make clean),这个目标所在规则中的命令无论目标文件是否存在都会被无条件执行。
.IGNORE:对于.IGNORE后面跟的依赖文件,生成这些依赖文件的命令在执行时如果遇到错误,make将忽略错误继续执行。它的功能类似于命令行属性的减号“-”。
.SILENT:对于该目标依赖的文件,执行生成依赖文件的命令时,make不会打印出所执行的命令。它的功能类似于命令行属性的“@”。
7、搜索目录
当前目录永远是第一搜索目录
VPATH变量
例,VPATH = /usr/src:../headers 为所有规则指定了两个搜索目录,/usr/src和../headers
vpath关键字
使用更为灵活,可以为不同的文件指定不同的搜索目录
例,vpath %.h ../headers 表示在..headers目录下搜索所有以.h结尾的文件,如果某文件在当前目录下没有找到的话
例,vpath %.h headers:src
vpath % usr 表示.h结尾的文件,先在headers目录,然后在src目录,最后到usr目录里寻找
8、预定义变量
$@:表示一个规则中的目标文件名
$^:规则的所有依赖文件列表
$*:是目标文件去掉后缀后的名称
自动变量只能用在规则的命令中,不能出现在规则的目标文件列表或依赖文件列表中。如果想让它们出现在目标文件列表中,要在它们前面加上一个$。如,$$*可以出现在目标文件列表或依赖文件列表,它代表目标文件名,等同于$*。
例,test.o: $$*.c common.h
gcc -c $*.c -o $@
9、使用条件语句
例,变量“CC”如果是gcc则链接时使用库libgnu,否则不链接任何库。
libs_for_gcc = -lgnu
normal_liabs =
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
build: test.c
$(CC) -o build test.c $(libs)