foreachmakefilemacrosinfo

Synchronize printing within Makefile foreach


I have the following example:

LIST_JOB = job1 job2 job3

define macro
$(info "JOB: $(1)")
job_$(1): job.f90
   ifort -c job.f90
   $(shell touch job.f90)
endef

all: rule

rule: $(foreach job,$(LIST_JOB), job_$(job))

$(foreach job,$(LIST_JOB), \
   $(eval $(call macro,$(job))) \
)

which prints the $(info "JOB: $(1)") lines first and after that the compilation commands:

"JOB: job1"
"JOB: job2"
"JOB: job3"
ifort -c job.f90
ifort -c job.f90
ifort -c job.f90

Is there any way to print the header lines right before the compilation (of course, while keeping the macro and the foreach loop)? This would mean the following order:

"JOB: job1"
ifort -c job.f90
"JOB: job2"
ifort -c job.f90
"JOB: job3"
ifort -c job.f90

Solution

  • Your problem comes from when make does thinks (parsing vs. calling recipes). Note that the recipes are shell commands (whatever the shell is), no need to call make function shell in a recipe. Try the following:

    LIST_JOB = job1 job2 job3
    
    define macro
    job_$(1): job.f90
        @echo 'JOB: $(1)'
        ifort -c job.f90
        touch job.f90
    endef
    
    all: rule
    
    rule: $(addprefix job_,$(LIST_JOB))
    
    $(foreach job,$(LIST_JOB),$(eval $(call macro,$(job))))
    

    Note: you could use $$(info JOB: $(1)) instead of echo 'JOB: $(1)'. It would be expanded as $(info JOB: job_jobN) during the parsing (this is a consequence of using foreach-eval-call: eval expands its parameter). And this would just be another recipe for this rule. As any recipe, when the rule is fired, it would be expanded, producing the expected output at the expected time, just before the result of the expansion is passed to the shell. And as info expands as an empty string nothing would be passed to the shell for it.