Makefile小结
Makefile最基本的规则:target....:prerequisites.....
command
或:target....:prerequisites.....;command
target:目标文件,prerequisites:依赖文件,command:要执行的操作。命令太长可以使用“\”来换行不断行,其中的命令使用UNIX的标准shell,/bin/sh来执行。
基本等同于直接在terminal中输入命令的效果。
伪目标一般指不需要依赖文件的一类目标,可以使用“.PHONY”来显式的指出。
Makefile中的注释以“#”开头,命令以“[Tab]键开头”。注意加注释时,不要直接加在变量定义后边,因为这是Makefile会将空格也计算在变量内。
Makefile默认会将第一个目标设置为最终的目标。
在命令行输入make命令时,默认会在当前目录按“GNUmakefile”,“makefile”,“Makefile”的文件来顺序搜索。如果需要指定特定的Makefile,可以使用make的参数
“-f”,"--file"。在Makefile中可以使用“include”关键字将别的Makefile包含进来。在include前加“-”号,可以让make继续执行,而不论文件是否能读取。
所有的make命令之前加-号,都是忽略函数返回值的。 -rm -rf ./
makefile中的include,有三种形式,
1) include, 2) -include,3) sinclude,sinclude与-include类似,但是兼容性好一些。
Makefile中调用include的方式:
1) 首先在当前或者指定的目录下寻找被调用文件;
2) 如果没有找到,从-I所指定的include目录中寻找,
3) 仍然没有找到,makefile试图寻找匹配规则来生成对应的文件,
常见的应用模式,生成dependence文件 .d文件:
sinclude $(SOURCE:.c = .d) #include .d文件:
%.d:%.c
@set -e;\
$(CC) -MM $(INC_FLAG) $(DEF_FLAG) $< > $@.$$$$;
环境变量MAKEFILES,make会把这个变量的值做成一个类似include的动作,其中有一个区别是,从这个环境变量引入的Makefile的目标不会被识别。这个变量中的值,
用空格分隔。
make中的命令执行时,如果需要之后的一条命令,在前一条的基础上执行,则这两条命令必须写在同一行上,并且用分号隔开。
exec:
cd /home/hchen; pwd;
在描述Makefile中的规则时,make支持三种通配符“*”,“?”,“[...]”
objects = *.o
当变量中定义了通配符时,makefile并不会展开,变量的值就是*.o
objects := $(wildcard *.o)
需要展开时,需要加入wildcard关键字,这时,变量中的值就是所有.o文件的集合
在寻找目标文件和依赖文件的时候,在当前文件中找不到的情况下,make命令会自动搜索“VPATH”所指定的路径。“VPATH”变量中的值用“冒号”分隔。
VPATH = src:../headers
makefile会按顺序,一次搜索./src文件夹和../headers文件夹;
Makefile还有一种关键字“vpath”,用来指定符合模式的文件的所搜路径。 Eg vpath %.c ../foo makefile会在../foo中搜索所有的.c文件
静态模式:<targets...>:<target-pattern>:<prereq-patterns....>
<command>
适用于使用“%”来定义一个目标集模式。prereq-patterns一般也是用“%”来表示某种依赖文件。
可以有两个target,相同的依赖关系以及操作;
bigoutput littleoutput : text.g
generate text.g -$(subst output, , $@) > $@
$@中有几个目标,便等同于几个target
-MM自动生成依赖关系,gcc -MM main.c文件
Makefile中的变量,是大小写敏感的,传统的Makefile的变量名全是大写的命名方式。变量在声明时需要给予初值,在使用时,需要在前边加上“$”符号。可以用“()”
和“{}”来括起变量。如果要表示真实的“$”字符,需要使用“$$”表示。
几种定义方式:A=1234
A:=1234 前边的变量不能使用后边才定义的变量,这样防止上一种定义方式可能发生的变量嵌套时的死锁。
A?=1234 如果A前边没有定义过,这条语句才会有效。
A+=1234 为变量A追加值,以空格隔开,如果变量之前有定义,“+=”会自动继承前次操作的赋值符。“=” “:=” "+="
如果有变量是通过命令行参数来定义的,同时Makefile内部也对它进行了定义,则默认忽略Makefile中的定义。除非加“override”关键字在变量定义时。
对变量列表中的变量可以直接进行替换: $(sources:.c = .d)将之前source中的.c文件都替换为.d文件。
Makefile中还有针对目标的变量和针对模式的变量。
从terminal中将变量传入makefile, 直接make var=2接口,makefile内部直接将var作为一个为赋值的变量就可以。该var的值也可以作为target,来从外部控制makefile流程。
Makefile中的条件判断:make是在读取Makefile时就计算表达式的值,并根据条件表达式的值来选择语句,所以不应该吧自动化变量如($@)放在条件表达式中。
1)ifeq, else, endif
2)ifneq
3)ifdef
4)ifndef
for循环:必须使用$$(),来调用循环变量。
rule1:
for i in $(SOURCE); do echo $$(i); done
Makefile默认会将要执行的命令,在执行前输出到屏幕,当我们用“@”字符在命令前时,这个命令就不会被显示出来了。用“-”在命令前,则该命令即使出现问题,make
也不会退出。
在Makefile中执行命令时,如果要让上一条命令的结果应用于下一条命令时,应该使用“分号”来分隔这两条命令。
Eg: cd /home/hchen cd /home/hchen;
pwd pwd
在Makefile间传递变量,直接在当前环境生成环境变量,在定义变量时,使用“export”关键字。只加一个export后没有变量,则传递所有变量。如果有从命令过来的变量,Makefile会自动在嵌套式的
Makefie中传递。也可以使用unexport来拒绝传递变量;
Makefile中的字符串处理函数:函数调用与变量的使用很像,也是使用“$”来标识。
1)$(subst <from>,<to>,<text>):字符串替换函数。
2)$(patsubst <%from>,<%to>,<text>):模式字符串替换函数。
3)$(strip <string>):去掉字符串的前后空格。
4)$(findstring <fing>,<in>):查找字符串并返回。
5)$(filter <pattern.....>, <text>):过滤函数,返回符合模式的单词。
6)$(filter-out <pattern.....>, <text>):反过滤函数,返回不符合模式的单词。
7)$(sort <list>):给字符串<list>中的单词排序,去除相同的单词。
8)$(word <n>, <text>):取单词函数。
9)$(wordlist <s>, <n>, <text>):取多个单词函数。
10)$(words <text>):统计单词个数函数。
11)$(firstword <text>):取首个单词函数。
Makefile中的文件名操作函数:
1)$(dir <name....>) 取目录函数,可以是多个数据的列表,返回多个。
2)$(notdir <name....>) 取文件函数,与上一函数相反。
3)$(suffix <name.....>) 取后缀函数,如文件后缀。
4)$(basename <name....>) 取前缀函数,除了文件后缀的其他部分。
5)$(addsuffix <suffix>, <name....>) 加后缀函数,加文件后缀。
6)$(addprefix <prefix>, <name....>) 加前缀函数,加除了文件后缀之外的部分。
7)$(join <list1>, <list2>) 连接函数,将<list2>的单词对应的加到<list1>的后边。
Makefile中的其他函数:
1)$(if <condition>, <then-part>, <else_part>)
2)$(origin <variable>) 返回变量的来历
返回值是固定的几个,undefined,default,file,command line,override,automatic,environment,
一般用在变量是否被重新定义,override太过暴力,可以在来自env的进行重定义;
ifeq “$(origin bletch)" "environment"
bletch = barf,
3)$(shell xxx) 引用UNIX的shell命令,与“反引号”作用相同。
contents := $(shell cat foo)
4)$(error <text...>) 表示出现错误,打出text,退出。
5)$(warning <text...>) 表示出现warning,打出text。
6) $(call <expression>, <param1>, <param2> ....)自定义一个参数化的函数
reverse = $(1) $(2) ##首先自定义一个复杂的表达式
foo = $(call reverse , a, b) ##直接调用
##返回a b。
Makefile中的参数“-w”或是“--print-directory”,在切换目录时,输出信息。
“-n”或是“--just-print",只打印出命令及其规则,但是不执行,适合调试。
“-C”或是“--directory”,指定读取makefile的目录。
"-s" make时的参数,全面禁止命令的显示。
“-i” 执行过程中,忽略所有的error;
“-k” 执行过程中,一个target执行错误之后,执行其他的target;
1)嵌套式的makefile,一般讲make和makefiag定义为变量,这样方便一些 make 参数的传递,
2)makefile中定义命令包,命名空间与变量相同,调用也相同;以define开头, endef结束;
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
自动化变量$@,表示规则中的目标文件集合,用于匹配目标模式中定义的集合;
$<,依赖目标中的第一个目标的名字,如果依赖目标是以%来定义的,那么$< 表示符合模式的一系列的文件集合,是一一取出来的。
$*,目标模式 %,及其之前的部分;
%.d : %.c
gcc $(INC_FLAG) -o $*.o //其中的$*表示.d文件名
$(shell pwd | sed 's///');来进行目录的操作。