本文共 5190 字,大约阅读时间需要 17 分钟。
另见《Makefile手册中文版》=>10.5.3 自动化变量
例:
test : a.o b.o gcc -o test $^%.o: %.c b.c gcc -c -o $@ $< clean: rm *.o test
$^ : 所有的依赖
//所有通过目录搜索得到的依赖文件的完整路径名(目录 + 一般文件名)列表。 因为通过目录搜索得到的依赖文件可能会在其他目录。 $@ : 规则的目标文件(: 左边的文件,可以是任意文件,不是只可以是.o文件) $<: 第一个依赖文件。//规则中通过目录搜索得到的依赖文件列表的第一个依赖文件 例:a.o : a.c a.S gcc -c -o $@ $< 则$<指的是a.c而不是a.S $? : 表示比目标还要新的依赖文件列表 % : 对于本处来说,到test : a.o b.o时,会发现a.o没有,然后寻找规则的目标文件,找到了%.o与其对应, 于是,%.o对应a.o,也就是%等于a,也就是:a.o : a.c,到b.o的时候也是这样进行。 注意: 1.实际上,生成.o文件时,用的命令一般就是gcc -c -o $@ $< ,用gcc -c -o $@ $^会报错,显示最后那个只能是一个文件。 示例:a.c中用到了a.h和b.c,那么需要这样写: a.o : a.c a.h b.c gcc -c -o $@ $<</div> 表面上看,$<表示的是第一个依赖文件,也就是a.c,看起来没用到a.h和b.c。其实将上边写为: a.o : a.c gcc -c -o $@ $<</div> 也是可以的。但是,当只修改了a.h或者a.c的时候,直接make,第二种方法不能识别到依赖的更新, 而第一种方法可以。本处
$^指的就是a.o , b.o。 会对所有的.o文件(本处是a.o, b.o)分别执行gcc -c -o $@ $<,执行a.o时,$@对应a.o,$<对应a.c下边这样是错误的,因为如果没有指定输出项目的时候Make会自动找到makefile中第一个目标中没有通配符的目标进行构造。
test : %.o gcc -o test $^%.o: %.c b.c gcc -c -o $@ $<clean: rm *.o test
其他makefile的函数见网页收藏:
"GNU Make 使用手册(中译版)(于凤昌)" => 8 文本转换函数 "Makefile手册中文版"$(subst form,to,text)
在文本"text"中使用"to"替换每一处的"from" 例:$(subst ee,EE,feet on the street) 结果为:"fEET on the strEET" $(patsubst pattern,replacement,text) 寻找‘text'中符合格式‘pattern'的字,用‘replacement'替换它们. 例:$(patsubst %.c,%.o,a.c.c bar.c) 结果为:‘a.c.o bar.o' 注意:foo := a.c.c bar.c var := $(foo:.c=.o) #或者var :=$(foo:%.c=%.o) 能达到一样的效果。 $(filter pattern...,text) 返回在‘text'中由空格隔开且匹配格式‘pattern...'的字 例:$(filter %.c,%.s,foo.c bar.c baz.s ugh.h) 结果为:‘foo.c bar.c baz.s' $(filter-out pattern...,text) 返回在‘text'中由空格隔开且不匹配格式‘pattern...'的字 例:$(filter-out %.c,%.s,foo.c bar.c baz.s ugh.h) 结果为:'ugh.h' $(strip string) 去掉前导和结尾空格,并将中间的多个空格压缩为单个空格。 例:$(strip a b c ) 结果为‘a b c'。 注意:函数strip和条件语句连用非常有用。当使用ifeq或ifneq把一些值和空字符串比较时,通常要将一些 仅由空格组成的字符串认为是空字符串 $(findstring find,in) 在字串in中查找find字串。如果找到,那么返回find,否则返回空字符串。 例: $(findstring a,a b c) 返回值:"a" $(sort list) 给字符串list中的单词排序(升序)。 例: $(sort foo bar lose) 返回值:"bar foo lose"。 注意:sort 函数会去掉list中相同的单词。 $(word n,text) 取字符串text中第n个单词。(从一开始) 例: $(word 2, foo bar baz) 返回值:"bar"。 注意:如果n比text中的单词数要大,那么返回空字符串 $(wordlist s,e,text) 从字符串text中取从s开始到e的单词串。s和e是一个数字 例:$(wordlist 2, 3, foo bar baz) 返回值是"bar baz" $(words text) 统计text中字符串中的单词个数。 例:$(words, foo bar baz) 返回值是"3"。 备注:如果我们要取text中最后的一个单词,我们可以这样:$(word $(words text),text) $(firstword text) 取字符串text中的第一个单词。 例:$(firstword foo bar) 返回值是"foo"。 注意:这个函数可以用 word 函数来实现:$(word 1,text)。$(dir names...)
抽取‘names'中每一个文件名的路径部分 例:$(dir src/foo.c hacks) 结果为: 'src/ ./'。 $(notdir names...) 抽取‘names'中每一个文件名中除路径部分外一切字符(真正的文件名) 例:$(notdir src/foo.c hacks) 结果为:'foo.c hacks'。 $(wildcard pattern) 通配符在规则中可以自动扩展,但变量中在函数的参数中通配符不能正常扩展。在这些场合扩展通配符,使用函数wildcard 例:当前目录有a.c b.c b.h,c_src = *.c表示c_src就是'*.c',而c_src = $(wildcard *.c),则c_src = a.c b.c $(suffix names...) 从文件名序列names中取出各个文件名的后缀,如果文件没有后缀,则返回空字串 例:$(suffix src/foo.c src-1.0/bar.c hacks) 返回值:".c .c"。 $(basename names...) 返回文件名序列names的前缀序列,如果文件没有前缀,则返回空字串。 例:$(basename src/foo.c src-1.0/bar.c hacks) 返回值:"src/foo src-1.0/bar hacks"。 $(addsuffix suffix,names...) 把后缀suffix加到names中的每个单词后面。 例:$(addsuffix .c,foo bar) 返回值:"foo.c bar.c"。 $(addprefix prefix,names...) 把前缀prefix加到names中的每个单词后面 例:$(addprefix src/,foo bar) 返回值:"src/foo src/bar"。 $(join list1,list2) 把list2中的单词对应地加到list1的单词后面。如果list1的单词个数要比list2的多,那么, list1中的多出来的单词将保持原样。如果list2的单词个数要比list1多,那么,list2多出 来的单词将被复制到list2中。 例:$(join aaa bbb , 111 222 333) 返回值:"aaa111 bbb222 333"$(foreach var,list,text)
前两个参数‘var'和‘list',首先扩展,‘text'此时不扩展;接着,对每一个‘list'扩展产生的字,将用来为'var'扩展后命名的变量赋值; 然后‘text'引用该变量扩展;因此它每次扩展都不相同。结果是由空格隔开的‘text' 在‘list'中多次扩展的字组成的新的'list'。 ‘text'多次扩展的字串联起来,字与字之间由空格隔开,如此就产生了函数foreach的返回值。 例: dirs := a b c d files := $(foreach dir,$(dirs),$(wildcard $(dir)/*)) 这里‘text'是‘$(wildcard $(dir)/*)'。 第一个为变量dir发现的值是‘a',所以产生函数foreach结果的第一个字为‘$(wildcard a/*)'; 第二个重复的值是‘b',所以产生函数foreach结果的第二个字为‘$(wildcard b/*)'; 第三个重复的值是‘c',所以产生函数foreach结果的第三个字为‘$(wildcard c/*)'; 例子和下例有共同的结果: files := $(wildcard a/* b/* c/* d/*)另外还有:$(if ...) $(value ...) $(eval ...) $(call ...) $(origin ...) $(shell ...),见"Makefile手册中文版"
test : a.o b.o gcc -o test $^%.o : %.c gcc -c -o $@ $<clean: rm *.o test
若有一个clean文件,则已经有了目标文件,执行make clean就会失败。
解决方法: (用假想目标 .PHONY) .PHONY: clean // 此语句写在clean前边或者后边都可以。通常,make会把其要执行的命令行在命令执行前输出到屏幕上。当我们用“@”字符在命令
行前,那么,这个命令将不被make显示出来,例: @echo 正在编译XXX模块...... 运行结果: 正在编译XXX模块...... echo 正在编译XXX模块..... 运行结果: echo 正在编译XXX模块...... 正在编译XXX模块...... 其他注意: 1. 如果make执行时,带入make参数“-n”或“--just-print”,那么其只是显示命令,但不会执行命令,这 功能可用来调试Makefile 2. make参数“-s”或“--slient”可以全面禁止命令的显示。:= # 即时变量。例: A := abc # A的值即刻确定,在定义时即确定
= # 延时变量。例: B = 123 # B的值使用到时才确定 ?= # 延时变量, 如果是第1次定义才起效, 如果在前面该变量已定义则忽略这句 += # 附加, 它是即时变量还是延时变量取决于前面的定义例1:A := $(C)
B = $(C) C = abc all: @echo A = $(A) @echo B = $(B) 运行结果: A = B = abc例2:A := $(C)
B = $(C) C = abc all: @echo A = $(A) @echo B = $(B) C = 123运行结果:
A = B = 123例3:A := $(C)
B = $(C) C = abc all: @echo A = $(A) @echo B = $(B) C ?= 123 运行结果: A = B = abc详见《Makefile手册中文版》 => 搜索“GNU make环境变量”
MAKEFILES MAKEFILES_LIST VPATH SHELL MAKESHELL MAKE MAKELEVEL MAKEFLAGS MAKECMDGOALS CURDIR SUFFIXES .LIBPATTERNS转载地址:http://zgvjz.baihongyu.com/