patsubst有多个通配符

时间:2016-11-30 05:48:31

标签: makefile

我有一个像

这样的目录结构
packages/
  foo/
    lib/
      a.js
      b.js
  bar/
    lib/
      c.js
      d.js

我正在尝试编写一个简单的Makefile来通过编译器运行源文件,并将packages/foo/lib/a.js的结果输出到packages/foo/build/a.js。在过去,我做过像

这样的事情
JS = $(shell find packages/foo/lib -name "*.js")
BUILD = $(patsubst packages/foo/lib/%.js, packages/foo/build/%.js, $(JS))

.PHONY: all
all: $(BUILD)

packages/foo/lib/%.js: packages/foo/build/%.js
  # Compile $^ and output to $@

效果很好。但是,我现在正在做

JS = $(shell find packages/*/lib -name "*.js")
BUILD = $(patsubst ...)

这里的问题是patsubst似乎不喜欢多个%通配符(即packages/%/lib/%.js)。但是,如果我使用packages/%.js,那么我无法知道在替换中使用哪个目录。我确信有一种非常简单的方法可以在make docs中找不到。

1 个答案:

答案 0 :(得分:1)

要定义BUILD,您可以使用愚蠢但简单的解决方案:

BUILD = $(subst /lib/,/build/,$(JS))

只要您不担心源中的其他“lib”和“build”路径名组件。

但是,除非您想为每个目录foobar等手动指定规则,否则这将为您留下如何定义实际Makefile规则的问题。

相反,也许尝试这样的事情(如果你剪切和粘贴,请记得在适当的地方再次用标签替换空格):

PACKAGES = $(wildcard packages/*)

ALL :=

define add_package
JS := $$(shell find $(1)/lib -name "*.js")
BUILD := $$(patsubst $(1)/lib/%.js, $(1)/build/%.js, $$(JS))
$(1)/build/%.js:: $(1)/lib/%.js
        echo COMPILE $$^ '->' $$@
        cp $$^ $$@  # super fast compiler!
ALL += $$(BUILD)
endef

$(foreach p, $(PACKAGES), \
  $(eval $(call add_package,$(p))))

all: $(ALL)

这会为每个包目录评估一个模板,这样你就可以把任何内容放在那里,只要你把美元符号的正确加倍。