本文是一些自己学习makefile时的笔记。以下内容主要摘取自陈皓编写的跟我一起写Makefile,这是一个很好的学习资料。
makefile介绍
makefile的核心规则
1
2
target : prerequisites
command
target是目标文件,prerequisites是生成target的依赖文件。当target不存在,或prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行,command命令一定要由一个Tab键开头。
在makefile末尾一般会看到,用来删除编译产生的中间文件等:
1
2
clean :
rm ...
这里clean 不是一个文件,它只不过是一个动作名字(伪目标),其冒号后什么也没有,那么,make就不会自动去找它的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make命令后明显得指出这个label的名字,如make clean。
make是如何工作的
make会在当前目录下找名字叫“Makefile”或“makefile”的文件,并根据该文件一层一层地去找文件的依赖关系,直到最终编译出第一个目标文件。详细可参见这里和这里。
书写规则
$@ 表示目标的集合,就像一个数组, $@ 依次取出目标,并执于命令,可用于多目标。参考这里。
静态模式可以更加容易地定义多目标的规则。其语法为
1
2
<targets ...> : <target-pattern> : <prereq-patterns ...>
<commands>
举例:
1
2
3
4
5
6
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
<command>
其中%.o即为target-pattern,%.c为prereq-patterns。%.o: %.c的含义为:将objects中所有以.o的目标,后缀换为.c组成新的集合。
使用变量
变量基础
变量定义
1
VAL = ...
变量使用
1 2 3
$(VAL) 或 ${VAL}
变量会在使用时精确展开。
定义变量值时的
=与:==允许使用当前尚未定义好的变量作为右值,但可能出现递归定义的问题;:=强制要求只能使用前面已定义好了的变量作为右值。
变量高级用法
变量替换
1 2 3 4 5 6 7
# 定义变量 foo := a.o b.o # 变量替换 bar := $(foo:.o=.c) # bar = a.c b.c # 或 bar := $(foo:%.o=%.c) # bar = a.c b.c
变量追加
1 2
foo := a.o b.o foo += c.o # foo = a.o b.o c.o
自动化变量
$@:当前规则中,目标(或目标集)。$^:当前规则中,所有依赖组成的的集合。$<:当前规则中,第一个依赖。
举个栗子,对
exc: library.cpp main.cpp那么,
$@就指代exc,$^指代library.cpp main.cpp,$<指代library.cpp。如果
@$指代的目标有多个(即是一个目标集)时,则将目标依次取出展开,执行command,参考这种方式貌似对于多个相互独立的文件分别编译非常方便,尤其当文件非常多时。
举个栗子,对
1 2 3 4 5 6
objects = foo.o bar.o all: $(objects) $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@
展开后对应执行
1 2 3 4
foo.o : foo.c $(CC) -c $(CFLAGS) foo.c -o foo.o bar.o : bar.c $(CC) -c $(CFLAGS) bar.c -o bar.o
使用条件判断
关键字
ifeq,ifneq,判断是否相等。示例:1 2 3 4 5
ifeq ($(CC),gcc) $(CC) -o foo $(objects) $(libs_for_gcc) else $(CC) -o foo $(objects) $(normal_libs) endif
关键字
ifdef,ifndef,判断变量是否有值。示例:1 2 3 4 5 6 7 8
foo = ifdef foo frobozz = yes else frobozz = no endif # 该例中frobozz为no
使用函数
函数的调用语法为:
1
2
3
$(<function> <arguments>)
# 或是
${<function> <arguments>}