8

So, to compile my executable, I need to have the library locations set up correctly. The problem is, the setup comes from a bunch of scripts that do the env variable exporting, and what needs to be set up may change (beyond my control) so I need to use those scripts instead of copying their functionality. To compile in regular command line, I need to do something like:

setup library1
setup library2
source some_other_setup_script.bash
g++ blah.c
# setup is a executable on my system that run some scripts

How would I write a makefile that accomplishes that? As far as I tried, the env variable exporting does not carry over (i.e. "export VAR=remember; echo $VAR" won't work)

polyglot
  • 9,945
  • 10
  • 49
  • 63

6 Answers6

11

You can also add environment variables properly with the machinery of GNU make, like so:

export TEST:="Something Good!"
test:
    echo $$TEST

This (I think) has different semantics from:

TEST2:="Something not quite so useful?"
test2:
    echo ${TEST2}

Which (again, I think) does the substitution within make before passing along to the shell. Note that the export command doesn't work within a target block, just unindented as an immediately executed command.

Dav Clark
  • 1,430
  • 1
  • 13
  • 26
6

If variable exporting is not working the way it does on your command line, that suggests that Make is choosing a shell different from the one you're using, with different syntax for handling variables (export VAR=remember; echo $VAR works fine for me). Make uses /bin/sh by default, but you can override this with the SHELL variable, which Make does not import from the environment. I suggest setting SHELL (in the Makefile) to whatever you're using in your environment and trying the export VAR=remember experiment again.

Matthew
  • 800
  • 3
  • 12
  • 35
Beta
  • 96,650
  • 16
  • 149
  • 150
  • I also realize that I should use $$VAR so that make won't think that I'm quoting a macro... – polyglot Oct 10 '09 at 23:50
  • 3
    It doesn't really mean that. GNU make simply runs a new shell for each line in the comand. (I suspect he combined the two commands with ; for brevity) http://www.gnu.org/software/make/manual/make.html#Execution "When it is time to execute commands to update a target, they are executed by invoking a new subshell for each command line." – Ted Mielczarek Oct 13 '09 at 15:20
  • would be great if you can share the way to set `SHELL` in `Makefile` right here too – cryanbhu Jun 27 '19 at 05:06
  • 1
    @cryanbhu: Looking back after ten years, I wish I'd given a slightly different Answer, but don't feel like editing it. Anyway, to set `SHELL`, just put `SHELL=/bin/bash` in your makefile (*outside* any rule). Be sure to use the actual path in use on your system; if you're not sure, try `which bash`, or whatever the command is in whichever system you're using. – Beta Jun 27 '19 at 20:04
3

Ultimately you will need to define the variable and execute the compiler in a shell list or even a script, rather than in separate make commands. There are a couple of refinements you could add, however. You could tell make about the script:

maintarget: script.sh blah.c
    source script.sh; g++ blah.c

script.sh:
    setup include script here

Another thing would be to just execute all that stuff in the same shell

maintarget: blah.c
    run this; run that; run the other thing; g++ blah.c 

I believe all make versions will run a ; list in the same shell, but you can always force a subshell with (list) or by calling specifically a shell script as a compiler command wrapper.

Don't forget to have the appropriate targets depend on your scripts themselves. BTW, some make versions (pmake aka bsd make) can execute a command when defining a make variable, and all versions of make then exports those. But I don't think gmake can do that.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
1

You could write another shell script that executes all those commands, then prints out variable assignments that make can use. Run the script, pipe its output to a file, then include that file from your Makefile. For example:

Makefile:

all:
    echo $(FOO)

test.mk: test.sh
    ./$< > $@

include test.mk

test.sh

echo "FOO=1"

Running "make" in the directory containing this Makefile produces:

make: Entering directory `/home/luser/build/mktest'
Makefile:7: test.mk: No such file or directory
./test.sh > test.mk
make: Leaving directory `/home/luser/build/mktest'
make: Entering directory `/home/luser/build/mktest'
echo 1
1
make: Leaving directory `/home/luser/build/mktest'

make creates test.mk by running the shell script, then includes it. test.mk contains the output of test.sh, and is parsed as a Makefile. See http://www.gnu.org/software/make/manual/make.html#Include for more details.
We use a variant of this in Mozilla's client.mk to let you define options in a "mozconfig" file: http://mxr.mozilla.org/mozilla-central/source/client.mk#138

Ted Mielczarek
  • 3,919
  • 26
  • 32
0

Restatement: How do I get a shell variable into a make file?

Something like:

MYVAR := $(shell echo $(MYVAR)) <any_makefile_additions_here> 

So, this defines MYVAR inside a MAKEFILE when an environment variable named MYVAR is also set.

ingyhere
  • 11,818
  • 3
  • 38
  • 52
0

It might be of interest, that, in order to override an option that is already defined in a makefile, make supports (I am referring to GNU Make 3.82, but other version probably too) the option -e. Example:

Makefile:

CC=gcc
...

Run make:

CC=gcc-4.7
make -e

will use gcc-4.7 instead of gcc.

user1240076
  • 183
  • 1
  • 2
  • 10