907

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.

pillravi
  • 4,035
  • 5
  • 19
  • 33
Pablo
  • 28,133
  • 34
  • 125
  • 215

8 Answers8

1004

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.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
P Shved
  • 96,026
  • 17
  • 121
  • 165
  • 18
    to pass from command line somthing with spaces do ``make A='"as df"'`` – Ciro Santilli OurBigBook.com Jan 16 '13 at 17:27
  • 6
    Seems like you're asking for trouble if you care about environment variables. For one thing, it's a debugging nightmare if it works in place A and not in place B, just because they have different environments. – James Moore Jan 30 '13 at 01:00
  • It is actually spelled --environment-overrides – user7610 Nov 23 '13 at 11:13
  • 16
    Just based on experience, exporting stuff like CFLAGS is a recipe for nightmare for large projects. Large projects often have 3rd party libraries that only compile with a given set of flags (that no one bothers fixing). If you export CFLAGS, your project's CFLAGS ends up overriding the 3rd party library's and triggers compile errors. An alternate way might be to define `export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)` and pass it along as `make -C folder $(PROJECT_MAKE_FLAGS)`. If there's a way to tell the library's makefile to ignore the environment, that'd be ideal (opposite of -e). – R.D. Mar 17 '14 at 07:09
  • For passing variables to a submake, consider appending to MAKEFLAGS in the parent make. See [here](http://www.gnu.org/savannah-checkouts/gnu/make/manual/html_node/Options_002fRecursion.html). – pattivacek Jul 31 '14 at 19:37
  • 36
    WARNING: In the section "Exporting from the parent Make" above, "Don't do this!" is *critically misleading*. Passing variables on the command line overrides assignments in the sub-makefile but exported variables do *not* override assignments in the sub-makefile. These two methods for passing variables to a sub-makefile are *not* equivalent and should not be confused. – Jonathan Ben-Avraham Aug 17 '15 at 05:28
  • Guys did anyone have any success using make `override` statement? Because I just get: `make: override: Command not found` – Tomáš Zato Sep 30 '15 at 12:30
  • I'd like to know why this is not working; I have a makefile that has `ifdef($(DEBUG),1) debug_flags else normal_flags endif` which is located at the top and the variable is passed from command line like `make all DEBUG=1` or `make DEBUG=1 all` but it ignores that value and uses the value set by `DEBUG ?= 0` at all times. Why is that? – jtimz May 24 '16 at 01:44
  • Just to complement, this is the [link](https://www.gnu.org/software/make/manual/make.html#Overriding) to the documentation of the **From command line** approach. – wlnirvana Jul 10 '16 at 16:51
  • 2
    Multiple arguments? – basickarl Oct 09 '17 at 14:42
  • 14
    Any difference ? `make target FOO=bar` `make FOO=bar target` ? – gfan Oct 08 '18 at 07:20
  • In `Makefile` I have a line `ifdef MY_FLAG`, if I execute a command `make MY_FLAG=any_string_I_want`, the `ifdef MY_FLAG` evaluates to true, however, if I execute a command `make MY_FLAG` (i.e. without setting any value), make command returns an error. **So my question:** how can I make `Makefile` support two options such that `make MY_FLAG` would evaluate `ifdef` to true and single `make` without anything would evaluate `ifdef` to false? – mercury0114 Oct 22 '20 at 10:25
  • Part of the anwer is wrong. The CFLAGS if its inherited from another make target via $(MAKE) target you don't need nothing. It's simply propogated from the parent. – Arun George Sep 19 '21 at 13:59
  • Is it possible to expand an existing environment variable? I use autotools which has some default values in `CFLAGS` and sometimes I want to pass `-D DEBUG` in addition to those default arguments. I tried `make CFLAGS="\$CFLAGS -D DEBUG" all` but that does not escape the dollar sign but yields `FLAGS -D DEBUG`. – SimonH Dec 15 '21 at 16:20
382

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

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 2
    by sub-makes you mean to the makefiles `included` in the main makefile? – Pablo May 13 '10 at 10:49
  • 2
    @Michael: It means calling make again from inside the makefile. I've updated my answer since you seem to be interested in this detail. – Mark Byers May 13 '10 at 10:54
  • 4
    "Note that this won't propagate to sub-makes automatically." Untrue! "By default, only variables that came from the environment or the command line are passed to recursive invocations. You can use the export directive to pass other variables." https://www.gnu.org/software/make/manual/html_node/Environment.html#Environment – ThomasMcLeod Jul 31 '18 at 01:10
  • If you look at the page you referenced you'll see it says explicitly _make automatically passes down variable values that were defined on the command line, by putting them in the MAKEFLAGS variable. See Options/Recursion._ So contrary to this answer, make **will** propagate to sub-makes automatically. – MadScientist Nov 21 '21 at 13:53
  • 1
    make target foo=bar also works!! – itirazimvar Dec 28 '21 at 11:18
  • on windows is set foo=bar && make – superbem Oct 05 '22 at 19:53
181

Say you have a makefile like this:

action:
    echo argument is $(argument)

You would then call it make action argument=something

nc3b
  • 15,562
  • 5
  • 51
  • 63
40

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
2240
  • 1,547
  • 2
  • 12
  • 30
35

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.

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • 2
    The other way is indeed better in nearly all cases. I'll leave this here for completeness. – Thomas May 13 '10 at 10:58
  • 3
    This is the only answer which shows the assignment of variables _before_ the make command on the same line - it's worth knowing this isn't a syntax error. – M_M Apr 01 '20 at 20:23
  • 5
    The nuance to understand is that with the assignment in front you're setting an environment variable for the make subprocess. With the assignment after the target you're passing an argument to make and it is parsing it and it will override what's set in your environment. – user615501 Jan 28 '22 at 18:48
8

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)
Ciro Costa
  • 2,455
  • 22
  • 25
5

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

serup
  • 527
  • 5
  • 11
4
export ROOT_DIR=<path/value>

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

parasrish
  • 3,864
  • 26
  • 32