2017-05-24 23 views
1

我嘗試在我的Makefile中將諸如foo/bar/baz.proto之類的文件名轉換爲類似foo/bar/Baz.java的文件。爲此,我想我可以使用sed。然而,似乎如預期的那樣命令不起作用:使用sed在Makefile中使用大寫文件名稱

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中工作?

UPDATE:

文件與下列目標生成的Java: $(JAVAGEN)/%.java: $(SRCDIR)/%.proto

如何申請替代也爲目標?

+0

這是如何幫助我在Makefile? – machinekoder

+0

'$(1)'應該是什麼? (我將它顯示的行放在makefile的全局範圍內,而不是在配方內部或函數定義中)。您需要發佈更多的makefile才能更清晰。 – blackghost

+0

確保Makefile中的shell和sed路徑與沒有的路徑相同。 GNU make也有你可以使用的uc/lc函數。 – stevesliva

回答

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

如何將替代也應用於目標?

由於首先匹配目標,並且無法向後運行sed,您需要的是定義反函數或生成多個顯式規則。我將展示後一種方法。

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

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

我們基本上使用multiline variable語法生成每個文件一個規則$(PROTO_SPEC),然後用eval安裝該規則。 this documentation page也有一個非常類似的例子,可以幫助你。

+0

好主意!但是,'PROTO_SPECS'是一個使用通配符創建的列表:'PROTO_SPECS:= $(通配符$(PROTODIR)/ *。proto)' – machinekoder

+0

現在我需要一種方法在列表中的每個元素上運行sed命令 – machinekoder

+0

@AlexanderRössler是的,就像[foreach](https://www.gnu。org/software/make/manual/make.html#Foreach-Function) – eush77