文章目录
1 Makefile的基本规则
在讲述这个 makefile 之前,还是让我们先来粗略地看一看 makefile 的规则。
target ... : prerequisites ...
command
...
...
- target
可以是一个 object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。对于
标签这种特性,在后续的“伪目标”章节中会有叙述。
- prerequisites
生成该 target 所依赖的文件和/或 target
- command
该 target 要执行的命令(任意的 shell 命令)
这是一个文件的依赖关系,也就是说,target 这一个或多个的目标文件依赖于 prerequisites 中的文
件,其生成规则定义在 command 中。说白一点就是说: 3
, 发布 1.0
prerequisites 中如果有一个以上的文件比 target 文件要新的话,command 所定义的命令就会被执行。
例子
- 创建文件
touch Makefile main.o main.cpp
MakeFileTest : main.o
@echo "make MakeFileTest"
main.o : main.cpp
@echo "make main.o-------"
- 执行make结果
ubuntu@ubuntu:~/work/shell/MakeFile2$ make
make main.o-------
make MakeFileTest
- 修改main.o
根据上面说法,如果main.o的文件时间比main.cpp新的话,证明是main.0没有变化,不需要编译main.o的,也就不会执行make main.0
ubuntu@ubuntu:~/work/shell/MakeFile2$ make
make MakeFileTest
MakeFile的执行顺序时,遍历执行Makefile文件里面所有的mk命令,然后执行第一个target目标
2. make执行步骤
在默认的方式下,也就是我们只输入 make 命令。那么,
- make 会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文
件,并把这个文件作为最终的目标文件。 - 如果 edit 文件不存在,或是 edit 所依赖的后面的 .o 文件的文件修改时间要比 edit 这个文件新,
那么,他就会执行后面所定义的命令来生成 edit 这个文件。 - 如果 edit 所依赖的 .o 文件也不存在,那么 make 会在当前文件中找目标为 .o 文件的依赖性,如
果找到则再根据那一个规则生成 .o 文件。(这有点像一个堆栈的过程) - 当然,你的 C 文件和 H 文件是存在的啦,于是 make 会生成 .o 文件,然后再用 .o 文件生成 make
的终极任务,也就是执行文件 edit 了。
这就是整个 make 的依赖性,make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目
标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么 make 就会直接退出,并
报错,而对于所定义的命令的错误,或是编译不成功,make 根本不理。make 只管文件的依赖性,即,如
果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
3. 变量赋值
结果看都是忽略掉=右边的空格,后面的空格不会过滤
添加“”和变量赋值,不会忽略掉空格
OBJECT := wangdong test ffille ssddf #最后都有一个空格
OBJECT1 := " wangdong test ffille ssddf "
OBJECT2 = $(OBJECT1)
MakeFileTest : main.o
@echo "make MakeFileTest"
@echo "OBJECT : --$(OBJECT)--"
@echo "OBJECT1 : --$(OBJECT1)--"
@echo "OBJECT2 : --$(OBJECT2)--"
结果:
make MakeFileTest
OBJECT : --wangdong test ffille ssddf --
OBJECT1 : -- wangdong test ffille ssddf --
OBJECT2 : -- wangdong test ffille ssddf --
4. make clean和伪目标文件
.PHONY : clean
clean :
-rm xxx.txt //-会跳过错误,不影响后面执行
@echo "clean rm-------"
cp xx.txt xxxxx.txt //没有xx.txt会退出,不会执行后面
@echo "clean cp-------"
@make clean结果:
rm xxx.txt
rm: 无法删除'xxx.txt': 没有那个文件或目录
makefile:20: recipe for target 'clean' failed
make: [clean] Error 1 (ignored)
clean rm-------
cp xx.txt xxxxx.txt
cp: 无法获取'xx.txt' 的文件状态(stat): 没有那个文件或目录
makefile:20: recipe for target 'clean' failed
make: *** [clean] Error 1
前面说过,.PHONY 表示 clean 是一个“伪目标”。而在 rm 命令前面加了一个小减号的意思就是,也
许某些文件出现问题,但不要管,继续做后面的事。当然,clean 的规则不要放在文件的开头,不然,这
就会变成 make 的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean 从来都是放在文件的最
后”。
5. Makefile 里有什么?
Makefile 里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
- 显式规则。显式规则说明了如何生成一个或多个目标文件。这是由 Makefile 的书写者明显指出要
生成的文件、文件的依赖文件和生成的命令。 - 隐晦规则。由于我们的 make 有自动推导的功能,所以隐晦的规则可以让我们比较简略地书写 Makefile,这是由 make 所支持的。
- 变量的定义。在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像你 C 语
言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。 - 文件指示。其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像 C 语言中的
include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if
一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
8 Chapter 2. makefile 介绍
, 发布 1.0 - 注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用 # 字符,这个就像 C/C++
中的 // 一样。如果你要在你的 Makefile 中使用 # 字符,可以用反斜杠进行转义,如:# 。
最后,还值得一提的是,在 Makefile 中的命令,必须要以 Tab 键开始。
6. 引用其他Makefile文件
使用include来引用其他mk文件,其表示,无论 include 过程中出现什么错误,都不要报错继续执行
include vendor/chinatsp/scripts/Chinatsp.mk
# -表示chinatsp.mk报错不会影响执行
-include vendor/chinatsp/scripts/Chinatsp.mk
//这里找不到Chinatspxx.mk就不会退出,如果没有-,那么就会退出MakeFile
-include Chinatspxx.mk
MakeFileTest : main.o
@echo "make MakeFileTest"
7. 伪目标
“伪目标”并不是一个文件,只是一个标签,由于“伪目标”
不是文件,所以 make 无法生成它的依赖关系和决定它是否要执行。我们只有通过显式地指明这个“目
标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。
当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显式地指明
一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪目标”。
make执行all,all是一个伪目标不会生成,就会去遍历prog1,2,3
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
8. 多目标$@
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@
上述规则等价于:
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput
9. 显示命令@
通常,make 会把其要执行的命令行在命令执行前输出到屏幕上。当我们用 @ 字符在命令行前,那么,
这个命令将不被 make 显示出来,最具代表性的例子是,我们用这个功能来向屏幕显示一些信息
不加@会首先打印命令 echo “make MakeFileTest”,然后在执行命令
机上@,不会打印命令内容,直接执行shell命令
@Makefile
OBJECT := wangdong test ffille ssddf
OBJECT1 := " wangdong test ffille ssddf "
MakeFileTest : main.o
echo "make MakeFileTest"
echo "OBJECT : --$(OBJECT)--"
@echo "OBJECT1 : --$(OBJECT1)--"
结果:
echo "make MakeFileTest"
make MakeFileTest
echo "OBJECT : --wangdong test ffille ssddf --"
OBJECT : --wangdong test ffille ssddf --
OBJECT1 : -- wangdong test ffille ssddf --
10. 命令执行
两次pwd内容不一样,可见每一个shell命令都是在独立的进程
MakeFileTest : main.o
echo "make MakeFileTest"
cd ~
pwd
cd ~;pwd
cd ~
pwd
/home/wangdong/work/shell/MakeFile2
cd ~;pwd
/home/wangdong
11. 命令出错 -
命令出错
每当命令运行完后,make 会检测每个命令的返回码,如果命令返回成功,那么 make 会执行下一条
命令,当规则中所有的命令成功返回后,这个规则就算是成功完成了。如果一个规则中的某个命令出错
了(命令退出码非零),那么 make 就会终止执行当前规则,这将有可能终止所有规则的执行。
有些时候,命令的出错并不表示就是错误的。例如 mkdir 命令,我们一定需要建立一个目录,如果
目录不存在,那么 mkdir 就成功执行,万事大吉,如果目录存在,那么就出错了。我们之所以使用 mkdir
的意思就是一定要有这样的一个目录,于是我们就不希望 mkdir 出错而终止规则的运行。
为了做到这一点,忽略命令的出错,我们可以在 Makefile 的命令行前加一个减号 - (在 Tab 键之
后),标记为不管命令出不出错都认为是成功的。如:
clean:
-rm -f *.o
还有一个全局的办法是,给 make 加上 -i 或是 --ignore-errors 参数,那么,Makefile 中所有命
令都会忽略错误。而如果一个规则是以 .IGNORE 作为目标的,那么这个规则中的所有命令将会忽略错误。
这些是不同级别的防止命令出错的方法,你可以根据你的不同喜欢设置。
还有一个要提一下的 make 的参数的是 -k 或是 --keep-going ,这个参数的意思是,如果某规则中
的命令出错了,那么就终止该规则的执行,但继续执行其它规则。
12. 自动化变量 $@ @< $$@
在上述的模式规则中,目标和依赖文件都是一系例的文件,那么我们如何书写一个命令来完成从不
同的依赖文件生成相应的目标?因为在每一次的对模式规则的解析时,都会是不同的目标和依赖文件。
自动化变量就是完成这个功能的。在前面,我们已经对自动化变量有所提涉,相信你看到这里已对
它有一个感性认识了。所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取
出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。
下面是所有的自动化变量及其说明:
•
@
:
表
示
规
则
中
的
目
标
文
件
集
。
在
模
式
规
则
中
,
如
果
有
多
个
目
标
,
那
么
,
@ : 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,
@:表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,@ 就是匹配于目标中模
式定义的集合。
•
,
那
么
,
% : 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是 foo.a(bar.o) ,那么,
,那么,% 就是 bar.o ,$@ 就是 foo.a 。如果目标不是函数库文件(Unix 下是 .a ,Windows
下是 .lib ),那么,其值为空。
• $< : 依赖目标中的第一个目标名字。如果依赖目标是以模式(即 % )定义的,那么 $< 将是符合模
式的一系列的文件集。注意,其是一个一个取出来的。
• $? : 所有比目标新的依赖目标的集合。以空格分隔。
• $^ : 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除
重复的依赖目标,只保留一份。
• $+ : 这个变量很像 $^ ,也是所有依赖目标的集合。只是它不去除重复的依赖目标。
•
∗
:
这
个
变
量
表
示
目
标
模
式
中
a
.
* : 这个变量表示目标模式中 % 及其之前的部分。如果目标是 dir/a.foo.b ,并且目标的模式是 a.%.b ,那么,
∗:这个变量表示目标模式中a.* 的值就是 dir/a.foo 。这个变量对于构造有关联的文件名是比较有较。如果目
标中没有模式的定义,那么 $* 也就不能被推导出,但是,如果目标文件的后缀是 make 所识别的,
那么
∗
就
是
除
了
后
缀
的
那
一
部
分
。
例
如
:
如
果
目
标
是
f
o
o
.
c
,
因
为
.
c
是
m
a
k
e
所
能
识
别
的
后
缀
名
,
所
以
,
* 就是除了后缀的那一部分。例如:如果目标是 foo.c ,因为 .c 是 make 所能识别的后缀 名,所以,
∗就是除了后缀的那一部分。例如:如果目标是foo.c,因为.c是make所能识别的后缀名,所以,* 的值就是 foo 。这个特性是 GNU make 的,很有可能不兼容于其它版本的 make,所
以,你应该尽量避免使用 $* ,除非是在隐含规则或是静态模式中。如果目标中的后缀是 make 所
不能识别的,那么 $* 就是空值。
• ’ $ '符号的使用
美元符号$,主要扩展打开makefile中定义的变量
• ’ ′ 符 号 的 使 用 '符号的使用 ′符号的使用 符号主要扩展打开makefile中定义的shell变量
示例:
@build/core/definitions.mk
define copy-file-to-target
@mkdir -p $(dir $@)
$(hide) rm -f $@
echo "cp $< $@"
echo " 1: $@ --2: $< --3: $$@ "
endef
# Define a rule to copy a file. For use via $(eval).
# $(1): source file
# $(2): destination file
define copy-one-file
$(warning 2: $(2) 1: $(1))
$(2): $(1)
echo " 1: $@ --2: $< --3: $$@ "
echo "Copy: $$@"
@echo "---------------------------------------------"
$$(copy-file-to-target)
endef
#$(eval $(call copy-one-file, app.apk, sys.apk) )
$(eval $(call copy-one-file, app.apk one.apk , two.apk sys.apk) )
结果:
$(2): $(1) 是使用eval call之后传入的参数,这里是一个拷贝,代表src文件和dst文件
直接使用$@ $<是空的, $$@是dst参数的第一个文件
$$(copy-file-to-target)是展开copy-file-to-target里面的shell命令
得到的$@ 是目标target(dst)第一个值
<
依
赖
的
t
a
r
g
e
t
(
< 依赖的target(
<依赖的target((1))的第一个值
$$@得到的是是dst参数的第一个文件
在android 10 java.mk编译static jar时候,有调用copy-one-file来完成编译jar
makefile:28: 2: two.apk sys.apk 1: app.apk one.apk
echo " 1: --2: --3: two.apk "
1: --2: --3: two.apk
echo "Copy: two.apk"
Copy: two.apk
---------------------------------------------
rm -f two.apk
echo "cp app.apk two.apk"
cp app.apk two.apk
echo " 1: two.apk --2: app.apk --3: $@ "
1: two.apk --2: app.apk --3:
define copy-file-to-target
@mkdir -p $(dir $@)
$(hide) rm -f $@
$(hide) cp "$<" "$@"
endef
define copy-one-file
$(2): $(1)
@echo "Copy: $$@"
$$(copy-file-to-target)
endef
$(eval $(call copy-one-file, /home/wangdong/work/shell/MakeFile2/main.cpp, /home/wangdong/work/shell/MakeFile2/my.cpp))
$(eval $(call copy-one-file, /home/wangdong/work/shell/MakeFile2/Chinatsp.mk, /home/wangdong/work/shell/MakeFile2/Chinatsp.mk.cpp))
Chinatsp :
@echo "==========="
$(eval $(call copy-one-file, /home/wangdong/work/shell/MakeFile2/Chinatsp.mk, /home/wangdong/work/shell/MakeFile2/Chinatsp3.mk.cpp))
结果log,编译后,第二,三个copy one file根本不执行,chinatsp也不会执行,因为makefile默认会执行第一个遇到的target,其他的就执行不到了,因此编译里面自己直接添加这个,可能执行不到哦
$ make
Copy: /home/wangdong/work/shell/MakeFile2/my.cpp
rm -f /home/wangdong/work/shell/MakeFile2/my.cpp
cp "/home/wangdong/work/shell/MakeFile2/main.cpp" "/home/wangdong/work/shell/MakeFile2/my.cpp"
13. 字符串函数
13.1 subst 字符串替换函数
$(subst ,,
• 名称:字符串替换函数
• 功能:把字串
• 返回:函数返回被替换过后的字符串。
• 示例:
$(subst ee,EE,feet on the street)
把 feet on the street 中的 ee 替换成 EE ,返回结果是 fEEt on the strEEt 。
返回字符串去掉了.xml,意思是把.xml替换为null
$(warning $(subst .xml,,vendor/qcom/adb.xml test.xml))
makefile:41: vendor/qcom/adb test
13.2 patsubst 模式字符串替换函数
$(patsubst ,,
• 名称:模式字符串替换函数。
• 功能:查找
,如果匹配的话,则以 替换。这里, 可以包括通配符 % ,
表示任意长度的字串。如果 中也包含 % ,那么, 中的这个 % 将是
中的那个 % 所代表的字串。(可以用 \ 来转义,以 % 来表示真实含义的 % 字符)
• 返回:函数返回被替换过后的字符串。
可以看到subst和patsubst区别,subst只要是.c都会替换为.o,patsubst而是符合%.c替换为%.o, 这里%相当于x.c
$(warning subst: $(subst .xml,,vendor/qcom/adb.xml test.xml))
$(warning patsubst: $(patsubst %.c,%.o,x.c.c bar.c))
$(warning patsubst: $(subst .c,.o,x.c.c bar.c))
makefile:41: subst: vendor/qcom/adb test
makefile:42: patsubst: x.c.o bar.o
makefile:43: patsubst: x.o.o bar.o
13.3 strip 去空格
$(strip )
• 名称:去空格函数。
• 功能:去掉 字串中开头和结尾的空字符。
• 返回:返回被去掉空格的字符串值。
把string中的字符串按空格隔开,全部去除空格,中间多个空格只有一个空格
$(warning strip: --$(strip bar.c - xxx )--)
makefile:45: strip: --bar.c - xxx--
13.4 findstring 查找字符串函数
$(findstring ,)
• 名称:查找字符串函数
• 功能:在字串 中查找 字串。
• 返回:如果找到,那么返回 ,否则返回空字符串。
• 示例:
$(findstring a,a b c)
$(findstring a,b c)
第一个函数返回 a 字符串,第二个返回空字符串
证明字符串查找函数没有问题,以前加空格,只是因为后面多加了空格
STRING_I := aabb bb cdrd
FIND := cdrd
$(warning findstring: --$(findstring abb,aabb bb cc)-- )
$(warning findstring: --$(findstring cc,aabb bb cc)-- )
//证明字符串查找函数没有问题
$(warning findstring: --$(findstring ab,aabb bb cdrd)-- )
$(warning findstring: --$(findstring $(FIND),$(STRING_I))-- )
#FIND后面多了个空格,相当于查找的是card ,而不是card,因此找不到为null
$(warning findstring: --$(findstring $(FIND) ,$(STRING_I))-- )
makefile:49: findstring: --abb--
makefile:50: findstring: --cc--
makefile:51: findstring: --ab--
makefile:52: findstring: --cdrd--
makefile:53: findstring: ----
13.5 filter过滤函数
$(filter <pattern…>,
• 名称:过滤函数
• 功能:以 模式过滤
• 返回:返回符合模式 的字串。
返回符合要求*.cpp的字符串
$(warning filter: --$(filter %.cpp,babcdedfb.cpp adbc.cpp xxx)-- )
makefile:52: filter: --babcdedfb.cpp adbc.cpp--
13.6 filter-out 反过滤函数
$(filter-out <pattern…>,
• 名称:反过滤函数
• 功能:以 模式过滤
• 返回:返回不符合模式 的字串。
返回和filter相反的字符串
$(warning filter-out: --$(filter-out %.cpp,babcdedfb.cpp adbc.cpp xxx)-- )
makefile:52: filter-out: --xxx--
13.7 sort 排序,去重函数
$(sort )
• 名称:排序函数
• 功能:给字符串 中的单词排序(升序)。
• 返回:返回排序后的字符串。
• 示例:$(sort foo bar lose) 返回 bar foo lose 。 • 备注:sort 函数会去掉 中相同的单词。
13.8 words单词个数统计函数
$(words
• 名称:单词个数统计函数
• 功能:统计
• 返回:返回
• 示例:
(
w
o
r
d
s
,
f
o
o
b
a
r
b
a
z
)
返
回
值
是
3
。
•
备
注
:
如
果
我
们
要
取
<
t
e
x
t
>
中
最
后
的
一
个
单
词
,
我
们
可
以
这
样
:
(words, foo bar baz) 返回值是 3 。 • 备注:如果我们要取 <text> 中最后的一个单词,我们可以这样:
(words,foobarbaz)返回值是3。•备注:如果我们要取<text>中最后的一个单词,我们可以这样:(word $(words
$(warning words: --$(words abc a b cd)-- )
makefile:52: words: --4--
13.9 wordlist取单词串函数
$(wordlist ,,
• 名称:取单词串函数
• 功能:从字符串
• 返回:返回字符串
• 示例:$(wordlist 2, 3, foo bar baz) 返回值是 bar baz 。
2,4必须是数字,列出第2到第4的字符串
$(warning wordlist: --$(wordlist 2,4,abc a b cd)-- )
makefile:52: wordlist: --a b cd--
13.10 word取单词函数
**$(word ,
• 名称:取单词函数
• 功能:取字符串
• 返回:返回字符串
• 示例:$(word 2, foo bar baz) 返回值是 bar 。
13.11 firstword取第一个单词
$(firstword
• 名称:首单词函数——firstword。 • 功能:取字符串
• 返回:返回字符串
• 示例:
(
f
i
r
s
t
w
o
r
d
f
o
o
b
a
r
)
返
回
值
是
f
o
o
。
•
备
注
:
这
个
函
数
可
以
用
w
o
r
d
函
数
来
实
现
:
(firstword foo bar) 返回值是 foo。 • 备注:这个函数可以用 word 函数来实现:
(firstwordfoobar)返回值是foo。•备注:这个函数可以用word函数来实现:(word 1,
$(warning firstword: --$(firstword abc a b cd)-- )
makefile:52: firstword: --abc--
14. 文件名操作函数
14.1 dir取目录函数
$(dir <names…>)
• 名称:取目录函数——dir。
• 功能:从文件名序列 中取出目录部分。目录部分是指最后一个反斜杠(/ )之前的部分。如果没有反斜杠,那么返回 ./ 。
• 返回:返回文件名序列 的目录部分。
• 示例:$(dir src/foo.c hacks) 返回值是 src/ ./ 。
$(warning dir: --$(dir vendor/Android.mk a b cd)-- )
makefile:52: dir: --vendor/ ./ ./ ./--
14.2 文件名操作函数
$(notdir <names…>)
• 名称:取文件函数——notdir。
• 功能:从文件名序列 中取出非目录部分。非目录部分是指最後一个反斜杠(/ )之后的部分。
• 返回:返回文件名序列 的非目录部分。
• 示例: $(notdir src/foo.c hacks) 返回值是 foo.c hacks 。
//和dir相反,取/右边的字符串
makefile:52: notdir: --Android.mk a b cd--
$(warning notdir: --$(notdir vendor/Android.mk a b cd)-- )
14.3 suffix取后缀函数
$(suffix <names…>)
• 名称:取後缀函数——suffix。
• 功能:从文件名序列 中取出各个文件名的后缀。
• 返回:返回文件名序列 的后缀序列,如果文件没有后缀,则返回空字串。
• 示例:$(suffix src/foo.c src-1.0/bar.c hacks) 返回值是 .c .c。
//去字符串最后一个点右边的字符串
$(warning suffix: --$(suffix vendor/Android.mk a b cd)-- )
makefile:52: suffix: --.mk--
14.4 basename取前缀函数
$(basename <names…>)
• 名称:取前缀函数——basename。
• 功能:从文件名序列 中取出各个文件名的前缀部分。
• 返回:返回文件名序列 的前缀序列,如果文件没有前缀,则返回空字串。
• 示例:$(basename src/foo.c src-1.0/bar.c hacks) 返回值是 src/foo src-1.0/bar hacks 。
//和suffix取后缀相反,取最后一个.前面的字符串
$(warning basename: --$(basename vendor/Android.mk a b cdc.dd.d)-- )
makefile:52: basename: --vendor/Android a b cdc.dd--
14.5 addsuffix加后缀函数
$(addsuffix ,<names…>)
• 名称:加后缀函数——addsuffix。
• 功能:把后缀 加到 中的每个单词后面。
• 返回:返回加过后缀的文件名序列。
• 示例:$(addsuffix .c,foo bar) 返回值是 foo.c bar.c 。
//注意新得到的字符串最后的空格没有了
$(warning addsuffix: --$(addsuffix _suffix, a b cdc.dd.d )-- )
$(warning addprefix: --$(addprefix prefix_, a b cdc.dd.d )-- )
makefile:52: addsuffix: --a_suffix b_suffix cdc.dd.d_suffix--
makefile:53: addprefix: --prefix_a prefix_b prefix_cdc.dd.d--
14.6 addprefix加前缀函数
$(addprefix ,<names…>)
• 名称:加前缀函数——addprefix。
• 功能:把前缀 加到 中的每个单词后面。
• 返回:返回加过前缀的文件名序列。
• 示例:$(addprefix src/,foo bar) 返回值是 src/foo src/bar 。
$(warning addsuffix: --$(addsuffix _suffix, a b cdc.dd.d )-- )
$(warning addprefix: --$(addprefix prefix_, a b cdc.dd.d )-- )
makefile:52: addsuffix: --a_suffix b_suffix cdc.dd.d_suffix--
makefile:53: addprefix: --prefix_a prefix_b prefix_cdc.dd.d--
14.7 join
$(join ,)
• 名称:连接函数——join。
• 功能:把 中的单词对应地加到 的单词后面。如果 的单词个数要比 的多,那么, 中的多出来的单词将保持原样。如果 的单词个数要比 多,那么, 多出来的单词将被复制到 中。
• 返回:返回连接过后的字符串。
• 示例:$(join aaa bbb , 111 222 333) 返回值是 aaa111 bbb222 333 。
把list2里面的字符串依次加到1的后面
$(warning join: --$(join list1 list2 list3 list4 list5, a b xcb )-- )
$(warning join: --$(join list1 list2 , a b xcb xxxx)-- )
makefile:52: join: --list1a list2b list3xcb list4 list5--
makefile:53: join: --list1a list2b xcb xxxx--
14.8 wildcard 查询文件
表示查询,当前目录下的so文件,可以查询多个目录,在android mk中需要使用的路径如LOCAL_PATH
dirnotdir=$(notdir $(wildcard ./*.so) )
使用:SRC = $(wildcard *.c ./foo/*.c)
搜索当前目录及./foo/下所有以.c结尾的文件,生成一个以空格间隔的文件名列表,并赋值给SRC.当前目录文件只有文件名,子目录下的文件名包含路径信息,比如./foor/bar.c。
15. shell命令
使用$(shell xxx)
16. ifeq条件判断
ifeq ($(origin FOO), undefined)
FOO = bar
endif
17. foreach循环
//命令中途断开,需要使用
表示javalib是传入第一个参数里的对象,循环执行后面的warning语句
$(foreach javalib, $(1), \
$(warning $(ONE_JARALIB_MOUDLE_NAME) $(TSP_PREBUILT_MODULE_NAME))
18. call函数
call 函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以 call 函数来向这个表达式传递参数。其语法是:
$(call <expression>,<parm1>,<parm2>,...,<parmn>)
19. eval
eval表示展开表达式,使用时可以现场调试
$(eval ONE_JARALIB_MOUDLE_NAME := $(javalib)) \
20. log
warning和info用来打印log,error会直接停止
$(warning warning---- )
$(info info---- )
$(error error---- )
makefile:52: warning----
info----
makefile:54: *** error---- 。 停止。
参照link