阅读《跟我一起写makefile》,摘录文章个人认为有助于理解的语句,并记录自己验证实践的过程,方便自己后续工作中复习。
一、基本规则
target … : prerequisites …
command
- target 是一个目标文件(makefile支持多目标),可以是 Object File,也可以是执行文件,还可以是一个标签(Label)。
- prerequisites 生成 target 所需要的文件或是目标。
- command 为 make 需要执行的命令。(任意的 Shell 命令)
这是一个文件的依赖关系,也就是说,target 这一个或多个的目标文件依赖于prerequisites 中的文件,其生成规则定义在 command 中。说白一点就是说,prerequisites中如果有一个以上的文件比 target 文件要新的话,command 所定义的命令就会被执行。这就是 Makefile 的规则。也就是 Makefile 中最核心的内容。
二、最基本的实例
显式规则,依赖关系写的比较清楚。
run: main.o hello.o test.o
gcc -o run main.o hello.o test.o
main.o: main.c
gcc -c main.c
hello.o: hello.c
gcc -c hello.c
test.o: test.c
gcc -c test.c
clean:
rm run *.o
运行结果:
root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make run
gcc -c main.c
gcc -c hello.c
gcc -c test.c
gcc -o run main.o hello.o test.o
run所需要的依赖文件不存在时,执行下一语句。待依赖文件生成时,继续执行run对应的命令。
如果依赖的test.o文件没有生成的规则,makefile会自动产生规则去生成test.o文件。这个特性就是隐晦规则,主要靠make自动推导。只要 make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如自动把test.c加入到依赖关系中,并且cc -c -o test.o test.c也会被推导出来。
删除该语句测试
test.o: test.c
gcc -c test.c
运行结果:
gcc -c main.c
gcc -c hello.c
cc -c -o test.o test.c
gcc -o run main.o hello.o test.o
如果没有test.c文件则无法生成,直接终止执行。
root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make run
gcc -c main.c
gcc -c hello.c
make: *** No rule to make target `test.o', needed by `run'. Stop.
make 并不管命令是怎么工作的,他只管执行所定义的命令。
make 会比较 targets 文件和 prerequisites 文件的修改日期,如果 prerequisites 文件的日期要比 targets 文件的日期要新,或者 target 不存在的话,那么,make 就会执行后续定义的命令。我发觉书上这句话有点问题。
测试把hello.c文件删除后,即无法生成hello.o这个target,执行make run,结果如下
root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make run
gcc -c main.c
make: *** No rule to make target `hello.c', needed by `hello.o'. Stop.
后续定义的语句并不会去执行,直接终止。
test.o: test.c
gcc -c test.c
原来是我理解错误了,书中后面提到:
在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make 就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make 根本不理。make 只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
这个target不存在,是指上一次编译生成的run,已经不存在需要执行对应的command来产生。并且大前提是整个makefile的依赖关系正确和编译命令所需的文件是存在的情况下。
三、基本原理
- make 会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它会找文件中的第一个目标文件(target),实例中第一个目标target为run
- 如果 run 文件不存在,或是run 所依赖的后面的 .o 文件的文件修改时间要比 run这个文件新,那么,他就会执行后面所定义的命令来生成 run这个文件。(根据这个特性,我每次修改相应的文件时候,有依赖关系的文件都会重新编译和链接。其实完全可以不用make clean,毕竟大型源码重新编译一次是很耗费时间的。)
- 如果run所依赖的.o 文件也存在,那么 make 会在当前文件中找目标为.o 文件的依赖关系,也按照第3点的判断依据来更新生成.o文件。
- 如果run依赖关系中比如test.o的生成规则没在makefile文件中体现,make会自动产生规则并生成test.o文件,前提是test.c存在当前目录下,否则直接终止执行。
- 最终根据对应的依赖关系生成run这个可执行文件。