makefile 出现参数列表太长错误

tee*_*v42 4 make posix arguments

在 makefile 中,我有

@echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
Run Code Online (Sandbox Code Playgroud)

问题是它$(CLEAN_FILES)很大,所以当我运行 make 时,我得到

make: execvp: /bin/sh: Argument list too long
Run Code Online (Sandbox Code Playgroud)

我使用的是 Xubuntu 18.10。

编辑:我应该提供更多背景信息。我正在研究的是一个 make 规则(我正在使用 GNU make)来自动生成文件.hgignore。这是完整的 make 规则:

.hgignore : .hgignore_extra
    @echo "Making $@"
    @rm -f $@
    @echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
    @tail -n +2 $< >> $@
    @echo "" >> $@
    @echo "# The following files come from the Makefile." >> $@
    @echo "syntax: glob" >> $@
    @echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
    @chmod a-w $@
.PHONY : .hgignore
Run Code Online (Sandbox Code Playgroud)

编辑2:根据@mosvy的建议,我也尝试过

.hgignore : .hgignore_extra
    @echo "Making $@"
    @rm -f $@
    @echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
    @tail -n +2 $< >> $@
    @echo "" >> $@
    @echo "# The following files come from the Makefile." >> $@
    @echo "syntax: glob" >> $@
    $(file >$@) $(foreach V,$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES),$(file >>$@,$V))
    @true
    @chmod a-w $@
.PHONY : .hgignore
Run Code Online (Sandbox Code Playgroud)

运行make .hgignore此命令后,我不再收到“参数列表太长”错误,但生成的 .hgignore 文件仅包含该行之前的输出syntax: glob,之后不包含任何内容。

小智 7

正如 @schily 已经解释的那样,这不是 shell 问题,不能使用xargs、引用、分割成更多 echo 等;来解决。 make 操作中的所有文本都作为参数传递给单个execve(2),并且它不能长于操作系统允许的最大大小。

如果您使用 GNU make(Linux 上的默认设置),您可以使用它的fileforeach函数:

TEST = $(shell yes foobar | sed 200000q)

/tmp/junk:
        $(file >$@) $(foreach V,$(TEST),$(file >>$@,$V))
        @true

.PHONY: /tmp/junk
Run Code Online (Sandbox Code Playgroud)

这会将所有由$(TEST)换行符分隔的单词打印到名为 的文件中$@。它基于 make手册中的类似示例。

你的 Makefile 可能会被重新设计成更易于管理的东西,不需要花哨的 GNU 功能,但很难从你发布的代码片段中看出如何做。

更新:

对于问题的确切片段,可以这样做:

.hgignore : .hgignore_extra
    $(info Making $@)
    $(file >$@.new)
    $(file >>$@.new,# Automatically generated by Make. Edit .hgignore_extra instead.)
    $(shell tail -n 2 $< >>$@.new)
    $(file >>$@.new,)
    $(file >>$@.new,# The following files come from the Makefile.)
    $(file >>$@.new,syntax: glob)
    $(foreach L, $(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES), $(file >>$@.new,$L))
    @mv -f $@.new $@
    @chmod a-w $@
.PHONY : .hgignore
Run Code Online (Sandbox Code Playgroud)

我对其进行了一些更改,因此它首先写入.hgignore.new,如果一切顺利,然后才转移.hgignore.new.hgignore。您必须将缩进空格改回制表符,因为这个愚蠢的界面正在破坏空格。