Search code examples
shellmakefilerulesrecipe

How to create a multiple recipes by looping over a Makefile list?


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?


Solution

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