第十四篇 自动生成依赖关系(终结)

前面三篇已经把自动生成依赖关系所需要的知识点进行了剖析,本篇就来完成这个完整的makefile程序。
整体的依赖关系如下所示:
 
目标文件、依赖文件、最终的可执行文件我们都创建对应的文件夹来管理。下面直接给出编写完成的makefile程序:
 
执行make,输出结果如下图所示:
 
到目前,一切都很正常,下面我们来改一下头文件。
新建一个文件new.h,将func.h中的宏定义剪切并放到new.h中,在func.h中包含new.h,执行make。输出结果如下:
 
可见,make已经感知到了func.h得变化,于是重新执行了编译和链接,但是.dep依赖文件是没有重新生成的,现在我们更改new.h中的宏定义,将Hello Makefile改为Hello World。再次执行make,这次make提示没有什么可做的。
  我们明明更改了new.h中的宏定义,make却没有感知到。这是因为当.dep文件生成后,如果动态的改变头文件之间的依赖关系,那么make可能无法检测到这个改变,进而做出错误的编译决策。
  我们打开func.dep文件,内容如下:
 
  虽然我们增加了new.h,但是make并没有去更新依赖文件,导致依赖文件处于一个比较旧的状态,所以,当我们在新增加的头文件中做更改时,make是无法感知到的,因为这些头文件根本就没有作为依赖加入到规则中。
  考虑以下的解决方案:
  1、将依赖文件名作为目标加入自动生成的依赖关系中。
  2、通过include加载依赖文件时判断是否执行规则。
  3、在规则执行时重新生成依赖关系文件。
  4、最后加载新的依赖文件。
上面的2、3、4条正是我们在上一篇中分析的include的不为人知的行为。我们只需在makefile中做微小的修改即可。如下所示,我们将$@加入到了正则表达式的替换部分,也即将依赖文件名作为目标。
make在解析makefile时,首先加载include部分文件,然后根据文件名去查找规则,如果有新的头文件加入,如果包含到了c文件中,那必然会被感知到,如果是被包含在以前的旧的头文件中,这也会被make感知到(因为解决方案中的第一条,相当于我们给依赖文件增加了一些依赖),这时make会及时更新.dep依赖文件,将最新的依赖关系保存在依赖文件中,并重新加载依赖文件。
这时func.dep文件的内容如下所示:
 
deps/func.dep : func.c func.h new.h这条依赖和$(DIR_DEPS)/%.dep : %.c形成了依赖拆分的关系,这也是我们先前讲到的预备知识。
 
小结:
  1、makefile中可以将目标的依赖拆分写到不同的地方。
  2、include关键字能够触发相应规则的执行。
  3、如果规则的执行导致依赖的更新,可能导致再次解释执行相应的规则,甚至形成死循环。
  4、依赖文件也需要依赖于源文件得到正确的编译决策。
  5、自动生成文件间的依赖关系能够提高makefile的移植性。
posted @ 2018-12-30 21:15  lemaden  阅读(108)  评论(0编辑  收藏  举报