Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,文件之间有哪些依赖等。Makefile有自己的书写格式、关键字、函数。像C 语言有自己的格式、关键字和函数一样。而且在Makefile中可以使用系统shell所提供的任何命令来完成想要的工作。Makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
Makefile里包含了:显示规则、隐晦规则、变量定义、文件指示和注释
Makefile的文件名有两种方式:
# 默认的文件名,Makefile、makefike
> make
# 指定文件名,Make.Linux
> make -f Make.linux
target ... : prerequisites ...
command
Makefile规则的target 和prerequisites 存在依赖关系,target是依赖于prerequisites;Makefile 存在自动推导的能力;不断向上<font color=red>自动推导</font>;
参考示例:
test : test1.o test2.o
cc -o test test1.o test2.o
test1.o : test1.c test1.h
cc -c test1.c
test2.o : test2.c test2.h
cc -c test2.c
clean :
rm test test1.o test2.o
Makefile会进行自动推到,层层依赖、推导关系如下,
makefile会把所有依赖关系列举出来,执行make命令的时候,会根据依赖关系自动编译
每个.o文件的依赖文件默认会有同名的.c文件,比如有一个target是test.o,那么test.c默认就是test.O的依赖文件,这个是makefile的隐晦规则,是make会自动推导出来的
在默认命名的情况下,输入make命令做了什么?
make的依赖性,会自动推到一层层的依赖关系,最终编译出最终的目标。
例如:
# 声明一个变量
objects = test1.o test2.o \
test3.o
# 使用变量
test: $(objects)
cc -o test $(objects)
变量的基本赋值
在定义变量的值时,我们可以使用其它变量来构造变量的值,在Makefile中有两种方式来在用变量定义变量的值。
例如:
x := foo
y := $(x)
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被追加进去了)
如果变量之前没有定义过,那么,“+=”会自动变成“=”,如果前面有变量定义,那么“+=”会继承于前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符,如:
<font color=red size=5> (var:a = b) 或{var:a = b }</font>
把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符还是看一个示例吧:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
# 把“$(foo)”中所有以“.o”字串“结尾”全部替换成“.c”,最终bar的值是a.c b.c c.c
x = y
y = z
a := $($(x))
# 在这个例子中,$(x)的值是“y”,所以$($(x))就是$(y),于是$(a)的值就是“z”
Makefile中只有行注释,注释使用”#“ 字符 例如:
# 这是makefile的注释
在Makefile使用include关键字可以把别的Makefile包含进来,make命令开始时,会把找寻include所指出的其它Makefile,并把其内容安置在当前的位置。这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。include的语法是:
include <filename>
# 在include前面可以有一些空字符,但是绝不能是[Tab]键开始
# filename可以是当前操作系统Shell的文件模式(可以保含路径和通配符)
-include <filename>
# 无论include过程中出现什么错误,都不要报错继续执行。上面那条指令若是找不到include的目标文件,会报错
clean:
rm *.o temp
<font color=red size=4>伪目标不会自动被执行,只能显式地调用执行。</font>但是上面伪目标的写法有一个缺陷,若是当前目录下存在有一个文件名为"clean",那么根据我们的规则,command将不会被执行,因为目标已经存在了,为了解决这个问题,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”
.PHONY : clean
clean:
rm *.o temp
通过.PHONY,无论是否存在“clean”文件,我们的command都将会被执行了
常见伪目标
伪目标 | 描述 |
---|---|
all | 这个伪目标是所有目标的目标,其功能一般是编译所有的目标。 |
clean | 这个伪目标功能是删除所有被make创建的文件。 |
install | 这个伪目标功能是删除所有被make创建的文件。 |
这个伪目标的功能是例出改变过的源文件。 | |
tar | 这个伪目标功能是把源程序打包备份。也就是一个tar文件。 |
dist | 这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。 |
TAGS | 这个伪目标功能是更新所有的目标,以备完整地重编译使用。 |
check 和test | 这两个伪目标一般用来测试makefile的流程。 |
:=
: 强制按先后顺序执行,立即赋值。=
:赋值的结果会等到整个路径执行完再决定,后面的会覆盖前面的,延迟赋值。示例:
$ cat Makefile
a = foo
b1 := $(a) bar
b2 = $(a) bar
a = xyz
all:
@echo b1=$(b1)
@echo b2=$(b2)
$ make
b1=foo bar
b2=xyz bar
逗号和空格是 Makefile 表达式中的特殊符号
https://juejin.cn/post/6844904001872330760#heading-4
https://blog.csdn.net/weixin_38391755/article/details/80380786/
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。