Makefile 执行过程 & include 调用方式

2015年12月8日 16:48:31

此中测试代码见笔记 《Makefile入门》

Makefile 之执行过程

  1. 依次读取变量“MAKEFILES”定义的 makefile 文件列表
  2. 读取工作目录下的 makefile 文件(根据命名的查找顺序“GNUmakefile”,“makefile”,“Makefile”,首先找到那个就读取那个)
  3. 依次读取工作目录 makefile 文件中使用指示符“include”包含的文件
  4. 查找重建所有已读取的 makefile 文件的规则(如果存在一个目标是当前读取的某一个 makefile 文件,则执行此规则重建此 makefile 文件,完成以后从第一步开始重新执行)
  5. 初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行分支
  6. 根据“终极目标”以及其他目标的依赖关系建立依赖关系链表
  7. 执行除“终极目标”以外的所有的目标的规则(规则中如果依赖文件中任一个文件的时间戳比目标文件新,则使用规则所定义的命令重建目标文件)
  8. 执行“终极目标”所在的规则

include 调用方式

Makefile 中 include 的调用方式:(针对 include,不考虑 -include、sinclude)

  1. 首先在指定的目录下搜索被调用文件(如果没有路径,则为当前目录)

  2. 如果没有找到,则从 -I 所指定的 include 目录查找,如果还没找到,则从“/usr/gnu/include”“/usr/local/include”等目录查找

  3. 最终结果还是没找到,则 Makefile 输出异常信息 “No such file or directory”。

    测试

    ps:橙色标注部分,追求细节的话依赖目标不应该空着。

    以上操作对应 Makefile 执行过程中第 3 步,然后执行第 4 步:

  4. Makefile 中存在一个目标是当前读取的某一个 makefile 文件,执行此规则来生成对应文件,例如本例中的规则为:

    测试

    则根据该规则生成 .depend 文件。(此步骤亦可理解为:Makefile 会试图寻找匹配规则来生成对应文件)

    Makefile 继续执行,此例成功执行完毕。

  5. 如果没有对应规则,输出错误信息 “make: *** No rule to make target `non-exit-file’. Stop.”。Makefile 终止执行。

    测试

延伸

如果弄懂了以上内容,那么应该很轻易能够明白下图中 “all: .depend…” 的写法没有意义。

——因为 “include .depend” 会先于 根据“终极目标”展开依赖关系 执行,且如有必要 include 操作会自主生成 .depend 文件,然后将 .depend 文件中的依赖关系在主 Makefile 中展开。

此后若再重新生成 .depend 文件(?),已经没有操作需要此文件了(clean 可能会)。只有等到下一次执行 Makefile 时用到,却可能造成某种不确定性的干扰。

?:如果 .depend 的依赖目标为空,如以上截图所示,则会重新生成;如果 .depend 的依赖目标如下图所示,为源文件,则不会重新生成。

测试

参考

参考:说说Makefile那些事儿Makefile自动依赖(ps:这篇帖子中提到的“Makefile中include的调用方式:”与我实际验证有出入,已在笔记中说明。)

其中“程序首次编译时肯定不存在.depend文件,但这时makefile也不需要该文件,因为首次编译肯定连接的都是最新文件。也就是说首次编译时生成的.depend文件其实没用上,而是留作以后有了改动,比如更改了.h文件中的宏变量,则此时可根据.depend中的依赖关系只生成对应的.o文件了” 完全是错误的。

makefile需要 .depend文件,在执行gcc 指令之前就已生成了 .depend文件。展开说一下“以后有了改动…”,头文件改动:a. 改动文件名,则 $(SRCS) 中的文件肯定相应改动(不改动生成.o目标文件时报错),则 .depend 其中描述的目标文件,即 $(OBJS) 重新生成;b. 改动文件内容,则 .depend 中描述的目标文件,即 $(OBJS) 重新生成。

测试

看一下 .depend文件内容:

测试

以上足以说明首次编译时生成的 .depend 文件妥妥的用上了!!