Search code examples
makefilegnu-make

How to unconditionnally re-assign a variable in a makefile (with submakefile)?


I am trying to re-assign a makefile variable (depending on its initial value), while keeping the new value in a submakefile. Here is the layout:

Makefile
subdir/
    - Makefile-sub

Main makefile:

export ARCH:=good_value
all:
    @echo In main makefile, ARCH=$(ARCH)
    @make --no-print-directory -C subdir

Sub-makefile:

all:
    @echo In sub makefile, ARCH=$(ARCH)

If I run make, I get the expected output:

In main makefile, ARCH=good_value
In sub makefile, ARCH=good_value

But if I try to override the variable from the CLI (which I need to be able to do), it doesn't work anymore: make ARCH=bad_value yields

In main makefile, ARCH=bad_value
In sub makefile, ARCH=bad_value

And make -E ARCH=bad_value or make -E "ARCH=bad_value" or make -E "ARCH:=bad_value" or make -E "export ARCH=bad_value" or make -E "export ARCH:=bad_value" yields

In main makefile, ARCH=good_value
In sub makefile, ARCH=bad_value

I noticed that calling the makefile as @make --no-print-directory -C subdir ARCH=$(ARCH) reassigns the value correctly, but I reckon I shouldn't need to do it, and I'd rather avoid it since I have a LOT of variables to reassign, and sub-sub-makefiles. Is there another solution to my problem ?


Solution

  • You could use 3 sets of variables:

    • DEFAULT_VAR to define the default value of variable VAR,
    • TOP_VAR to be used in the top Makefile instead of VAR,
    • VAR to be used in sub-Makefiles.

    This would imply modifications of your top Makefile but only to this one (replace all uses of ARCH with TOP_ARCH):

    $ cat Makefile
    TOP_ARCH := good_value
    export ARCH := good_value
    
    all:
        @echo In main makefile, TOP_ARCH=$(TOP_ARCH)
        $(MAKE) --no-print-directory -C subdir
    
    $ cat subdir/Makefile
    all:
        @echo In sub makefile, ARCH=$(ARCH)
    
    $ make
    In main makefile, TOP_ARCH=good_value
    make --no-print-directory -C subdir
    In sub makefile, ARCH=good_value
    
    $ make TOP_ARCH=bad_value
    In main makefile, TOP_ARCH=bad_value
    make --no-print-directory -C subdir
    In sub makefile, ARCH=good_value
    

    If you have many such variables and your make is GNU make you can automate most of this:

    $ cat Makefile
    VARIABLES := ARCH BIN COMP
    DEFAULT_ARCH := good_value
    DEFAULT_BIN := good_value
    DEFAULT_COMP := good_value
    $(foreach v,$(VARIABLES),$(eval TOP_$v=$(DEFAULT_$v)$(eval export $v=$(DEFAULT_$v))))
    
    all:
        @echo In main makefile, TOP_ARCH=$(TOP_ARCH), TOP_BIN=$(TOP_BIN), TOP_COMP=$(TOP_COMP)
        $(MAKE) --no-print-directory -C subdir
    
    $ cat subdir/Makefile
    all:
        @echo In sub makefile, ARCH=$(ARCH), BIN=$(BIN), COMP=$(COMP)
    
    $ make TOP_ARCH=bad_value TOP_COMP=bad_value
    In main makefile, TOP_ARCH=bad_value, TOP_BIN=good_value, TOP_COMP=bad_value
    make --no-print-directory -C subdir
    In sub makefile, ARCH=good_value, BIN=good_value, COMP=good_value