2

Makefile

abc:
TEST=$@ /* TEST=abc */

def:
TEST=$@ /* TEST=def */

xxx:
        @echo $(TEST)

If I run make abc xxx, I expect output abc.

If I run make def xxx, I expect output def.

But it doesn't work like that. It seems like make won't let me define a variable in target. My question is how could I define a variable and its value which depend on which target is built?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user1932637
  • 183
  • 2
  • 12
  • possible duplicate of [Passing arguments to "make run"](http://stackoverflow.com/questions/2214575/passing-arguments-to-make-run) – Waleed Khan Dec 27 '12 at 18:08
  • As written, the two `TEST` macro assignments are processed as the file is read, and the second 'wins'. Note that the macro includes the C comment; when I run `make abc xxx`, the output starts with xxx, includes all the names in my root directory, `TEST=def` and `*/`. When you're building `abc`, there is no command to be executed. Ditto `def`. When you build `xxx`, the value of `$@` is `xxx`. You can't easily make `xxx` output a value that depends on what else was built earlier in the same run of `make`. – Jonathan Leffler Dec 27 '12 at 18:14
  • @WaleedKhan: the suggested duplicate question seems to be very different from what this is asking about (if I understand what this is asking about). – Jonathan Leffler Dec 27 '12 at 18:16
  • Thanks Jonathan, I'm sorry I forgot mention to remove c comments. you are right. but how could make define a variable depends on target? I hope TEST is processed when target is build, rather than file is read. – user1932637 Dec 27 '12 at 18:39

1 Answers1

5

Using GNU Make, you can duplicate the intended result of your Makefile as follows:

echo.%:
    @echo $*

or simply:

%:
    @echo $*

These would allow you to specify make echo.abc or make abc, respectively, and see abc as output.

That's all well and good, but it sounds like you would be more interested in target-specific variables. If the variable value is dependent on, but not a substring of, the target name, you can do something like this:

%:
    @echo $(TEST)

abc: TEST=xyzzy

def: TEST=plugh

This allows you to specify make abc and see xyzzy as output.


If you want to go beyond this, so that the behavior of a target changes based on what other targets are specified on the command line, we have two options: either have .PHONY targets that update a file used by your primary target, or do some processing of the MAKECMDGOALS variable:

Option 1:

xxx: xxx.temp
    @cat xxx.temp
    @rm xxx.temp

abc def:
    @echo $@ > xxx.temp

.PHONY: xxx abc def

This relies on the fact that the command line goals are processed in order (If you specify several goals, make processes each of them in turn, in the order you name them. -GNU Make Manual, section 9.2), so you must specify make abc xxx and not make xxx abc.

Option 2:

ifneq (,$(findstring abc,$(MAKECMDGOALS)))
    VAR=abc
else ifneq (,$(findstring def,$(MAKECMDGOALS)))
    VAR=def
endif

xxx:
    @echo $(VAR)

abc def:
    @echo -n > /dev/null

.PHONY: xxx abc def

The @echo -n > /dev/null suppresses the make: Nothing to be done for 'abc'. message. This seems much clumsier to me, and I would recommend Option 1 if you can tolerate the temp file.

laindir
  • 1,650
  • 1
  • 14
  • 19
  • Thank you laindir. I'm getting closer. – user1932637 Dec 27 '12 at 20:47
  • foo: @echo $(TEST) abc: TEST=xxx def: TEST=yyy – user1932637 Dec 27 '12 at 20:48
  • foo: @echo $(TEST) abc: TEST=xxx def: TEST=yyy make abc foo expect see xxx, but won't. how to let foo target see abc:TEST? – user1932637 Dec 27 '12 at 20:56
  • Target-specific variables are only in scope while the rule for the corresponding target is being run (i.e., it's in scope for the `abc` rule, but not for the `foo` rule. If you want the actions of one target to depend on what other targets are being built, you'll need to either modify a file (I'll see if I can edit with an example of that), or do some checking of `$(MAKECMDGOALS)` like in [this answer](http://stackoverflow.com/a/14061796/1257631) – laindir Dec 28 '12 at 15:05