GNU Makefile遍历列表异常:首项为空且末项被跳过
Makefile foreach循环首次迭代传空值、最后一个元素未处理的问题解决
问题现象
编写的Makefile通过foreach遍历列表元素并传递给函数时,首次迭代出现空值,最后一个元素从未被处理。执行make -f loop.mak后输出显示:
- 第一次
$(info)打印空的BENCHMARK和COMPILER - 仅处理了前3个元素,
bench_4从未出现在---- BENCHMARK:的输出中
问题原因
核心问题在于变量展开时机和延迟赋值的副作用:
GENERATE_TARGET中使用BENCHMARK=$(1)这种延迟赋值(=),变量不会立即展开,而是在后续被引用时才会解析。foreach循环中,$(eval)执行时,$(info)会先尝试展开$(BENCHMARK)和$(COMPILER),但此时这些变量的赋值还未生效,或者被循环的下一次迭代覆盖,导致输出错位。- 循环最后一次迭代的
$(eval)生成的目标,因为没有后续迭代触发$(info)输出,所以看不到对应的打印。
修复方案
修改GENERATE_TARGET的变量赋值方式为立即展开(:=),并调整$(info)的位置,确保在变量赋值后立即展开:
ALL_BENCHMARKS=bench_1 bench_2 bench_3 bench_4 define GENERATE_TARGET BENCHMARK:=$(1) COMPILER:=$(2) $(info ---- BENCHMARK: $(BENCHMARK) COMPILER: $(COMPILER)) ./$(BENCHMARK)$(COMPILER).file: @echo "Building $$@" endef $(foreach benchmark, $(ALL_BENCHMARKS), \ $(info loop: $(benchmark)) \ $(eval $(call GENERATE_TARGET,$(benchmark),.llvm)) \ ) default: @echo "default"
执行验证
运行make -f loop.mak后,输出将符合预期:
$ make -f loop.mak loop: bench_1 ---- BENCHMARK: bench_1 COMPILER: .llvm loop: bench_2 ---- BENCHMARK: bench_2 COMPILER: .llvm loop: bench_3 ---- BENCHMARK: bench_3 COMPILER: .llvm loop: bench_4 ---- BENCHMARK: bench_4 COMPILER: .llvm default
关键说明
- 使用
:=(立即赋值)替代=(延迟赋值),确保BENCHMARK和COMPILER在GENERATE_TARGET被调用时就完成赋值,避免后续展开时的变量覆盖问题。 - 将
$(info)放在目标定义之前,确保在eval执行时立即打印当前迭代的正确变量值,不会被下一次迭代干扰。
内容的提问来源于stack exchange,提问作者CONts
相关产品推荐
相关产品推荐

