Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent make from communicating any variable to a submake?

Tags:

shell

makefile

I am unable to prevent make from communicating any variables to a submake. I've read the manual and I've followed their advice (resetting MAKEOVERRIDES and MAKEFLAGS) but it's still not working has I think it should.

Consider the following prototype Makefile:

${warning $(MAKEOVERRIDES)}
${warning $(MAKEFLAGS)}
${warning $(VAR)}

none:
    $(MAKE) -f Makefile MAKEOVERRIDES= MAKEFLAGS= all

all:
    echo done!

If I make VAR=10 none, I get the following:

Makefile:2: VAR=10
Makefile:3: 
Makefile:4: 10
make -f Makefile MAKEOVERRIDES= MAKEFLAGS= all
make[1]: Entering directory `/home/adriano/sandbox/makes'
Makefile:2: 
Makefile:3: 
Makefile:4: 10
echo done!
done!
make[1]: Leaving directory `/home/adriano/sandbox/makes'

Meaning that make is communication VAR to the submake. Is this the correct behaviour?

I've tried unexport VAR and bash -c make ... without any luck.

EDIT: I've modified none's recipe to: bash -c "echo $$MAKEOVERRIDES $$MAKEFLAGS $$VAR" ; make ...

This way I found out that VAR is actually being passed through the environment that make creates for the commands to be executed and not through the other variables (the other variables are also passed this way to make).

I think my question now is: how can I create a fresh shell/environment to run my sub make?

EDIT: Someone asked why am I trying to this; I'll try to answer to that here.

I have a "module" which uses a variable named CONFIG. In order to build this module I need to build another partially unrelated "module" which also uses CONFIG, but with a different value. The problem is that when I try to build the "sub-module" CONFIG contains the value of the "super-module." I could specify CONFIG when making the "sub-module" however both modules use many variables with the same name and trying to specify them all would make the modules tightly coupled which is something I cannot afford.

How can this be so difficult...

like image 929
Adriano Carvalho Avatar asked Oct 03 '22 21:10

Adriano Carvalho


1 Answers

This is wrong:

none:
        $(MAKE) -f Makefile MAKEOVERRIDES= MAKEFLAGS= all

These variables (MAKEOVERRIDES and MAKEFLAGS) are set in the environment by the parent make to be passed down to the sub-makes. Setting overrides on these values inside the recipe won't help, because make has to set the environment for the recipe before it actually starts the commands in the recipe (of course).

You have to override/remove these values in the parent makefile, so that those changes are seen by the parent make before it constructs the sub-make's environment:

MAKEOVERRIDES =
none:
        $(MAKE) -f Makefile all

There's no perfect way to do this. However, you can play a trick that will work most of the time:

unexport $(shell echo '$(MAKEOVERRIDES)' | sed 's/=[^ ]*//g')
MAKEOVERRIDES =

The first line tries to unexport all the variables in MAKEOVERRIDES and the second line resets MAKEOVERRIDES. There are a few issues with this. One is that if MAKEOVERRIDES is empty, it will use "unexport" by itself which unexports everything. That can be easily worked around by sticking some bogus variable before the shell function. The other is that if any variable's value contains whitespace, the expansion will consider it a variable to be unexported. That's probably OK, but it's odd.

I can't think of any better way to do it.

You don't really say why you want to do this. Have you considered doing something different, such as running the commands where you want to have a "vanilla" environment using env; for example if you want to run a command with a limited and specific set of env vars, you can run:

test:
        env -i PATH='$(PATH)' LANG='$(LANG)' runMyCommand --with --my arguments

Unfortunately some versions of env use - instead of -i; check your man page.

Alternatively, you can try to start a login shell which will re-read the user's shell setup environment from scratch:

test:
        /bin/sh -lc 'runMyCommand --with --my arguments'

EDIT: It's difficult because what you're asking to do (restrict the environment of the sub-make) is tricky.

Luckily based on your description, it doesn't seem necessary. Make has a hierarchy of importance for finding variable values. The command line is the highest level (well, there's override but we'll ignore that). After that comes variables set in the makefile itself. And last and lowest comes variables imported from the environment (well, default variables are even lower but we'll ignore that too).

So if your goal is to allow the variables in the sub-makes to not be affected by command line variables given to the upper-level makes, then all this rigmarole of getting the variables out of the environment is not necessary. Variables set in the sub-makefiles will take precedence over the values in the environment. So all you have to do is get rid of the variables set on the command line, which I've already shown how to do above, by setting MAKEOVERRIDES.

like image 90
MadScientist Avatar answered Oct 13 '22 12:10

MadScientist