Makefile基本规则和原理

阅读《跟我一起写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的依赖关系正确和编译命令所需的文件是存在的情况下。

三、基本原理

  1. make 会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),实例中第一个目标target为run
  3. 如果 run 文件不存在,或是run 所依赖的后面的 .o 文件的文件修改时间要比 run这个文件新,那么,他就会执行后面所定义的命令来生成 run这个文件。(根据这个特性,我每次修改相应的文件时候,有依赖关系的文件都会重新编译和链接。其实完全可以不用make clean,毕竟大型源码重新编译一次是很耗费时间的。)
  4. 如果run所依赖的.o 文件也存在,那么 make 会在当前文件中找目标为.o 文件的依赖关系,也按照第3点的判断依据来更新生成.o文件。
  5. 如果run依赖关系中比如test.o的生成规则没在makefile文件中体现,make会自动产生规则并生成test.o文件,前提是test.c存在当前目录下,否则直接终止执行。
  6. 最终根据对应的依赖关系生成run这个可执行文件。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 来自陈浩的一片老文,但绝对营养。 示例工程:3 个头文件*.h,和 8 个 C 文件*.c。 初 编译过程,源文件...
    周筱鲁阅读 4,747评论 0 17
  • makefile关系到整个工程的编译规则,一个工程中的源文件不计其数,按其类型、功能、模块分别放在若干的目录当中,...
    Joe_HUST阅读 1,904评论 0 3
  • makefile 介绍 make命令执行时,需要一个 makefile 文件,以告诉make命令如何去编译和链接程...
    Stan_Z阅读 1,647评论 2 15
  • Makefile 介绍 make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译...
    Caiaolun阅读 232评论 0 0
  • 完整代码 (function(global) { if(global.seajs) { return; ...
    tzujun阅读 343评论 0 0