GNU make:代码生成器的正确依赖配置与删除文件处理方案
问题根因
你的实现核心问题是给了Make错误的规则声明:
dep1 sources : config这条规则声明了配方会同时生成dep1和sources两个文件,但实际配方只会生成dep1,完全不会处理sources- 多线程
-j执行时,Make会根据初始文件状态做一次性调度:发现sources缺失,就会触发dep1 sources规则,同时认为sources会被这条规则生成,所以会并行调度object的编译任务,这时候负责实际生成sources的gen_ready规则还没执行,就会出现cat sources找不到文件的报错。 - 单线程或者用分组目标
&:时正常,是因为这两种场景下Make会等待同规则的所有目标处理完成、或者整个分组配方执行完才会调度后续依赖,刚好避开了调度错位的问题。
解决方案
不需要强制Make重新扫描依赖,只要修正规则声明,让每个配方的实际产出和声明的目标完全对齐即可,修改后的Makefile示例如下:
all : object # 测试用配置生成 config: touch config # 单独声明dep的更新规则,不绑定不存在的sources目标 # 实际场景下你可以批量生成所有dep<n>的同类规则 dep1 : config touch dep1 # 用分组目标声明本配方会同时生成sources和gen_ready两个文件 # 所有需要判断是否更新的dep都写在前置依赖里 sources &: gen_ready gen_ready : dep1 echo $? > sources touch gen_ready # 编译规则直接依赖sources即可,Make会自动保证sources生成完成才执行编译 object : sources cat sources touch object # 清理规则可选 .PHONY: clean clean: rm -f config dep1 sources gen_ready object
实现说明
- 用GNU Make 4.3+支持的分组目标(&:) 声明
sources和gen_ready由同一个配方生成,多线程下Make会等待整个配方执行完成,才会调度依赖sources的后续任务,不会出现调度错位。 $?可以正常拿到所有本次更新过的依赖列表,不会出现列表不全的问题,因为所有dep的更新都会在gen_ready规则执行前完成。- 规则声明完全匹配实际产出,Make的原生依赖调度就可以正常工作,不需要额外的重扫描逻辑。
内容的提问来源于stack exchange,提问作者vjalle
相关产品推荐
相关产品推荐

