Hauton Tsang
Hauton Tsang

Reputation: 13

Makefile appending to variable for previous dependencies

I have a command foo that accepts a list of parameters. I want to alter the parameters I pass to foo depending on the target I am building. I have tried appending to target-specific variables, but that doesn't quite do what I want...

So, for example take this Makefile (which doesn't work since foo is built by target1):

all: target1 target2

foo:
    echo foo $(foo_args)

target1: foo_args += abc
target1: foo
    echo Target1
target2: foo_args += def
target2: foo
    echo Target2

.PHONY: foo target1 target2

What happens:

> make all
foo abc
target1
target2

> make target1
foo abc
target1

> make target2
foo def
target2

What I want:

> make all
foo abc def
target1
target2

> make target1
foo abc
target1

> make target2
foo def
target2

Makefile syntax can be specific to GNU make. I'd also like to keep the parallelism so that target1 and target2 can be built in parallel.

Upvotes: 1

Views: 815

Answers (3)

Alexey Semenyuk
Alexey Semenyuk

Reputation: 704

Scalable variant of John's answer:

define add_target
foo_args_all += $2
foo_args_$(strip $1) := $2
$1: foo; @echo $$@
foo_targets += $1
endef

all:
$(eval $(call add_target, target1, abc))
$(eval $(call add_target, target2, def))

all: $(foo_targets)
foo:; @echo foo $(sort $(foreach g,$(or $(MAKECMDGOALS), all),$(foo_args_$g)))

.PHONY: all $(foo_targets)

Output:

$ make  -f sample.gmk
foo abc def
target1
target2

$ make  -f sample.gmk all
foo abc def
target1
target2

$ make  -f sample.gmk target1
foo abc
target1

$ make  -f sample.gmk target2
foo def
target2

$ make  -f sample.gmk target2 target1
foo abc def
target2
target1

$ make  -f sample.gmk target1 target2
foo abc def
target1
target2

Upvotes: 1

blackghost
blackghost

Reputation: 1825

The problem with making target-specific variables is that they are only available in the scope of that target. In particular, if you were building a target with multiple dependencies, you would only go down one dependency at a time, and foo_args would only reflect the targets on the side of the tree you happen to be invoking foo from.

Another solution might be to use something like the following at the top of your makefile:

foo_args_target1 := abc
foo_args_target2 := def
foo_args_all := abc def
foo_args := $(sort $(foreach goal,$(MAKECMDGOALS),$(foo_args_$(goal))))
$(info foo_args is $(foo_args))

This has the advantage that foo_args is available globaly. This still has a scalability issue though -- if you were to create a new target all2 : target1 target2, then you would have to add a foo_args_all2 := ... into the makefile (you couldn't automatically detect that all2 was dependent on target1 or target2, and update foo_args automatically).

Upvotes: 0

user657267
user657267

Reputation: 21000

Your example is missing a number of details and there may be a better way of handing things (e.g. why are the targets PHONY? How does foo depend on target1?), a complete example that shows exactly how the files are generated will get you a better answer.

That said, something like the following should work in this case

.PHONY: all foo target1 target2

all: foo_args += abc def
all: target1 target2

target1: foo_args += abc
target1: foo
    @echo Target1

target2: foo_args += def
target2: foo
    @echo Target2

foo:
    @echo foo $(sort $(foo_args))

Upvotes: 0

Related Questions