将makefile(> 131000个字符)变量的内容写入文件?

时间:2011-08-30 17:59:48

标签: makefile

如何在不调用shell命令的情况下将makefile变量的内容写入文件? 问题是变量的内容可能比shell允许的命令长(即长于MAX_ARG_STRLEN(131072)字符)。

特别是在makefile中,我有一个包含要处理的长文件名列表的变量(包括它们对于源外构建的绝对路径)。现在我需要将这些文件名写入(临时)文件,然后我可以将其传递给另一个命令。

到目前为止,我们有一条规则,($COLLATED_FILES是包含路径的变量):

$(outdir)/collated-files.tely: $(COLLATED_FILES)
    $(LYS_TO_TELY) --name=$(outdir)/collated-files.tely --title="$(TITLE)" \
    --author="$(AUTHOR)" $^

如果COLLATED_FILES超过大约130000个字符,则会中断,我们收到错误消息:

make[2]: execvp: /bin/sh: Argument list too long

作为解决方案,我们现在尝试将变量的内容写入文件,并在$(LYS_TO_TELY)命令中使用该文件。不幸的是,我还没有找到一种方法来做到这一点,而无需调用shell。 我的尝试包括:

$(outdir)/collated-files.list: $(COLLATED_FILES)
    echo "" > $@
    $(foreach f,$^,echo $f >> $@;)

但是这也会在shell中同时调用所有echo命令,因此shell命令也一样长。

有没有办法将$(COLLATED_FILES)的内容写入磁盘上的文件而不将它们在命令行上传递给shell命令?

我还搜索了我是否可以将变量的内容传递给shell,但是我找不到任何方向,或者......

4 个答案:

答案 0 :(得分:5)

假设您使用的是GNU Make,则有file函数!

https://www.gnu.org/software/make/manual/html_node/File-Function.html

$(file op filename,text)

其中op>>>

这需要GNU Make 4.0 +

答案 1 :(得分:2)

您可以将用于构建COLLATED_FILES值的任何makefile代码移动到一个简单的帮助器makefile,然后从原始makefile中递归调用make并使用普通的shell重定向来捕获递归make调用的stdout - 在这种情况下,基本上使用make作为基本的文本处理工具。例如,使用以下内容创建名为get_collated_files.mk的makefile:

COLLATED_FILES=abc
COLLATED_FILES+=def
COLLATED_FILES+=ghi
# ... etc ...

# Use $(info) to print the list to stdout.  If you want each filename on a 
# separate line, use this instead:
#
# $(foreach name,$(COLLATED_FILES),$(info $(name)))

$(info $(COLLATED_FILES))

all: ;@#shell no-op to quell make complaints

然后,在原始的makefile中:

collated-files.list:
        $(MAKE) -f get_collated_files.mk > $@

$(outdir)/collated-files.tely: collated-files.list
    $(LYS_TO_TELY) --name=$(outdir)/collated-files.tely --title="$(TITLE)" \
    --author="$(AUTHOR)" --filelist=collated-files.list

这比使用数百或数千个单独的echo调用一次附加到文件一个路径上效率要高得多。

编辑:最后一个选项,如果您真的希望将每个文件名放在一个单独的行上,并且您可以对COLLATED_FILES的定义方式进行大量控制:

define NL


endef
COLLATED_FILES=abc
COLLATED_FILES+=$(NL)def
COLLATED_FILES+=$(NL)ghi
$(info $(COLLATED_FILES))
all: ;@#no-op

这种方法允许您再次使用$(info)的一次调用,如果由于某种原因这对您很重要。

答案 2 :(得分:2)

这是gnu make的补丁,可让您直接将变量写入文件。它创建了一个新的'writefile'函数,类似于现有的'info'函数,除了它接受一个文件名参数并写入文件:

https://savannah.gnu.org/bugs/?35384

答案 3 :(得分:1)

在我看来,你好像应该重新思考你的构建设计 - 当然,有一个更好的方法,就是让变量变大。但这是一种方法:

# Make sure this doesn't collide with any of your other targets.    
NAMES_TO_WRITE = $(addprefix write_,$(COLLATED_FILES)) 

collated-files.list: $(NAMES_TO_WRITE)

write_blank:
        echo "" > collated-files.list

.PHONY: $(NAMES_TO_WRITE)
$(NAMES_TO_WRITE) : write_% : write_blank
        echo $* >> collated-files.list