3
votes

Given a makefile, with a target-specific defintion:

# A target-specific definition for both: 'all' and 'x'.
all : foo += target
x   : foo += target


all : x ;

x ::
    @echo '$(foo)'


Running, I get:

# override Makefile-level variables, with a command-line definition.
$ make foo=cmd
cmd



Now, the same makefile, as above, but with a pattern-specific defintion:

# A pattern-specific definition that matches both targets: 'all' and 'x'.
% : foo += target


all : x ;

x ::
    @echo '$(foo)'


Running, I get:

# override Makefile-level variables, with a command-line definition.
$ make foo=cmd
cmd cmd cmd

Now, both makefiles are almost identical, except that:

  • For version 1 of Makefile: (With target-specific definition), we had:
    all : foo += target
    x : foo += target
  • For version 2 of Makefile (With pattern-specific definition), we had:
    % : foo += target

In both cases, we had basically the same configuration:

  1. A pattern/target definition that appends to a previous value.
  2. The pattern/target definition applies both to all and x targets.
  3. We had a command-line definition that is suppose to override the makefile-level definition.

Now, interpreting or implementing that override, Make uses a very different methodology, for version 1 (target definition) than version 2 (pattern definition).

Let's see:

  • For target definition, Make completely ignores ANY value defined in the makefile. Hence, the final value is: cmd.
  • For pattern definition, however, Make comes up with "conciliatory" approach, trying to satisfy both, the makefile-level definition and the command-line defintion, so it:
    1. Accepts that the final value is cmd, per the command-line that overrides the makefile definition.
    2. But, because the makefile implies that the "patterns" are supposed to "append" additional values - never mind that those same values had been overridden - Make will still "obey" those appends, but it will done with different values (i.e. the "winning" command-line value), thereby reaching a "compromise" where nor does the makefile, or the command-line have sole control over the final value of the variable.

Well, these different approaches that Make takes to implement a command-line override, (per pattern vs target specific variables), is even more obvious when we expect the very different final results we get for them, respectively:

  1. cmd (for target-specific).
  2. cmd cmd cmd (for pattern-specific).

Is this justified? And how so?

1

1 Answers

3
votes

This appears to be a minimal complete example:

%: foo += targ

x:
    @echo $(foo)

Invoked as make foo=cmd (using GNUMake v3.81), this produces

cmd cmd

This looks like a bug to me. According to the manual:

Variables provided on the command line (and in the environment if the ‘-e’ option is in force) will take precedence [over target-specific variables].

So the += statement should have no effect. But apparently if the assignment is in a pattern rule, the command-line value overrules the value which the rule tries to append, but not the act of appending it, so that Make appends $(foo) to itself.