makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
foo.o : foo.c defs.h
cc -c -g foo.c
foo.o是我们的目标,foo.c和defs.h是目标所依赖的源文件,而只有一个命令“cc -c -g foo.c”(以Tab键开头)。这个规则告诉我们两件事:
1、文件的依赖关系,foo.o依赖于foo.c和defs.h的文件,如果foo.c和defs.h的文件日期要比foo.o文件日期要新,或是foo.o不存在,那么依赖关系发生。
2、如果生成(或更新)foo.o文件。也就是那个cc命令,其说明了,如何生成foo.o这个文件。(当然foo.c文件include了defs.h文件)。
变量引用方式:$(VARIABLE_NAME)或者$(VARIABLE_NAME),引用的是VARIABLE_NAME的值而不是符号。
这类变量可以通过"="或"define"定义。递归变量被用的时候再去扩展。
student = lilei
CLASS = $(student)$(teacher)
teacher = young
all:
@echo $(CLASS)
输出:lilei young
递归方式拓展的变量在定义时可以引用之前没有定义的变量(可能后续定义或makefile命令行传递的变量)。但是,要注意因为出现变量的递归而出现无限的变量展开的过程。如下:
X = $(Y)
Y = $(Z)
Z = $(X)
这样的话,会陷入无限变量展开,因为最终引用的自己。
直接展开式变量通过“:=“定义。变量值中其他变量或函数引用在定义变量时展开。
X := student
Y := $(X)
X := teacher
all:
@echo $(X) $(Y)
输出结果为:teacher student
直接展开式变量在定义时就完成了对所引用变量和函数的展开,因此不能实现对其后续定义的引用。
“?="来进行条件赋值,只有此变量在之前没有赋值的情况下才会对变量进行赋值。
X := student
X ?= teacher
Y ?= student
all:
@echo $(X) $(Y)
输出 student student
格式 $(VAR:A=B)或者${VAR:A=B),将已经定义的变量VAR值的后缀字符(串)A结尾的字使用指定的字符(串)B替换。结尾的含义是空格前(变量值多个字之间使用空格分开)。
X := fun.o main.o
Y := $(X .o=.c)
all:
@echo $(X) $(Y)
输出 fun.o main.o fun.c main.c
注意的是$(X .o=.c)中等号两边不能有空格。
一个通用变量在定义之后的其他地方,可以对其值进行追加。Makefile使用”+=“来进行一个变量的追加操作。
X = fun.o main.o
X += sub.o
all:
@echo $(X)
输出:fun.o main.o sub.o
注意的是一个变量在追加前未被定义,则”+=“会自动变成”=“,即变量变成递归展开式变量。
$(addprefix prefix,name…)
函数名称:加前缀函数。
$(addprefix src/,foo bar main)
返回值:src/foo src/bar src/main
$(addsuffix,name…)
函数名称:加后缀函数。
$(addsuffix .c,foo bar main)
返回值:foo.c bar.c main.c
参考资料: 嵌入式linux学习手册 —朱兆祺