Makefile备忘
本文摘自 : 跟我一起写 Makefile
makefile文件一般保存名称为makefile或者Makefile,没有后缀。
make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
在 Makefile 中,规则的顺序是很重要的,因为,Makefile 中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让 make 知道你的最终目标是什么。一般来说,定义在 Makefile 中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make 所完成的也就是这个目标。
Makefile 里主要包含了五个东西: 显式规则、隐晦规则、变量定义、文件指示 和 注释:
1. 显式规则。显式规则说明了,如何生成一个或多个目标文件。这是由 Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
2. 隐晦规则。由于我们的 make 有自动推导的功能,所以隐晦的规则可以让我们比较简略地书写 Makefile,这是由 make 所支持的。
3. 变量的定义。在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像你 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
4. 文件指示。其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像C 语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if 一样;还有就是定义一个多行的命令。
5. 注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符。这个就像 C/C++ 中的“//”一样。如果你要在你的 Makefile 中使用“#”字符,可以用反斜框进行转义,如:\# 。
最后,还值得一提的是,在 Makefile 中的命令,必须要以 Tab 键开始。
make的执行过程:
1. 读入所有的 Makefile。
2. 读入被 include 的其它 Makefile。
3. 初始化文件中的变量。
4. 推导隐晦规则,并分析所有规则。
5. 为所有的目标文件创建依赖关系链。
6. 根据依赖关系,决定哪些目标要重新生成。
7. 执行生成命令。
makefile的语法规则(注意在makefile中指令必须以tab键开头,在vim中设定:set tabstop=4):
在 Makefile 使用 include 关键字可以把别的 Makefile 包含进来,这很像 C 语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。
在 include 前面可以有一些空字符,但是绝不能是 Tab 键开始。include是make保留的关键字不是shell中可执行的指令:include foo.make a.mk b.mk c.mk e.mk f.mk
环境变量 MAKEFILES,尽量不用这个特性。当 Makefile 出现了怪事,可以看看当前环境中有没有定义这个变量。
一般来说,makefile的目标基本上是一个文件,但也有可能是多个文件:
targets : prerequisites ; command #冒号前是需要生成的文件,冒号后面是生成这个文件所需要的文件(文件依赖) 。只有在冒号后面的文件比冒号前的文件新,指令command才会被执行。
command
...
targets 是文件名,以空格分开,可以使用通配符。command 是命令行,如果其不与“target:prerequisites”在一行,那么,必须以 [Tab键] 开头,如果和 prerequisites 在一行,那么可以用分号做为分隔。
targets 可以是一个 object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。make 会比较 targets 文件和 prerequisites 文件的修改日期,如果 prerequisites 文件的日期要比 targets 文件的日期要新,或者 targets 不存在的话,那么,make 就会执行后续定义的命令。
在makefile 中我们可以使用变量。makefile 的变量也就是一个字符串,理解成 C 语言中的宏可能会更好。
例1:
edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o\ //反斜杠(\)是换行符的意思。指令必须以tab键开头。
insert.o search.o files.o utils.o
... ...
clean :
rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
上面的edit (target)就是由冒号后面的.o文件(prerequisites)生成。
第二行中的cc是编译指令,只有在.o文件中有比edit新的文件存在或在edit这个文件不存在,第二行的指令行才会被执行,这样可以减少重复。
因为clean后面没有文件,所以make不会主动的执行其后面的指令,但可以显示的调用这条指令:make clean
例2:(这段代码的作用和例1是一样的)
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
clean :
rm edit $(objects)
make可以自动推导文件以及文件依赖关系后面的命令,只要 make 看到一个.o 文件,它就会自动的把.c 文件加在依赖关系中。
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h #自动的将main.cpp当作依赖文件。
... ...
.PHONY : clean
clean :
-rm edit $(objects)
PHONY 意思表示 clean 是一个“伪目标”。而在 rm 命令前面加了一个小减号的意思不要管可能出现的某些错误,继续做后面的事。