Makefile的re目标在--jobs参数大于1时不总是重新编译库的问题
你推测的场景完全成立。问题根源是你当前Makefile中re目标的两个前置依赖fclean和all没有显式的先后执行约束:Make仅知道re需要等待fclean和all都执行完成,并不会默认要求all必须在fclean结束后才启动。当开启--jobs=N且N>1时,fclean和all会被并行调度:
- 第一次执行
make re -j2时,all规则先检查到当前已经存在library.a和obj目录下的目标文件,判定不需要重新编译,同时执行的fclean会把这些文件删除,最终就只会输出删除操作的日志。 - 第二次执行时,
all检查到library.a已经被上次的fclean删除,才会正常执行编译流程,就出现了你观察到的现象。
不需要强制限定--jobs=1,有多个兼容并行的修复方案:
- 【兼容性最优方案】使用递归Make调用保证执行顺序
修改re目标的规则为:
re: $(MAKE) fclean $(MAKE) all
这种写法会让Make先完整执行完fclean对应的子Make进程,再启动all对应的子Make进程,完全规避并行冲突,兼容所有版本的GNU Make。
2. 【GNU Make 4.3+版本方案】使用.WAIT特殊目标显式指定顺序
如果你的运行环境可以升级到GNU Make 4.3及以上版本,可以用内置的.WAIT特殊目标声明依赖顺序:
re: fclean .WAIT all
.WAIT会告诉Make必须等前面的所有依赖执行完成,才能调度后面的依赖执行,也可以保证fclean先跑完再执行all。
3. 额外规范补充:建议将伪目标加入.PHONY
clean、fclean、re这类不需要生成对应同名文件的目标,建议显式声明为伪目标,避免当前目录出现同名文件时,Make误判目标已更新不执行规则:
.PHONY: all clean fclean re
内容的提问来源于stack exchange,提问作者Arthur Khazbulatov
相关产品推荐
相关产品推荐

