在Makefile$(foreach)循环中插入新行

在Makefile$(foreach)循环中插入新行,makefile,newline,Makefile,Newline,我正在编译Makefile中的大量文件列表 my.list : ${deps} rm -f $@ $(foreach F,$^,echo "${F}" >> $@;) 但是${deps}可能很大,并且生成的命令行对于一个SHELL调用来说可能太大。是否可以替换';'通过换行符“\n” 您可以定义一个扩展为换行符的变量,如下所示: define NEWLINE endef 现在,您可以使用$(换行符)展开到换行符 但是这不会改变任何事情,foreach仍然会生成一

我正在编译Makefile中的大量文件列表

my.list : ${deps}
    rm -f $@
    $(foreach F,$^,echo "${F}" >> $@;)

但是${deps}可能很大,并且生成的命令行对于一个SHELL调用来说可能太大。是否可以替换<代码>';'通过换行符“\n”

您可以定义一个扩展为换行符的变量,如下所示:

define NEWLINE

endef
现在,您可以使用
$(换行符)
展开到换行符


但是这不会改变任何事情,
foreach
仍然会生成一个在语句之间嵌入换行符的命令,而不是一个包含
的命令

替换“;”通过一个回车符,将产生一个大小相同的字符串,但会遇到相同的问题

“foreach”只是一个字符串扩展。如果要对每个项执行单独的命令,可以使用for循环

my.list : ${deps}
    rm -f $@
    (for F in $^; do echo $$F >> $@ ; done)

正如Jonathan Wakely的回答中已经提到的,直截了当的答案是

define newline


endef
有趣的是,对于除换行符以外的所有字符,有一种更简单的方法可以在shell的帮助下将不可打印的字符转换为变量,例如:

tab := $(shell printf '\011')
但是,它在这里不起作用,因为内置shell函数用空格替换所有换行符

上面的版本仍然有点脆弱,特别是当与automake结合时,它将从输入文件中无声地删除第二个连续换行符,将
换行符
变成一个空变量。要强制它保留换行符,我们可以扩展代码段:

blank :=
define newline

$(blank)
endef
最后,要为每个依赖项实际获取单独的shell命令,需要通过
eval
运行生成的字符串:

define generate-rule =
my.list : $(1)
    rm -f $$@
    $(foreach F,$$^,$(newline)$(tab)echo "${F}" >> $@)

endef

$(eval $(call generate-rule,$(deps)))
编辑——经过一些修改后,看起来我的原稿唯一的问题不是因为空格,而是因为
MAKE\O
。我已经在我的版本中修复了它,但我将主要在下面删除它们

顺便说一下,我不确定我的解决方案是否相关。但是,我发现自己已经在<代码>中定义了已经在<代码>前缀中,并且无法找到如何使用给定的任何其他答案插入换行符。 解决方案:

define BR
$(1)

endef

define MAKE_O
$(1): $(wildcard $(1:obj/%.o=src/%.cpp)); \
        $(CXX) ... -c $$< \$(call BR)-o $1 ... \
                \$(call BR)&& touch $$@
endef
$(foreach N,main.o,$(eval $(call MAKE_O,$(N))))
我更改了
BR
以执行缩进,但将行尾留给您:

define BR
$(1)
$(1:%= )        #<remove this comment
endef
define MAKE_O
$(1): $(wildcard $(1:obj/%.o=src/%.cpp)); \
        $(CXX) ... -c $$< $(call BR,\)-o $1 ... \
                $(call BR,\)&& touch $$@
endef
$(foreach N,main.o,$(eval $(call MAKE_O,$(N))))
我使用了
$(call BR,\)
,这样新行就不会被解析为新行的转义,而
$(1:%=
space
选项卡则强制使用该选项卡(已经定义了许多类似的规则,比如
space:=$(space)$(space)
,但没有事先的值)。空格左侧的变量必须计算为某个值。为了清楚起见,删除调用前后的空格:
…lastword$(call BR,\)firstword…
会产生
…lastword\n\t firstword…
,或写出

[^]...lastword \[$]
[^]$(call BR,\)firstword...[$]
…产生

[^]...lastword \[$]
[^]        firstword...[$]
为了达到同样的效果(使用^,$表示行的开始和结束。其他人可能会知道如何更好地格式化/注释这一行。)


我的语法highlighter显然对“转义”括号和尾随空格不感兴趣,但结果不错。

最直接的答案可能是使用:

@printf "\n"
您还可以像我通常所做的那样,在每个新make目标执行时使用它来显示描述。例如,目标:

.PHONY: clean-version
clean-version:    ## Reset version back to committed version number
    @printf "\n## Reset version to last committed version number ##\n\n"; \
    $(GIT) checkout $(VERSION_FILE);

我假设你的真实目标比循环中的回声更复杂?因为在这个例子中根本没有理由使用
foreach
。您可以直接
echo$^
。@EtanReisner,这不是把所有内容都放在一行吗?@JonathanWakely啊,没错,那么,`printf'%s\n'。EtanReisner是的,这很复杂:我正在动态生成一个Makefile,我在deps中有10000多个文件。另一种方法是拆分规则:每1000个生成一个规则
${deps}
元素,以及另一个组合结果的规则。这在创建作为多个shell命令运行的多行的方法中是否有效?我不知道,但我不确定OP担心的问题是否是真正的问题。如果是大型命令行,并且在
DEPS
中的ist确实很大,这样可能会超过单个命令行的长度限制。在使用Bash的GNU/Linux上,命令行可以是无限的,所以这可能不是一个真正的问题。在其他平台上,它会是。具有讽刺意味的是,这缺少了新行;)为什么使用()要启动子shell?这仍然会创建一个shell命令,其中包含整个
deps
列表,但至少不会对每个项重复该命令参见Etan Reisner的注释“如果它是一个大的命令行,并且DEPS中的列表确实很大,那么通过这种方式可能会超过单个命令行的长度限制”如果命令是限制因素而不是
DEPS
本身的内容,这会有所帮助(不包括子shell位)哪个首先扩展为一百万字的命令,并且执行时没有问题(bash 4.2.37),Makefile变量受相同的限制?对于L=$(seq 1000000)也是一样的echo$L那么,是否存在真正的限制?
ARG_MAX
限制适用于命令行从一个进程传递到另一个进程的长度,但是如果shell在内部计算参数,这个特定的限制不会影响这一点。
@printf "\n"
.PHONY: clean-version
clean-version:    ## Reset version back to committed version number
    @printf "\n## Reset version to last committed version number ##\n\n"; \
    $(GIT) checkout $(VERSION_FILE);