Variables in GNU Make recipes, is that possible?

Is it possible to have variables in GNU Make recipes?

Something like this doesn't work:

%_t.mkd : %.mkd REV=$$(svn info $<|grep 'Last Changed Rev'|cut -f4 -d\ ) echo $${REV}

Is there some way to make that work at all?

As you can see what I want is to extract the revision that a file was changed and then use that later in the full recipe. Unfortunately I can't use svn:keywords as I need the revision number outside of the document in question.

4 Answers

This doesn't work because the make tool starts a new shell process for each recipe line. And shell variables – even 'exported' environment variables – cannot possibly propagate "upwards"; they're gone as soon as the shell process exits.

  • The traditional method is to join the recipe lines using \ in the Makefile:

    foo: bar baz line1; \ line2; \ line3

    (Note that the commands must be separated using ; or &&, because the backslashes are also passed to the shell which does the same line-joining.)

    See also info make "Splitting Lines" and info make "Splitting Recipe Lines" in the GNU Make manual.

  • The other method is to tell make to always use one shell process for the entire recipe, using the .ONESHELL directive:

    .ONESHELL:
    foo: bar baz line1 line2 line3

    See info make "One Shell".

    (Note that while .ONESHELL is recommended by POSIX, not all make versions support it; e.g. BSD make only has a command-line flag for it. This shouldn't be a problem though.)

Thanks to

This is the solution to change a variable in a recipe:

recipe: $(eval variablename=whatever)

taking what @user3645902 mentioned, here is the solution to the main question:

recipe: @$(eval REV=`svn info $<|grep 'Last Changed Rev'|cut -f4 -d`) @echo $(REV)
1

According to Gnu Make 6.5 Setting Variables:

The shell assignment operator != can be used to execute a program and set a variable to its output. This operator first evaluates the right-hand side, then passes that result to the shell for execution. If the result of the execution ends in a newline, that one newline is removed; all other newlines are replaced by spaces. The resulting string is then placed into the named recursively-expanded variable.

So you could try the following (not tested):

REV != $$(svn info $<|grep 'Last Changed Rev'|cut -f4 -d\ ) \
echo $${REV}
3

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like