如何解决Makefile规则中的‘argument list too long’报错?
Makefile 解决"execvp: /bin/sh: Argument list too long"错误
问题背景
使用Makefile 3.82版本控制工作流依赖,当前规则触发make: execvp: /bin/sh: Argument list too long错误。核心逻辑是:当所有前置文件对应的.done标记文件都存在时,合并所有前置文件。
原规则代码:
contains=$(foreach v,$2,$(if $(findstring $1,$v),$v,)) .SECONDEXPANSION: %.merged: $$(call contains,_$$*_,$$(STEP1s)) if (for x in $^; do [ -f $$x.done ] || exit; done); then \ for f in $^; do cat $$f; echo; done > $@; fi
补充:仅执行for x in $^;do echo $$x;done时不会触发报错。
可行解决方案
方案1:通过临时文件传递依赖列表
将过长的依赖列表写入临时文件,通过while read循环读取文件内容,避免命令行参数堆积过长。修改后的规则:
contains=$(foreach v,$2,$(if $(findstring $1,$v),$v,)) .SECONDEXPANSION: %.merged: $$(call contains,_$$*_,$$(STEP1s)) echo "$^" > $@.tmp.list; \ if (while read -r x; do [ -f "$$x.done" ] || exit 1; done < $@.tmp.list); then \ while read -r f; do cat "$$f"; echo; done < $@.tmp.list > $@; fi; \ rm -f $@.tmp.list
- 优点:完全规避命令行参数长度限制,兼容所有系统;
- 注意:添加
-r参数避免文件名中的反斜杠被转义,用引号包裹变量防止含空格的文件名出错。
方案2:用xargs分批处理参数
借助xargs将过长的依赖列表分批传递给shell命令,减少单条命令的参数长度:
contains=$(foreach v,$2,$(if $(findstring $1,$v),$v,)) .SECONDEXPANSION: %.merged: $$(call contains,_$$*_,$$(STEP1s)) echo "$^" | xargs -n1 sh -c '[ -f "$0.done" ]' && \ echo "$^" | xargs cat | sed '$!s/$/\n/' > $@
- 说明:
xargs -n1逐个检查每个依赖的.done文件是否存在;xargs cat分批合并文件,sed '$!s/$/\n/'为除最后一个文件外的内容添加换行,替代原规则中的echo;
- 优点:无需临时文件,代码更简洁;
- 注意:若文件名含空格或特殊字符,需确保
echo "$^"的输出能被xargs正确解析(可添加-d'\n'参数指定换行符分隔,部分系统支持)。
报错原因
原规则中$^展开后包含大量依赖文件,导致整个shell命令的参数总长度超过系统允许的上限(由ARG_MAX控制)。仅执行echo时未触发报错,是因为部分shell对echo命令的参数处理有优化,或echo本身的参数长度限制更高,但cat命令在处理大量文件参数时直接触发了限制。
内容的提问来源于stack exchange,提问作者nos
相关产品推荐
相关产品推荐

