Reputation: 17932
Certain files in my target have dependencies on other targets. I can ensure a proper build by adding explicit rules like this:
static/app.mjs: js2/.legacy_app.built.mjs
static/admin_unit.mjs: js2/.legacy_admin.built.mjs
static/admin_source.mjs: js2/.legacy_admin.built.mjs
static/admin_module.mjs: js2/.legacy_admin.built.mjs
But this means changing my Makefile every time I add a new "admin_X" source to my project. What I would like to do is have a catch-all pattern rule like:
static/app.mjs: js2/.legacy_app.built.mjs
static/admin_%.mjs: js2/.legacy_admin.built.mjs
But this does not work, as explained by https://stackoverflow.com/a/3734705/179583:
Pattern rules with no recipes at all are documented as meaning something quite different [… :] they cancel any pre-existing implicit rule
Is there a clean way to specify that "any target matching a certain pattern" depends on some particular other target?
Upvotes: 2
Views: 1810
Reputation: 17932
I found another trick to do this, under the special case that all relevant files are built via their own particular recipe. I.e. this will not work in the general case, unless you have split out or can duplicate a separate recipe for the targets in question.
Granting that, it's a simple matter of tying in the common dependency via a phony target. This ADMIN
target depends on the shared intermediate file, and then in turn is specified as a prequisite of a pattern-matching recipe:
.PHONY: ADMIN
ADMIN: js2/.legacy_admin.built.mjs
static/admin_%.mjs static/admin_%.mjs.map: js2/admin_%.build.mjs ADMIN FORCE
node_modules/.bin/rollup --config rollup.config.js $< --format esm --sourcemap -o $@
# …also contains recipe to build "js2/.legacy_admin.built.mjs" itself
Now before any static/admin_%.mjs
file is built, make ensures that the common js2/.legacy_admin.built.mjs
helper file has been created.
(See when multiple pattern rules match a target for some background on how various versions of Make pick which recipe to use.)
Upvotes: 0
Reputation: 61610
As you know, a pattern rule like:
static/admin_%.mjs: js2/.legacy_admin.built.mjs
recipe...
does not specify any targets, just a template for discovering the prerequisites of targets that you specify otherwise, with a recipe for making those targets from the prerequisites.
So there has to be something else in your makefile that determines what the targets are. Let's suppose it is just a list as in:
$ cat Makefile
MJS_STEMS := app admin_unit admin_source admin_module
MJS_FILES := $(addprefix static/,$(MJS_STEMS:%=%.mjs))
.PHONY: all clean
all: $(MJS_FILES)
$(MJS_FILES): js2/.legacy_admin.built.mjs
static/%.mjs: | static
@echo $< > $@
@echo "$@ depends on $<"
js2/.legacy_admin.built.mjs: | js2
touch $@
static js2:
mkdir -p $@
clean:
$(RM) $(MJS_FILES) js2/.legacy_admin.built.mjs
Here,
$(MJS_FILES): js2/.legacy_admin.built.mjs
says that each of $(MJS_FILES)
depends on js2/.legacy_admin.built.mjs
.
That's the most concise way to do it without a pattern rule. The make runs like:
$ make
mkdir -p static
mkdir -p js2
touch js2/.legacy_admin.built.mjs
static/app.mjs depends on js2/.legacy_admin.built.mjs
static/admin_unit.mjs depends on js2/.legacy_admin.built.mjs
static/admin_source.mjs depends on js2/.legacy_admin.built.mjs
static/admin_module.mjs depends on js2/.legacy_admin.built.mjs
If you want you can move the maintenance of the MJS_STEMS
list out of the
makefile into another file:
$ cat ./mjs_stems
app
admin_unit
admin_source
admin_module
$ cat Makefile
MJS_STEMS := $(shell cat ./mjs_stems)
MJS_FILES := $(addprefix static/,$(MJS_STEMS:%=%.mjs))
.PHONY: all clean
all: $(MJS_FILES)
$(MJS_FILES): js2/.legacy_admin.built.mjs
static/%.mjs: | static
@echo $< > $@
@echo "$@ depends on $<"
js2/.legacy_admin.built.mjs: | js2
touch $@
static js2:
mkdir -p $@
clean:
$(RM) $(MJS_FILES) js2/.legacy_admin.built.mjs
$ make clean
rm -f static/app.mjs static/admin_unit.mjs static/admin_source.mjs static/admin_module.mjs js2/.legacy_admin.built.mjs
$ echo "admin_foobar" >> mjs_stems
$ make
touch js2/.legacy_admin.built.mjs
static/app.mjs depends on js2/.legacy_admin.built.mjs
static/admin_unit.mjs depends on js2/.legacy_admin.built.mjs
static/admin_source.mjs depends on js2/.legacy_admin.built.mjs
static/admin_module.mjs depends on js2/.legacy_admin.built.mjs
static/admin_foobar.mjs depends on js2/.legacy_admin.built.mjs
Or you can just get the MJS_STEMS
list from the environment:
$ cat Makefile
MJS_STEMS := $(strip $(MJS_STEMS))
MJS_FILES := $(addprefix static/,$(MJS_STEMS:%=%.mjs))
.PHONY: all clean
all: $(MJS_FILES)
$(MJS_FILES): js2/.legacy_admin.built.mjs
static/%.mjs: | static
@echo $< > $@
@echo "$@ depends on $<"
js2/.legacy_admin.built.mjs: | js2
touch $@
static js2:
mkdir -p $@
clean:
$(RM) $(MJS_FILES) js2/.legacy_admin.built.mjs
$ make clean
rm -f static/app.mjs static/admin_unit.mjs static/admin_source.mjs static/admin_module.mjs static/admin_foobar.mjs js2/.legacy_admin.built.mjs
$ export MJS_STEMS=$(cat ./mjs_stems)
$ make
touch js2/.legacy_admin.built.mjs
static/app.mjs depends on js2/.legacy_admin.built.mjs
static/admin_unit.mjs depends on js2/.legacy_admin.built.mjs
static/admin_source.mjs depends on js2/.legacy_admin.built.mjs
static/admin_module.mjs depends on js2/.legacy_admin.built.mjs
static/admin_foobar.mjs depends on js2/.legacy_admin.built.mjs
$ make clean
rm -f static/app.mjs static/admin_unit.mjs static/admin_source.mjs static/admin_module.mjs static/admin_foobar.mjs js2/.legacy_admin.built.mjs
$ export MJS_STEMS="aa bb cc"
$ make
touch js2/.legacy_admin.built.mjs
static/aa.mjs depends on js2/.legacy_admin.built.mjs
static/bb.mjs depends on js2/.legacy_admin.built.mjs
static/cc.mjs depends on js2/.legacy_admin.built.mjs
$ make clean
rm -f static/aa.mjs static/bb.mjs static/cc.mjs js2/.legacy_admin.built.mjs
But one way or another, somewhere, you have to specify the list of targets, and to add new targets you have to update something.
Upvotes: 1
Reputation: 15196
If all those files already exist in the filesystem (i.e. not supposed to be built by make from scratch), you can use $(wildcard ...)
:
$(wildcard static/admin_*.mjs): js2/.legacy_admin.built.mjs
Upvotes: 1