Makefile中for循环无法正常运行问题排查及可移植写法咨询
问题原因分析
这个问题我之前排查过类似的,其实根源不在GNU Make的版本差异,而是Debian系统默认shell的变更导致的:
- 在Debian旧稳定版(比如Jessie)中,
/bin/sh是直接链接到bash的,bash支持自己特有的大括号扩展语法(也就是{20..50000..10}这种生成序列的写法)。 - 而Debian稳定版(比如Stretch及之后)把
/bin/sh默认指向了dash——这是一个轻量的POSIX兼容shell,它不支持bash的大括号扩展特性。 - GNU Make默认会调用系统的
/bin/sh来执行规则里的shell命令,所以在新系统里,dash不认识{20..50000..10},就直接把它当成普通字符串输出了。你提到的Make 4.0 vs 4.1只是刚好和Debian版本升级同步,并不是直接原因。
可移植的实现方式
下面几种方法都能让你的循环在不同Debian版本(或其他POSIX系统)下正常工作:
1. 强制Make使用bash执行命令
在Makefile的最开头加上这一行,指定Make用bash来处理shell命令,这样大括号扩展就能正常生效:
SHELL := /bin/bash
注意:这个方案要求目标系统必须安装bash(Debian系一般都自带,但极简系统或部分小众发行版可能需要提前安装)。
2. 使用POSIX兼容的seq命令
如果想要完全兼容所有POSIX shell,就用seq命令生成序列,替换bash特有的大括号扩展:
all: for i in $$(seq 20 10 50000); do \ echo "Computing $$i"; \ done
seq的语法是seq 起始值 步长 结束值,所有POSIX兼容系统都支持这个命令,完全不用担心shell兼容性问题。
3. 用Make自身的循环逻辑(脱离shell)
如果不想依赖shell的循环特性,也可以用Make内置的foreach函数实现,完全由Make控制流程:
# 先生成数字序列 NUMBERS := $(shell seq 20 10 50000) all: $(foreach i,$(NUMBERS),echo "Computing $(i)";)
这种方式的好处是不依赖任何shell特性,完全由Make处理,但要注意:所有echo命令会被展开成一行执行,如果你的循环里有更复杂的逻辑(比如需要每条命令单独执行、有依赖关系),可能需要调整写法。
内容的提问来源于stack exchange,提问作者kyticka
相关产品推荐
相关产品推荐

