由于博主没有深入地学习Makefile的语法与规则,所以在分析Makefile的时候遇到了不少的困难。
前两天在尝试将C++程序打包成OpenWrt的ipk文件时,博主看了大量的Makefile文件[查博文]。看得博主头大。
经[GunsNRose]的指引,我再深入地学习了Makefile的语法。
推荐书籍:《跟我一起写Makefile》
详细的写法请阅读推荐书籍。这里博主只例举出常见的用法与实践过程。
<目标列表> : <所需列表> <操作命令序列>
当<目标列表>不存在,或<所需列表>中有任意一项的修改时间比<目标列表>新,那么就会执行下面的<操作命令序列>里的指令。
是否成功,决定于生成的<目标列表>是否存在且比<所需列表>更新。如果不满足就会报错,停止make过程。
这个功能很有用。我们没有必要把每一个要生成.o文件都写一个 xxx.o : xxx.c
target:=myapp objects:=main.o demo.o foo.o bar.o $(target):$(objects) $(CC) -o $(target) $(objects)
make会根据objects变量的,自动推导出需要编译xxx.o对应的xxx.c或xxx.cpp文件,并进行$(CC) -c xxx.c
类似于C语言里的#include,在make解析Makefile时,会将include后面的内容导入进来。格式如下:
include foo.make *.mk $(bar)
它会导入当前路径下 foo.make, a.mk, b.mk, c.mk 以及bar变量所指的文件名。如果找不到,会到默认的路径下去找。
如果make执行时,有“-I”或“--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。
变量赋值3种方式:(1)即时推算赋值(2)延后推算赋值
延后推算赋值:
bar = Booo foo = $(bar) bar = Hub All: @echo $(foo)
make输入的结果是 Hub,而不是Booo。
如果将第二行的等号换成":=":
bar = Booo foo := $(bar) bar = Hub All: @echo $(foo)
结果就是 Booo。
":=" 是将右边的变量推算后的结果赋值给右边。
"=" 是表示左边的变量由右边的变量推算而来,在以后对左边变量的读取时再推算。
最后一种是 ?=,表示如果该变量没有定义,那么就给它赋值。属于赋引用类型。
ccc = xxxx ccc ?= zzzz test: @echo $(ccc)
输出结果是:xxxx,可以第2行的赋值是无效的。如果把第1行去掉,则输出结果便是zzzz了。
引用一个变量,就是用 $()将变量名包起来,也可以是${}。如:
A = 12 B = $(A) C = ${A}
foo := a.o b.o c.o bar := $(foo:.o=.c)
将foo中每所有的".o"替换成".c"并赋给bar。
var_name := aa aa := AAAAA bb := BBBBB test: @echo $($var_name)
输出结果是AAAA。如果将var_name改成bb,那么输出的结果是BBBB。它其实是进行了两步推算:
-->@echo $($var_name)
-->@echo $(aa) #将 $(var_name) 推算出 aa
-->@echo AAAAA
类似PHP里面也有这样的用法。
在Shell里,往PATH里追加都是:
PATH=$PATH:/usr/local/xxx
在Makefile里也可以这么做:
AA:=11 AA:=$(AA) 22
不过有更好的方式:
AA := 11 AA += 22
+= 是属于赋值,不是赋引用。如下例子:
AA := 11 BB := 66 AA += 22 $(BB) BB = 77 test7: @echo $(AA)
输出结果是:11 22 66,而不是11 22 77
多行变量是格式为
define <变量名> <变量的值> endef
与上面的"="变量赋值是一样的意思。
foo := AAAA define MLVar "Hi, It‘s multi-line var $(foo) $(1) $(2)" endef foo := BBBB test8: @echo $(MLVar) @echo $(call MLVar,bbb) @echo $(call MLVar,aaa,bbb)
make test8的输出结果是:
Hi, It‘s multi-line var BBBB Hi, It‘s multi-line var BBBB bbb Hi, It‘s multi-line var BBBB aaa bbb
上面的例子,检验出了对MLVar的赋值是采用延后推算方式。
用 $(call MLVar) 可以像函数一样给MLVar变量里面的 $(1), $(2), $(3) ... $(N) 赋值。
我们可以将执行的命令放置在变量中,并执行。如下:
define rm_obj @echo "Remove all objects" rm -f *.o rm -f *.obj endef test10: $(rm_obj)
$@ 表示目标变量
$< 表示依赖变量
$(N) N为1,2,3...,表示$(call xxx)中的第N个参数
ifdef (变量) 定义时时内容 else 没定义时内容 endif ifndef (变量) 没定义时内容 else 定义时内容 endif
ifeq (变量1, 变量2) 相等时内容 else 不相等内容 endif ifneq (变量1, 变量2) 不相等内容 else 相等内容 endif
根C里的宏没什么区别
单词是以空格进行划份的。
下面的相关的函数:
函数格式 |
功能说明 |
$(subst <from>,<to>,<text>) |
将<text>中的所有<from>字串替换为<to>,并返回 |
$(patsubst <pattern>,<replacement>,<text>) |
用模式匹配方式替换字串,并返回 |
$(strip <text>) |
去除<text>的空格 |
$(findstring <find>,<in>) |
查找<in>中是否含有<find>字串,有则返回<find> |
$(filter <pattern...>,<text>) |
从<text>里选出符合<pattern>的单词 |
$(filter-out <pattern...>,<text>) | 与filet相反 |
$(sort <list>) |
对列表进行排序,并去除相同的词 |
$(word <n>,<text>) |
从<text>中取出第n个单词,以1开始 |
$(wordlist <s>,<e>,<text>) |
从<text>中取出从<s>到<e>的单词 |
$(words <text>) |
返回单词个数 |
$(firstword <text>) |
返回第一个单词 |
函数格式 |
功能说明 |
$(dir <names...>) |
返回文件名序列<names>;的目录部分 |
$(notdir <names...>) |
从文件名序列<names>;中取出非目录部分。 |
$(suffix <names...>) |
取后缀函数 |
$(basename <names...>) |
取前缀函数 |
$(addsuffix <suffix>,<names...>) |
加后缀函数 |
$(addprefix <prefix>,<names...>) |
把前缀<prefix>加到<names>中的每个单词后面 |
$(join <list1>,<list2>) |
把<list2>;中的单词对应地加到<list1>;的单词后面。 |
原文:http://my.oschina.net/hevakelcj/blog/414295