使用sed

时间:2017-05-24 07:08:17

标签: sed makefile

我尝试将foo/bar/baz.proto等文件名转换为Makefile中的foo/bar/Baz.java。为此,我想我可以使用sed。但是,该命令似乎无法按预期工作:

uppercase_file = $(shell echo "$(1)" | sed 's/\(.*\/\)\(.*\)/\1\u\2/')
# generated Java sources
PROTO_JAVA_TARGETS := ${PROTO_SPECS:$(SRCDIR)/%.proto=$(JAVAGEN)/$(call uppercase_file,%).java}

当我尝试在命令行上运行sed命令时,似乎可以工作:

~$ echo "foo/bar/baz" | sed 's/\(.*\/\)\(.*\)/\1\u\2/'
foo/bar/Baz

为什么这在Makefile中不起作用?

更新:

使用以下目标生成java文件: $(JAVAGEN)/%.java: $(SRCDIR)/%.proto

如何将替换应用于目标?

1 个答案:

答案 0 :(得分:1)

GNU Make不会替换substitution reference的替换部分中的%字符(这基本上是patsubst的语法糖),如果它是变量引用的一部分。我没有发现文档中描述的这种行为,但你可以看一下它在源代码中实现(相信函数我认为是find_char_unquote)。

我建议将调用移出替换引用,因为uppercase_file显然可以在任何文件路径上正常运行:

PROTO_JAVA_TARGETS := $(call uppercase_file,${PROTO_SPECS:$(SRCDIR)/%.proto=$(JAVAGEN)/%.java})

如果$(PROTO_SPECS)不解析为单个元素,而是解析为元素列表,则可以使用foreach在已处理列表的每个元素上调用该函数:

PROTO_JAVA_TARGETS := $(foreach JAVA,${PROTO_SPECS:$(SRCDIR)/%.proto=$(JAVAGEN)/%.java},$(call uppercase_file,$(JAVA)))
  

使用以下目标生成java文件:$(JAVAGEN)/%.java: $(SRCDIR)/%.proto

     

如何将替换应用于目标?

由于Make首先匹配目标,并且无法向后运行sed,因此您需要定义反函数或生成多个显式规则。我将展示后一种方法。

define java_from_proto
$(call uppercase_file,$(1:$(SRCDIR)/%.proto=$(JAVAGEN)/%.java)): $1
    # Whatever recipe you use.
    # Use `$$@`, `$$<` and so on instead of `$@` or `$<`.
endef

$(foreach PROTO,$(PROTO_SPECS),$(eval $(call java_from_proto,$(PROTO))))

我们基本上使用multiline variable语法在$(PROTO_SPEC)中为每个文件生成一个规则,然后使用eval来安装该规则。 <{3}}上还有一个非常相似的例子可以提供帮助。