一、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.

一些特殊的伪目标

巧用伪目标及自动化变量

  • 打印变量
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”那么就完蛋了。

日志输出

注意:
echo:会在shell中显示echo这条命令和这条命令的输出结果
@echo:不会在shell中显示echo这条命令,但是会显示命令的输出结果
echo无法在makefile的foreach等语法里使用

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选项。

分类: makefile

0 条评论

发表回复

您的电子邮箱地址不会被公开。