Setting a Makefile Variable From Outside the Makefile

[article]
Summary:

In this article, Ask Mr. Make talks about how to set Makefile variable from outside the Makefile.

A simple way to handle this is with a Makefile variable called BUILD_DEBUG which is set to yes in the Makefile and overriden on the GNU Make command-line when building the release version. In that case you might see something like

        BUILD_DEBUG=yes
        ...

at the start of the Makefile. That sets the default to be debug builds and is overriden by doing

gmake BUILD_DEBUG=no

when it's release time. And around release time you might be tempted to define BUILD_DEBUG to be no in your shell's start up script (e.g. in .cshrc or .bashrc) so that all your builds are release. Unfortunately, this doesn't work. To see why you need to understand how GNU Make sets variables in a Makefile. Start by considering this simple Makefile that prints the value of BUILD_DEBUG:

        BUILD_DEBUG=yes
        all: ; @echo BUILD_DEBUG is $(BUILD_DEBUG)

Trying three runs of the Makefile (once with no options, once setting BUILD_DEBUG on GNU Make's command-line and finally with BUILD_DEBUG set in the environment) yields:

        $ gmake
        BUILD_DEBUG is yes
        $ gmake BUILD_DEBUG=no
        BUILD_DEBUG is no
        $ export BUILD_DEBUG=no 
        $ gmake
        BUILD_DEBUG is yes

The last line shows that variables defined inside a Makefile override values in the environment. If you want to us a hammer to “solve” this problem you can set GNU Make's -e switch which makes the environment take precedence, but that affects every variable not just the one we are concerned with.

The rule to remember is (like the old paper, scissors, rock game): command-line beats Makefile beats environment. So a variable defined on the command-line will take precedence over the same variable defined in a Makefile which will take precedence over the same variable defined in the environment.

So suppose you want to have a BUILD_DEBUG variable that is set by default to yes and can be overriden either on the command-line or in the environment. GNU Make provides two ways to achieve that. Both rely on checking to see if the variable is already defined.

Here's one way. Replace the setting of BUILD_DEBUG in the original Makefile to

        ifndefBUILD_DEBUG
        BUILD_DEBUG=yes
        endif

Now if BUILD_DEBUG has not already been set (that's what ndef means: not defined) then it will be set to yes, otherwise it is left unchanged. Since that's a bit of a mouthful GNU Make provides a shorthand for the pattern ifndef/set variable/endif in the form of the ?= operator. With a one character change we get the desired result:

        BUILD_DEBUG?=yes
        all: ; @echoBUILD_DEBUG is $(BUILD_DEBUG)

The ?= says set BUILD_DEBUG to yes, unless it is already defined, in which case leave it alone. Rerunning the test from above reveals:

        $ gmake
        BUILD_DEBUG is yes
        $ gmake BUILD_DEBUG=no
        BUILD_DEBUG is no
        $ export BUILD_DEBUG=no 
        $ gmake
        BUILD_DEBUG is no

And this provides the ultimate flexibility allowing a default setting in the Makefile which is overriden in the environment and a temporary override on the command-line.

        $ export BUILD_DEBUG=no
        $ gmake BUILD_DEBUG=aardvark
        BUILD_DEBUG is aardvark

User Comments

1 comment
Debra Lee's picture

The rule to remember is that command-line beats rock, paper, and scissors. Makefile beats environment.

 

October 10, 2022 - 10:35pm

About the author

AgileConnection is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.