I have the following makefile that has multiple cp
commands to copy directories from source to destination.
process:
cp dir/level/2000/config.json output/2000/config.json
cp dir/level/2001/config.json output/2001/config.json
cp dir/level/2002/config.json output/2002/config.json
stage:
mkdir -p output/2000 output/2001 output/2002
cp dir/common/2000/esc output/2000/esc
cp dir/common/2001/esc output/2001/esc
cp dir/common/2002/esc output/2002/esc
apply: stage process
I want to make the above Makefile more dynamic by introducing a variable list of 2000 2001 2002
and it would then loop over the variable and run the rule every iteration. Something like...
var := 2000 2001 2002
process:
cp dir/level/${var}/config.json output/${var}/config.json
stage:
mkdir -p output/${var}
cp dir/common/${var}/esc output/${var}/esc
apply: stage process
Now if I run make apply
it should recreate the same steps as the first makefile.
I tried using multiple targets as ${var}
and it worked the way I wanted but it can only be used in place of one of the targets, not for both stage
and process
. I did
process:
cp dir/level/2000/config.json output/2000/config.json
cp dir/level/2001/config.json output/2001/config.json
cp dir/level/2002/config.json output/2002/config.json
${var}:
mkdir -p output/$@
cp dir/common/$@/esc output/$@/esc
apply: ${var} process
Now if I run make apply, it will run as I expected but how to use the same multiple targets in place of process
too?
CodePudding user response:
You would use pattern rules most likely:
apply: stage process
var := 2000 2001 2002
process: $(foreach V,$(var),output/$V/config.json)
stage: $(foreach V,$(var),output/$V/esc)
output/%/config.json: dir/level/%/config.json
cp $< $@
output/%/esc : dir/common/%/esc
mkdir -p $(@D)
cp $< $@
CodePudding user response:
The simplest solution is probably to use a shell for
loop in your recipe:
var := 2000 2001 2002
process:
for year in $(var); do \
cp dir/level/$$year/config.json output/$$year/config.json; \
done
Note that within the recipe we need to write $$year
to refer to the
shell variable named year
because a single $
would introduce a
makefile variable reference.
Using just make
syntax, you could do this:
var = 2000 2001 2002
outputs = $(patsubst %,output/%/config.json,$(var))
output/%/config.json: dir/level/%/config.json
echo cp $< $@
all: $(outputs)
This creates a variable outputs
that has the content:
output/2000/config.json output/2001/config.json output/2002/config.json
And then uses a pattern rule to implicitly create recipes for creating those outputs from the corresponding inputs.