patsubst with multiple wildcards

I have a directory structure like

packages/
  foo/
    lib/
      a.js
      b.js
  bar/
    lib/
      c.js
      d.js

and I'm trying to write a simple Makefile to run the source files through a compiler and output the result of compiling packages/foo/lib/a.js to packages/foo/build/a.js. In the past, I've done something like

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 $@

which works great. However, I'm now doing

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

The problem here is that patsubst doesn't seem to like multiple % wildcards (ie packages/%/lib/%.js). However, if I use packages/%.js, then I can't know which directory to use in the substitution. I'm convinced there's a very simple way to do this that I can't find in the make docs.

Upvotes: 0

Views: 2080

Answers (1)

K. A. Buhr
K. A. Buhr

Reputation: 51019

To define BUILD, you could use the stupid but simple solution:

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

as long as you aren't worried about additional "lib" and "build" pathname components in your source.

However, this leaves you with the problem of how to define the actual Makefile rules, unless you want to manually specify a rule for each directory foo, bar, etc.

Instead, maybe try something like this (remember to replace spaces with tabs again where appropriate, if you cut and paste):

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)

This evaluates a template for each package directory, so you can put anything in there, as long as you get the fiddly doubling of dollar signs correct.

Upvotes: 1

Related Questions