Makefile: defining rules and prerequisites in reci

2019-07-13 10:47发布

问题:

I have a setup where the files I want to process with make are dependent on the output of another program. Building the program and all its prerequisites is also a complicated task so I would like to use make for this as well. Now my problem is, that it doesn't seem that one can generate rules and prerequisites in Makefile recipes. Consider the following code:

bar:
    echo target1 target2 target3 > bar

foo: bar
    $(eval BAR := $(shell cat bar))

define FUN
$(1):
    touch a$(1)
endef

ifdef BAR
$(foreach i,$BAR,$(eval $(call FUN,$(i))))
endif

blub: foo $(BAR)

I replaced a big set of complicated recipes that lead to the generation of the list of files I want to have in the end by the bar recipe. In reality, producing the content of bar is very complicated and should be done by a set of Makefile recipes and cannot just be done by (as the above suggests):

BAR:=$(shell echo target1 target2 target3)

I would like to put the foreach loop into the recipe for foo but that fails with prerequisites cannot be defined in recipes which makes sense and is also explained in function define in makefile

But it seems that when I do make blub that at the time when foo eval's BAR to a different value, the prerequisites for blub are not re-evaluated.

So I think ultimately I'm looking for two things:

  • how do I generate recipes dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?

  • how do I update the prerequisites of a target (blub in this case) dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?

Thank you!

EDIT: SOLUTION

With the help of @user657267 the following seems to solve my problem:

.PHONY: all
all: blub

-include bar.make

.PHONY: blub
blub: $(BAR)
    echo $^

bar.make: Makefile
    printf 'BAR=target1 target2 target3\n' > $@
    printf 'target1 target2 target3:\n' >>$@
    printf '\ttouch $$@' >> $@

.PHONY: clean
clean:
    rm -f target1 target2 target3 bar.make

回答1:

Sounds like you should be using make's self-remaking features

-include bar.make

blub: $(BAR)
    @echo $^

bar.make:
    @echo BAR := target1 target2 target3 > $@
    @echo target1 target2 target3: ; touch $$@ >> $@

Obviously the recipes for bar.make are contrived, in the real world they'd probably invoke some kind of script that outputs a valid makefile.