Search code examples
makefile

Makefile set variable in target


I have a makefile where a variable $DEBUG decides whether to build for deployment or debugging. There is one main Makefile, and multiple platform-specific makefiles that get included. I want the variable $DEBUG to be set to 1 automatically when the target test is built.

The main makefile:

DEBUG := 0

test : override DEBUG := 1

DIST_DIR := dist/
ifeq ($(DEBUG), 1)
    BUILD_DIR := build/debug
else
    BUILD_DIR := build/deploy
endif


# detect operating system
ifeq ($(OS), Windows_NT)
    UNAME := Windows
else
    UNAME := $(shell uname -s)
endif

# include platform-specific Makefile
export
ifeq ($(UNAME), Darwin)
    include Makefile.darwin
endif
ifeq ($(UNAME), Linux)
    include Makefile.linux
endif

And the platform-specific Makefile.linux:

... 
CXX := clang++-3.8
CXXFLAGS := -std=c++14 -fPIC -I./external/include -fcolor-diagnostics
LDFLAGS := 
LDLIBS := -lpthread -lm


ifeq ($(DEBUG), 1)
    CXXFLAGS += -g
else
    CXXFLAGS += -O3 -DNDEBUG
endif

... 

all : $(TARGET)


test : $(TEST_TARGET)
    $(TEST_TARGET)

So there are two rules for test: One in the main makefile sets the target-specific variable $DEBUG, and the one in Makefile.linux builds the test. The variables used for building ($CXXFLAGS, $BUILDDIR, and others) are set before the rules, and use conditionals.

Everything in the makefiles is working correctly, however calling make test does not alter the variable $DEBUG: both $CXXFLAGS and $BUILDDIR still get set to the values they would have for a deployment built.

Is there a way to first set $DEBUG := 1 in Makefile when the target is test, and then normally proceed? Or is there a special variable that contains the target name, for example

ifeq ($(MAKEFILE_TARGET), test)
    ...
endif

Solution

  • test : override DEBUG := 1 doesn't work because it declares a target-specific variable that is only visible within that recipe.

    There does exist a variable containing the target names that were specified at the command line: MAKECMDGOALS. Note that it doesn't include the default target if it wasn't explicitly specified at the command line.

    Example makefile:

    DEBUG := $(filter test,$(MAKECMDGOALS))
    
    all:
        @echo all : $(MAKECMDGOALS) : $(DEBUG) : $(if $(DEBUG),1,0)
    
    test:
        @echo test : $(MAKECMDGOALS) : $(DEBUG) : $(if $(DEBUG),1,0)
    

    Usage:

    $ make
    all : : : 0
    $ make all
    all : all : : 0
    $ make test
    test : test : test : 1
    $ make all test
    all : all test : test : 1
    test : all test : test : 1