Passing additional variables from command line to make

MakefileGnuCommand Line-Arguments

Makefile Problem Overview


Can I pass variables to a GNU Makefile as command line arguments? In other words, I want to pass some arguments which will eventually become variables in the Makefile.

Makefile Solutions


Solution 1 - Makefile

You have several options to set up variables from outside your makefile:

  • From environment - each environment variable is transformed into a makefile variable with the same name and value.

    You may also want to set -e option (aka --environments-override) on, and your environment variables will override assignments made into makefile (unless these assignments themselves use the override directive . However, it's not recommended, and it's much better and flexible to use ?= assignment (the conditional variable assignment operator, it only has an effect if the variable is not yet defined):

      FOO?=default_value_if_not_set_in_environment
    

    Note that certain variables are not inherited from environment:

    • MAKE is gotten from name of the script
    • SHELL is either set within a makefile, or defaults to /bin/sh (rationale: commands are specified within the makefile, and they're shell-specific).
  • From command line - make can take variable assignments as part of his command line, mingled with targets:

      make target FOO=bar
    

    But then all assignments to FOO variable within the makefile will be ignored unless you use the override directive in assignment. (The effect is the same as with -e option for environment variables).

  • Exporting from the parent Make - if you call Make from a Makefile, you usually shouldn't explicitly write variable assignments like this:

      # Don't do this!
      target:
              $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    

    Instead, better solution might be to export these variables. Exporting a variable makes it into the environment of every shell invocation, and Make calls from these commands pick these environment variable as specified above.

      # Do like this
      CFLAGS=-g
      export CFLAGS
      target:
              $(MAKE) -C target
    

    You can also export all variables by using export without arguments.

Solution 2 - Makefile

The simplest way is:

make foo=bar target

Then in your makefile you can refer to $(foo). Note that this won't propagate to sub-makes automatically.

If you are using sub-makes, see this article: Communicating Variables to a Sub-make

Solution 3 - Makefile

Say you have a makefile like this:

action:
    echo argument is $(argument)

You would then call it make action argument=something

Solution 4 - Makefile

It seems command args overwrite environment variable.

Makefile:

send:
	echo $(MESSAGE1) $(MESSAGE2)

Example run:

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK

Solution 5 - Makefile

From the manual:

> Variables in make can come from the environment in which make is run. Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value. However, an explicit assignment in the makefile, or with a command argument, overrides the environment.

So you can do (from bash):

FOOBAR=1 make

resulting in a variable FOOBAR in your Makefile.

Solution 6 - Makefile

There's another option not cited here which is included in the GNU Make book by Stallman and McGrath (see http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html). It provides the example:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

It involves verifying if a given parameter appears in MAKEFLAGS. For example .. suppose that you're studying about threads in c++11 and you've divided your study across multiple files (class01, ... , classNM) and you want to: compile then all and run individually or compile one at a time and run it if a flag is specified (-r, for instance). So, you could come up with the following Makefile:

CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread

SOURCES = class01 class02 class03

%: %.cxx
	$(CXX) $(CXXFLAGS) -o $@.out $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
	./$@.out
endif

all: $(SOURCES)

.PHONY: clean

clean:
	find . -name "*.out" -delete

Having that, you'd:

  • build and run a file w/ make -r class02;
  • build all w/ make or make all;
  • build and run all w/ make -r (suppose that all of them contain some certain kind of assert stuff and you just want to test them all)

Solution 7 - Makefile

If you make a file called Makefile and add a variable like this $(unittest) then you will be able to use this variable inside the Makefile even with wildcards

example :

make unittest=*

I use BOOST_TEST and by giving a wildcard to parameter --run_test=$(unittest) then I will be able to use regular expression to filter out the test I want my Makefile to run

Solution 8 - Makefile

export ROOT_DIR=<path/value>

Then use the variable, $(ROOT_DIR) in the Makefile.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPabloView Question on Stackoverflow
Solution 1 - MakefileP ShvedView Answer on Stackoverflow
Solution 2 - MakefileMark ByersView Answer on Stackoverflow
Solution 3 - Makefilenc3bView Answer on Stackoverflow
Solution 4 - MakefileYumaInauraView Answer on Stackoverflow
Solution 5 - MakefileThomasView Answer on Stackoverflow
Solution 6 - MakefileCiro CostaView Answer on Stackoverflow
Solution 7 - MakefileserupView Answer on Stackoverflow
Solution 8 - MakefileparasrishView Answer on Stackoverflow