如何将GNU makefile文件列表拆分为单独的行

时间:2013-02-07 20:12:48

标签: makefile gnu-make freebsd solaris-10

我有一个包含用字符串_NEWLINE_分隔的文件列表的变量。我需要将该变量输出到一个文件中,以便每个文件都在一个单独的行中。诀窍是它需要在FreeBSD和Solaris上运行。

这就是我现在正在尝试的事情:

echo "lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf" | sed 's|_NEWLINE_|\'$'\n|g'

这适用于FreeBSD和Solaris上的shell。但是当在Solaris上的GNUmakefile中运行时,我得到了这个(在每行的末尾注意$):

lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf$
lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src$
lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf$

如果我从sed中删除\'$',那么它适用于Solaris,但不适用于FreeBSD。也许有一种方法可以告诉使用哪个版本,具体取决于makefile执行的系统?

修改 感谢 bobbogo 提出的解决方案,我创建了一个示例性的makefile,它提供了所需的结果,并且似乎在FreeBSD和Solaris上都有效:

one-line := lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/\
priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/comm\
unity.conf: lib/alarms/priv/snmp_conf/community.conf

many-lines := { echo '$(subst _NEWLINE_,' && echo ',${one-line})'; }

.PHONY: all
all:
  $(shell $(many-lines) > test.txt)

4 个答案:

答案 0 :(得分:1)

尝试了许多不同的解决方案,包括定义此答案中提到的\nAdd a newline in Makefile 'foreach' loop

真正的问题是跨平台的echo命令的实现不一致,以及默认情况下make使用sh调用shell命令的事实,printf本身非常不灵活。

由于这个答案,我找到了一个更好的方法:"echo -e" when called directly and when called via a shell-script

更好的方法是使用echo代替\n

使用_NEWLINE_而不是some_string = lib/alarms-1.2/priv/snmp_conf/target_params.conf: lib/alarms/priv/snmp_conf/target_params.conf\nlib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf\n 构造字符串,以分隔出输出文件中单独行的部分:

@printf "$(some_string)" >> $(some_file)

然后在makefile中打印它就像这样:

{{1}}

适用于FreeBSD和Solaris。

答案 1 :(得分:1)

如果这是GNU make,那么在make中全部完成。

one-line := lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf

define \n


endef

many-lines := $(subst _NEWLINE_,${\n},${one-line})

现在${many-lines}正是您想要的。令人讨厌的是,在shell系列中使用起来相当困难。如果你这样做:

tgt:
    echo '${many-lines}'

make将为每个行调用单独的 shell。第一个shell调用将获得一个未配对的'并退出并显示错误。

.ONESHELL:
tgt:
    echo '${many-lines}'

将以侵入性的方式工作。正确的解决方法是确保${many-lines}的每一行都有有效的sh语法。有点像:

echolines = $(subst ${\n},'${\n}echo ',echo '${many-lines}')
.PHONY: aa
aa:
    $(call echolines,${many-lines})

啧。

答案 2 :(得分:0)

免责声明:我没有使用Solaris或FreeBSD的经验......无论如何都在这里。

在make中,您可以使用$(patsubst模式,替换,文本)来替换模式。 试试这个......

FILENAMES := "lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf"

.PHONY: all

all:
    @echo $(patsubst _NEWLINE_,${\n},$(FILENAMES))

答案 3 :(得分:0)

作为替代方案,我认为你的第一种方法是有效的,如果你只是加倍$来“逃避”它:

sed 's|_NEWLINE_|\'$$'\n|g'