如何在不调用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,但是我找不到任何方向,或者......
答案 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'函数,除了它接受一个文件名参数并写入文件:
答案 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