2015-04-15 75 views
1

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

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

但是$ {deps}可能很大,并且生成的命令行对于一个SHELL调用可能太大。是否可以用换行符'\ n'替换​​3210?

+0

我假设你的真实目标比loop中的echo更复杂?因为没有理由在这个例子中使用'foreach'。你可以直接'echo $ ^'。 –

+1

@EtanReisner,不会把所有东西都放在一条线上吗? –

+1

@JonathanWakely啊,真的,'printf'%s \ n'那么。 –

回答

1

您可以定义扩展到一个新行,像这样的变量:

define NEWLINE 

endef 

现在你可以使用$(NEWLINE)拓展到一个新行。

虽然这不会改变任何东西,但foreach仍然会在语句之间生成一个带有嵌入换行符的单个命令,而不是在语句之​​间带有;的单个命令。

+0

这是否会在配方中创建多条作为多个shell命令运行的行? –

+0

我不知道,但后来我不确定OP所担心的问题是否真的值得关注。 –

+1

这取决于真正的目标是什么,而不是'echo',如果它是一个大的命令行,并且'DEPS'中的列表真的是**巨大**它可能超过单个命令行的长度限制this办法。 –

0

替换';'通过回车将产生一个相同大小的字符串,并受同样的问题影响。

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

my.list : ${deps} 
    rm -f [email protected] 
    (for F in $^; do echo $$F >> [email protected] ; done) 
+1

为什么使用()启动子shell?这仍然会创建一个包含所有'deps'列表的单个shell命令,尽管至少它不会重复每个项目的命令 –

+0

请参阅Etan Reisner的评论“如果它是一个大的命令行和DEPS中的列表真的是巨大的,可能超过这种方式的单个命令行的长度限制“ – Pierre

+0

如果命令是限制因素而不是”DEPS“本身的内容,这有助于(限制子shell位)。 –

1

正如乔纳森Wakely的答案已经提到的,直截了当的答案是

define newline 


endef 

有趣的是,对于除换行符的所有字符还有一个更简单的方式来获得非打印字符与一些帮助变量从外壳,例如:

tab := $(shell printf '\011') 

但它不会在这里工作,因为内置shell函数用空格替换所有换行符。

尽管上述版本仍然有点脆弱,特别是与automake结合时,它会默默地从输入文件中删除第二个连续的换行符,将newline变成一个空变量。迫使它保持换行符,我们可以延长段:

blank := 
define newline 

$(blank) 
endef 

最后,每个依存性真正得到一个单独的shell命令,您需要通过eval运行生成的字符串:

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

endef 

$(eval $(call generate-rule,$(deps))) 
0

编辑 - 经过一些修改后,它看起来像我的原始唯一的问题不是由于空白,但与MAKE_O。我已经在我的版本中修复了它,但我将主要在下面删除它们。

顺便说一下,原来的文章是写的,我不知道我的解决方案是否相关。但是,我发现自己已经在foreachdefine的中间,并且无法弄清楚如何使用给定的任何其他答案插入换行符。

解决方案:

define BR 
$(1) 

endef 

define MAKE_O 
$(1): $(wildcard $(1:obj/%.o=src/%.cpp)); \ 
     $(CXX) ... -c $$< \$(call BR)-o $1 ... \ 
       \$(call BR)&& touch [email protected] 
endef 
$(foreach N,main.o,$(eval $(call MAKE_O,$(N)))) 

希望的输出(编译从auto-dependency generation截断,因此touch):

> make obj/main.o 
g++ ... -c src/main.cpp \ 
-o obj/main.o ... \ 
&& touch obj/main.o 

我改变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 [email protected] 
endef 
$(foreach N,main.o,$(eval $(call MAKE_O,$(N)))) 

的标记会不由自主地证明这一点,但BR 2号线是$(1:%=_space_)_tab_(注释本身是不允许的。)结果:

> make -n obj/main.o 
g++ obj/main.o -c \ 
     -o obj/main.o && \ 
     echo statement on new line 

我用$(call BR,\)使换行不解析为逃生新的生产线,并$(1:%=空间)标签,这样的标签是被迫(许多类似的规则已经确定,像SPACE:=$(SPACE) $(SPACE)没有事先值。)空白的变量左边的值必须为东西。需要明确的是,前后调用后删除空格:...lastword$(call BR,\)firstword...产量...lastword\n\tfirstword...,或写出来,

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

... ...产量

[^]...lastword \[$] 
[^]  firstword...[$] 

达到相同的(使用^, $来表示该行的开始和结束,其他人可能会知道如何更好地对其进行格式化/注释。)

我的语法高亮显然不符合'转义'括号和尾部空格,但结果是体面的。