一、makefile的产生
http://www.crazyant.net/414.html (示例中,两个相互的依赖的.c文件,作者并没有写头文件,因为gcc是允许这样写的。但是编译过程会有警告,不影响编译。看这里:https://www.jianshu.com/p/e5c6a255076b
)
makefile文件的命名
https://www.ngui.cc/article/show-265470.html?action=onClick
指定makefile文件
make -f Makefile文件名
https://www.cnblogs.com/LiuYanYGZ/p/5441351.html
多个makefile -f m1 -f m2
多个 makefile 文件将会被按照指定的顺序进行链接并被 make 解析执行
指定make目录
make -C
https://blog.csdn.net/xiaoyink/article/details/108465261
include子Makefile
https://blog.csdn.net/yi412/article/details/48207903
二、makefile的原理
https://blog.csdn.net/chudongfang2015/article/details/79037409
如何判断目标是否需要重新构建
前置条件通常是一组文件名,之间用空格分隔。它指定了"目标"是否重新构建的判断标准:只要有一个前置文件不存在,或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),"目标"就需要重新构建。
三、makefile的好处
- 简化编译执行的命令(并没有gcc –c的过程)
- 一次make后,下次只会编译改动的文件,其它的文件不会再编译了。
看下面我第2次make,两个.o文件并没有重新生成,但是main会重新生成。
四、makefile调试
-
输出日志或者中断运行
https://www.cnblogs.com/black-mamba/p/9638396.html -
只看编译过程,并不真正编译
make --just-print make -n
-
追踪Makefile的调用链路
如果Makefile有多层嵌套,如何知道当前Makefile被哪个Makefile所调用?
-
set -e
set -e;command1;command2;...
只要有一个command执行失败,后面的command都不会执行。
五、makefile语法
https://blog.csdn.net/weixin_38391755/article/details/80380786,原文作者:https://blog.csdn.net/haoel/article/details/2886
https://blog.csdn.net/weixin_43621681/article/details/87925192
https://www.zhaixue.cc/makefile/makefile-foreach.html (函数)
https://www.cnblogs.com/kekec/p/3538019.html
https://www.cnblogs.com/raina/p/12342043.html
基本格式
target:requirments ; command
或者
target:requiremnts
1个Tab空格+command
- Makefile依赖关系中的竖线“|”
https://blog.csdn.net/sdu611zhen/article/details/53011253
竖线左边的目标就是正常前提目标,竖线右边的目标就是命令前提目标(我们需要执行某个或某些规则,但不能引起生成目标被重新生成。)。
Makefile脚本与Shell脚本语法的区别
https://www.jianshu.com/p/1818a7afe535
怎么运行makefile文件
将文件命名为makefile或者Makefile,然后在当前目录执行make指令即可进行编译。
自己写个简单的makefile文件然后运行:
https://blog.csdn.net/wangqingchuan92/article/details/92832544(很好一个例子整体上知道makefile是干什么的,麻雀虽小,五脏俱全。)
注意:make若不指定目标,默认执行第一个有效目标。通常为了第一个目标不被意外执行,只写target:,不执行任何操作
make可能遇到的问题
1.makefile---makefile:5: *** 遗漏分隔符 。 停止
https://blog.csdn.net/yfcheng_yzc/article/details/29609229
重要的概念
- 规则的概念及语法
- 伪目标的概念
如android源码执行make clean,这里的clean就是伪指令。
伪指令什么时候会被执行:
这里要说明一点的是,clean不是一个文件,它只不过是一个动作名字,有点像C语言中的lable一样,其冒号后可以什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make命令后明显得指出这个lable的名字。这样的方法非常有用,我们可以在一个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。
-
make clean与make clobber的区别
https://blog.csdn.net/pcsxk/article/details/52594223 -
make clean 与 make distclean 的区别
https://www.jianshu.com/p/9920cd513c2b/
make clean 仅清除之前编译的可执行文件及配置文件。
make distclean 要清除所有生成的文件。 -
指令开始要用TAB隔开
如果command不加tab,会报错:missing separator
。command只能写在target里,直接在Makefile文件中写command,也会报missing separator
错误。
注意command里,if表达式等不需要加tab.
一些特殊的伪目标:
- FORCE
https://blog.csdn.net/engineer0/article/details/111415894
哪个目标依赖了FORCE伪目标,哪个目标每次make都会重新执行一遍。
巧用伪目标及自动化变量:
- 打印变量
SRC := "./src/test1.c"
print-% :
@echo $* = $($*)
执行make print-变量名
即可打印对应的变量,为了更加通用,可以将打印目标单独封装成一个mk文件,然后通过-f 引用。
变量
1.变量赋值
1)使用"="号来赋值变量
(Android.mk就是用这种语法)
变量可以使用后面的变量来定义,如:
foo = $(bar)
bar = $(ugh)
ugh = Huh?
all:
echo $(foo)
最终的输出值是Huh?
2)使用":="号来赋值变量
前面的变量不能使用后面的变量,只能使用前面已定义好了的变量,更加安全。
y := $(x) bar
x := foo
那么,y的值是“bar”,而不是“foo bar”。
3)使用"?="号来赋值变量
FOO ?= bar
其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
4)使用"+="号来赋值变量
追加
2.引用变量
用美元符号即可,$(varName)
3.系统变量
4.自动化变量
https://blog.csdn.net/qq_39498080/article/details/79237260
https://blog.csdn.net/qu1993/article/details/88871799
文件相关
$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件。
$?:所有比目标新的依赖目标的集合。以空格分隔。(即引起当前目标更新的依赖文件的集合)
$(MAKECMDGOALS):表示make命令指定的目标
$(@D):
表示"$@"的目录部分(不以斜杠作为结尾) ,如果"$@"值是"dir/foo.o",那么"$(@D)"就
是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录) 。
$(@F):
表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相
当于函数"$(notdir $@)"
$*:
- 没有%匹配:表示不带后缀的目标文件名
如test1.o: test1.c test2.h
,则$*表示test1 - 有%匹配:目标文件名去掉非%部分后的文件名
例1:
如:a.%.b: @echo $*
执行
make dir/a.foo.b
,打印结果为dir/foo.
例2:
如:
print-% :
@echo $*
执行make print-SRC
,打印结果为SRC.
5.变量的高级用法
-
追加变量 (Android.mk依赖其它库经常会用到这个语法)
我们可以使用“+=”操作符给变量追加值,如: objects = main.o foo.o bar.o utils.o objects += another.o 于是,我们的$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o被追加进去了) 使用“+=”操作符,可以模拟为下面的这种例子: objects = main.o foo.o bar.o utils.o objects := $(objects) another.o 所不同的是,用“+=”更为简洁。 如果变量之前没有定义过,那么,“+=”会自动变成“=”,如果前面有变量定义,那么“+=”会继承于前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符,如: variable := value variable += more 等价于: variable := value variable := $(variable) more
-
define关键字定义多行变量(宏)
变量的值可以包含函数、命令、文字,或是其它变量,如:define two-lines echo foo echo $(bar) endef
调用two-lines变量,就会在控制台打印两行日志。
-
变量替换引用
https://blog.csdn.net/oqqHuTu12345678/article/details/125645226
6.变量共享
export的变量可以被子Makefile引用
https://cloud.tencent.com/developer/article/1012187
https://www.jianshu.com/p/6b2c4e8cfc3a
7.通过make命令传入变量
make VAR=XX
8.判断变量是否为空
ifeq ($(platform), )是判断platform是否为空
条件表达式
https://blog.csdn.net/weixin_43083491/article/details/112476879
条件表达式的语法为:
<conditional-directive>
<text-if-true>
endif
以及:
<conditional-directive>
<text-if-true>
else
<text-if-false>
endif
conditional-directive类型
ifeq:是否相等
ifneq:是否不相等
ifdef:是否定义
ifndef:是否未定义
if表达式:https://www.shuzhiduo.com/A/KE5QlPk0JL/
函数
https://blog.csdn.net/shenfengchen/article/details/110846275
函数的语法为:
$(<function> <arguments> )
或是
${<function> <arguments>}
这里,<function>就是函数名,make支持的函数不多。<arguments>是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。
1)常用的3个函数:wildcard notdir patsubst
https://blog.51cto.com/zhaoxiaohu/2410073
- wildcard
判断文件是否存在:https://blog.csdn.net/Herbert25/article/details/130947371
ifneq ($(wildcard FILE),)
#文件存在
endif
2)call函数
https://blog.csdn.net/qu1993/article/details/88976861
对于函数调用加不加call都一样,$(fun1)与$(call fun1)
效果一样。
3) filter(正向过滤)
https://blog.csdn.net/wd229047557/article/details/104670714
3)filter-out(反向过滤)
https://blog.csdn.net/naipeng/article/details/77879527
4)patsubst (字符串替换)
https://zhuanlan.zhihu.com/p/482984064
https://blog.csdn.net/andrewgithub/article/details/83717585
$(patsubst 原模式, 目标模式, 文件列表)
如:$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o
5)strip (合并连续空格)
https://blog.csdn.net/zhoudengqing/article/details/41777665
strip可以指定多个变量参数:
STR = a b c
STR2 = a2 b2 c2
LOSTR = $(strip $(STR) $(STR2))
LOSTR的打印结果为:a b c a2 b2 c2
6)abspath (绝对路径)
7) info (打印输出)
在Makefile文件中,非target位置,无法直接使用echo输出,只能通过$(info xxxx)
输出。
打印字符串与变量,不需要加双引号:$(warning board_config_mk is: $(board_config_mk))
8)call
https://www.jianshu.com/p/dcb4270c385c
函数语法:
$(call VARIABLE,PARAM,PARAM,...)
函数功能:
在执行时,将它的参数"PARAM"依次赋给临时变量"$(1)","$(2)".call对参数的数目没有限制,也可以没有参数值。
9)subst (字符串替换)
$(subst <aa>,<bb>,<text>)
把text中的aa替换成bb
10)addprefix (添加前缀)
https://blog.csdn.net/zhuiqiuk/article/details/77096132
自定义函数
注释符#
https://www.cnblogs.com/cjhk/p/11598565.html
注意#对变量的定义也会有影响,如:
dir := /foo/bar # directory to put the frobs in
dir这个变量的值是“/foo/bar”,后面还跟了4个空格,如果我们这样使用这样变量来指定别的目录——“$(dir)/file”那么就完蛋了。
日志输出
- 在command里输出:echo
@echo :https://blog.csdn.net/linuxweiyh/article/details/84673489
注意:
echo:会在shell中显示echo这条命令和这条命令的输出结果
@echo:不会在shell中显示echo这条命令,但是会显示命令的输出结果
echo无法在makefile的foreach等语法里使用
- 在makefile非command位置输出
http://t.zoukankan.com/dream397-p-13851604.html
$(warning xxxxx)或者$(error xxxxx)
echo与$(info)输出先后顺序
https://www.thinbug.com/q/47367589
echo是一个shell命令。因此,如果将其放入配方中,将调用shell来运行它,shell命令将生成输出:
foo: ; @echo "Hello World"
**通配符%与***
%可以匹配文件与规则(包括伪目标),而*只能匹配文件。
https://www.cnblogs.com/warren-wong/p/3979270.html
https://zhuanlan.zhihu.com/p/362915681
转义/二次展开$$
http://blog.chinaunix.net/uid-12072359-id-2960866.html
不要认为在makefile的规则的命令行中使用$var就是将makefile的变量和shell共享了,这里仅仅是读取makefile的变量然后扩展开,将其值作为参数传给了一个shell命令。而$$var是在访问一个shell命令内定义的变量,而非makefile的变量。此外,如果某规则有n个shell命令行构成,而相互之间没有用';'和'\'连接起来的话,就是相互之间没有关联的shell命令,相互之间也不能变量共享。
https://blog.csdn.net/gzxb1995/article/details/123308558
比如$(warning "$$(A)")
输出就是$A,如果$(warning "$(A)")
输出就是变量A的值。
加号+,减号-和at号@的含义
https://www.cnblogs.com/20170722-kong/p/8322369.html
- -号
遇到错误也继续执行
- @号
https://www.jianshu.com/p/8d0529d188a6
通常,make工具在执行Makefile中的某一条命令前,会将此命令的内容打印在屏幕上,我们称之为 - 命令回显。
当某一条命令前有@符号时,命令不再被回显。同时命令执行时会先删除@符号,然后执行接下来的内容。
一般,我们应该仅在那些打印信息的命令前加@符号,如echo命令。
注意:
当命令中有;号时,;号后面无须加@,否则会报错。只能在最前面加@
- +号
要求make执行命令,即使使用了-n选项。
0 条评论