Dummy00001
Dummy00001

Reputation: 17420

Multi-line define in GNU make

I'm trying to make sense out of the multi-line define directive of GNU make and I cannot. Example:

define A
1
2
endef
all:
    @echo W=$(word 1,$(A))

Running make produces a result I have expected the least:

W=1
make: 2: Command not found
make: *** [all] Error 127

It appears that part of $(A) has spilled outside the $(word) function.

Is it a bug or intended behavior? If the "spill" is intentional, how does it really works?

P.S. GNU make v3.81 on Linux/x64

Upvotes: 2

Views: 3220

Answers (2)

bobbogo
bobbogo

Reputation: 15483

The thing to remember here is that make stores each recipe as a single recursive variable. At the point that make decides that it must run your recipe, it expands that variable. Make then passes each line in the resulting expansion to a separate shell, stopping if any of those shell executions return an error.

In your example, before running anything make expands @echo W=$(word 1,$(A)).

  1. $(A) becomes 1¶2 (dunno what this looks like on your browser, but I'm using to represent a newline character)
  2. Now, 1¶2 is a single word as far as make is concerned, so $(word 1,1¶2) naturally expands to 1¶2 (can you see where this is going yet?)
  3. This leaves make with the string @echo W=1¶2. Make dutifully passes the first line of this to the shell (without the @ as that is special to make). The shell executes echo W=1.
  4. make executes 2 in a new shell.
  5. The second shell complains that it can't find the command 2.

So, yes, expected behaviour.

[Warning: slight simplification in the above where I gloss over the bit where make is able to elide the shell and invoke the command itself if the string has no shell metacharacters in it]

Upvotes: 4

Etan Reisner
Etan Reisner

Reputation: 80931

The $(word) function is splitting on spaces. Not whitespace, spaces.

There are no spaces in your A macro so nothing gets split.

Add a trailing space on the 1 line or a leading space on the 2 line and you get your expected behaviour.

This is consistent across GNU make 3.81, 3.82, 4.0, and 4.1 in some quick testing here.

The reason you see the "spill" as you called it is because of how the define is expanded. It is expanded literally, newline and all. (Think template expansion.)

So make expands the define into the call to $(word 1,...) then expands that result (the whole define including the newline) into the recipe template and ends up with two lines that it executes as the recipe.

Consider a macro like this:

define somecommands
echo foo
echo bar
echo baz
endef

all:
    $(somecommands)

What would you expect to happen here? How many lines is the body of all? How many shells are run here? What commands are executed? The answer is three lines, three shells and three echo commands.

If the newlines weren't counted then you would effectively run echo foo echo bar echo baz in one command and get foo echo bar echo baz as output instead of the expected (and far more useful) foo, bar, and baz on three different lines.

Upvotes: 2

Related Questions