GNU Make依赖重评估问题:子Makefile重建库后主程序未自动更新
问题:主Makefile无法检测子Makefile重建的库
我有一个依赖于独立Makefile构建的库的程序,主Makefile无法正确检测该库已重建,导致不会重新生成程序。
主Makefile(简化版)
progA: srcA libA touch $@ libA: make_libA_if_needed .PHONY: make_libA_if_needed make_libA_if_needed: make -f Makefile.libA libA clean: rm -f progA libA
子Makefile(Makefile.libA)
libA: libsrcA touch $@
正常工作场景
当libA不存在或无需重建时,配置运行正常:
jronnber@jronnber-mobl:~/tmp $ touch srcA libsrcA jronnber@jronnber-mobl:~/tmp $ make make -f Makefile.libA libA make[1]: Entering directory '/home/jronnber/tmp' touch libA make[1]: Leaving directory '/home/jronnber/tmp' touch progA jronnber@jronnber-mobl:~/tmp $ make make -f Makefile.libA libA make[1]: Entering directory '/home/jronnber/tmp' make[1]: 'libA' is up to date. make[1]: Leaving directory '/home/jronnber/tmp' jronnber@jronnber-mobl:~/tmp $
异常场景
更新libsrcA后,需要运行两次make才能正确重建progA:
jronnber@jronnber-mobl:~/tmp $ touch libsrcA jronnber@jronnber-mobl:~/tmp $ make make -f Makefile.libA libA make[1]: Entering directory '/home/jronnber/tmp' touch libA make[1]: Leaving directory '/home/jronnber/tmp' jronnber@jronnber-mobl:~/tmp $ make make -f Makefile.libA libA make[1]: Entering directory '/home/jronnber/tmp' make[1]: 'libA' is up to date. make[1]: Leaving directory '/home/jronnber/tmp' touch progA jronnber@jronnber-mobl:~/tmp $
问题
这是make的bug吗?还是可以通过修改Makefile来检测到libA已被子make重建?
解决方案
这不是make的bug,是当前Makefile的依赖关系设计存在问题。主Makefile中libA目标依赖于.PHONY的make_libA_if_needed,而伪目标总是会被标记为需要更新。但make的执行逻辑是先检查所有依赖的修改时间,再决定是否重建目标:第一次运行make时,主make先触发子make更新了libA,但此时主make已经完成了progA依赖的初始检查,不会重新判断libA的时间变化,因此需要第二次运行才会重建progA。
可以通过以下方式修改解决:
方法1:移除中间伪目标,直接让libA目标调用子make
修改主Makefile,去掉make_libA_if_needed伪目标,让libA的规则直接调用子make:
progA: srcA libA touch $@ libA: $(MAKE) -f Makefile.libA libA clean: rm -f progA libA
这里用$(MAKE)代替直接make是make的最佳实践,能保证递归调用时使用同一个make程序,正确处理环境变量等细节。
修改后测试效果:
jronnber@jronnber-mobl:~/tmp $ touch libsrcA jronnber@jronnber-mobl:~/tmp $ make make -f Makefile.libA libA make[1]: Entering directory '/home/jronnber/tmp' touch libA make[1]: Leaving directory '/home/jronnber/tmp' touch progA
仅需一次make即可完成libA和progA的重建。
方法2:让主Makefile感知子项目的依赖(不推荐)
如果愿意让主Makefile知晓子项目的依赖,可以让libA依赖于Makefile.libA和libsrcA,但这样会失去子Makefile的独立性,后续子项目依赖变更时需要同步修改主Makefile,不够灵活。
内容的提问来源于stack exchange,提问作者Johan
相关产品推荐
相关产品推荐

