Makefile
通过需要集中编译的文件整合,按照一定的书写规则,可以写成一个类似批处理的文档,这个文档就是Makefile。通过它可以集成编译一个庞大的项目,利于修改编译内容和维护。
一个示例
a.out : main.o add.o sub.o sef.o
gcc -o a.out main.o add.o sub.o sef.o
main.o : main.c
gcc -c main.c
add.o : add.c
gcc -c add.c
sub.o : sub.c
gcc -c sub.c
clean :
rm -rf *.o *.out
组成和各个部分的书写规则
规则:以规则为单位书写并执行,一条条的规则组成了一个Makefile文件。规则分为显式规则和隐式规则。一条规则由两句话组成,由一条依赖语句和一条命令语句组成。依赖语句需要顶格书写,命令语句需要缩进四个空格(既一个Tab)。
示例 #Makefile的一条显式规则 main.o : main.c defs.h cc -c main.c #Makefile的一条隐式规则 main.o: main.c
依赖:冒号是用来定义一条依赖语句的标志。冒号左边的文件叫做目标(target),右边的称作依赖目标。
命令:命令语句的书写规则跟在终端(terminal)中的编译语句书写规则完全一致的。命令语句有先后顺序,排在后面的命令比排在前面的要新。
# @表示不输出该命令(并非不输出命令执行的结果) @rm -vrf *.o *.out # 忽略错误,继续执行 -rm -vmf *.o *.out -@rm -vmf *.o *.out
注释:以“#”开头的为注释。并且,注释是独立的一行,不能嵌条。
#这是注释 main.o: main.c #这不是注释,这是非法的
依赖语句
目标(target):目标分为普通目标和伪目标。
普通目标:能够生成文件的目标。如下,
main.o
就是普通目标,因为执行完这条规则后,会自动生成一个main.o
的文件。main.o : main.c gcc -c main.c
普通目标中,最顶层的那么目标为终极目标。生成了终极目标,也就意味着Makefile文件执行完成。如下面代码,
a.out
就是一个终极目标。a.out : main.o add.o sub.o sef.o gcc -o a.out main.o add.o sub.o sef.o main.o : main.c gcc -c main.c
当最顶层的目标有多个的时候,那么第一个目标为第一目标。
伪目标:伪目标的依赖语句中没有依赖目标,因此也不会生成文件,它是用来执行一些命令的。如
make clean
语句中,clean
就是一个伪目标。使用Makefile预定的伪目标时(请查看附录来查询伪目标),不需要进行声明。而自己定义的伪目标,为了安全建议声明。# 声明伪目标的格式 .PHONY: <Phony_Target_Name> # 示例 .PHONY: hello go Oh_yeah
依赖:生成目标需要的那些文件。
冒号:冒号有双冒号规则和单冒号规则。同一个目标可以同时出现在不同的规则中,但是仅仅可以只用一种冒号规则。
# 合法 main.o : main.c gcc -c main.c main.o : add.c sub.c gcc -c add.c sub.c main.o : main.c sub.c gcc -c main.c sub.c #非法 main.o : main.c main.o:: add.c sub.c
单冒号规则和双冒号规则
双冒号规则:双冒号规则目标的地位等同于第一目标,无论怎样都会执行,直到目标文件为最新。
main.o:: main.c gcc -c main
单冒号与双冒号比较
- 一个目标同时拥有多个规则:单冒号会把依赖合并,命令仅仅执行最新的命令。而双冒号会单独执行。
- 一个目标没有依赖:当没有依赖但已经有了目标文件的时候,单冒号的规则永远都不会被执行(仅仅有目标文件,因此目标文件永远是最新的),而双冒号规则会执行;当是伪目标的时候,两者均会执行。
单冒号与双冒号规则在讨论的时候均以一条规则中的:依赖和命令为中心来进行辨别它们的不同之处。
Makefile工作原理
- make执行后,会搜索名字为”Makefile”或”makefile”的文件。
- 找到“第一目标”,检查修改时间。
- 如果第一目标并非为最新(相对于那条规则中依赖文件的修改时间),重新执行该规则。
规则执行的过程为如下:
- 第一目标并非最新
- 通过本规则的命令和依赖文件重新生成第一目标
- 依赖不存在,会执行其他规则生成该依赖文件;依赖存在,执行该规则生成第一目标。
make
只管文件的依赖性,编译出错或者依赖文件生成的错误make
命令都会终止。- 因为
clean
和第一目标有不存在依赖关系,不会自动执行。