Is there a way to simplify this sort of repetition in a Makefile?
duo = ./node_modules/.bin/duo
build: lib/background/build lib/page/build lib/popup/build
A good first start would be to stop repeating the targets/etc. in the rule bodies themselves and use the automatic variables for them instead. So '$@'
for the target filename, '$(@D)'
for the directory path (like dirname
) of the target filename, etc.
Which gets you:
duo = ./node_modules/.bin/duo
build: lib/background/build lib/page/build lib/popup/build
lib/background/build: lib/background/build/build.js lib/background/build/build.css
lib/page/build: lib/page/build/build.js lib/page/build/build.css
lib/popup/build: lib/popup/build/build.js lib/popup/build/build.css
lib/background/build/build.js: lib/background/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) lib/background/index.js > '$@'
lib/page/build/build.js: lib/page/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) lib/page/index.js > '$@'
lib/popup/build/build.js: lib/popup/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) lib/popup/index.js > '$@'
lib/background/build/build.css: lib/background/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) lib/background/index.css | $(myth) > '$@'
lib/page/build/build.css: lib/page/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) lib/page/index.css | $(myth) > '$@'
lib/popup/build/build.css: lib/popup/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) lib/popup/index.css | $(myth) > '$@'
Then realizing that pattern rules are helpful when you have targets and prerequisites that share filename patterns and similar rule bodies you can start using those too. They also give you an extra automatic variable.
You get this (intermediate) stage:
duo = ./node_modules/.bin/duo
build: lib/background/build lib/page/build lib/popup/build
lib/background/build: lib/background/build/build.js lib/background/build/build.css
lib/page/build: lib/page/build/build.js lib/page/build/build.css
lib/popup/build: lib/popup/build/build.js lib/popup/build/build.css
%/build/build.js: %/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.js > '$@'
%/build/build.js: %/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.js > '$@'
%/build/build.js: %/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.js > '$@'
%/build/build.css: %/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.css | $(myth) > '$@'
%/build/build.css: %/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.css | $(myth) > '$@'
%/build/build.css: %/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.css | $(myth) > '$@'
And them you see that you've really just got two duplicate rules so you combine them.
duo = ./node_modules/.bin/duo
build: lib/background/build lib/page/build lib/popup/build
lib/background/build: lib/background/build/build.js lib/background/build/build.css
lib/page/build: lib/page/build/build.js lib/page/build/build.css
lib/popup/build: lib/popup/build/build.js lib/popup/build/build.css
%/build/build.js: %/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.js > '$@'
%/build/build.css: %/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.css | $(myth) > '$@'
And then, since make doesn't handle directory targets/prerequisites as well as one might like, you can drop the lib/background/build
, lib/page/build
, and lib/popup/build
intermediate targets and just list the actual files as the prereqs for build
.
duo = ./node_modules/.bin/duo
build: lib/background/build/build.js lib/background/build/build.css \
lib/page/build/build.js lib/page/build/build.css \
lib/popup/build/build.js lib/popup/build/build.css
%/build/build.js: %/index.js node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.js > '$@'
%/build/build.css: %/index.css node_modules component.json
@mkdir -p '$(@D)'
@$(duo) '$*'/index.css | $(myth) > '$@'
I should probably mention that I didn't test this (for lack of desire to mock up the directory layout/etc.) but the transformations were straight-forward and the concepts are fairly simple so it should work just fine. But anything is possible.
To clean up the build
prerequisites you could use something like:
build: $(foreach d,background page popup,$(addprefix lib/$d/build/,build.js build.css))