I am running make on macOS and it is not pleased with any local variables . Take this snippet intended to get the full path to the directory of the Makefile script
setup_for_run:
mkfile_path=$(abspath $(lastword $(MAKEFILE_LIST)))
mkfile_dir=$(dir $(mkfile_path))
echo "scriptdir=$(SCRIPT_DIR)"
export PATH=$($(SCRIPT_DIR)/.venv/bin:$(PATH))
The result of make setup_for_run is:
$make setup_for_run
mkfile_path=/Users/steve/git/hercl/Makefile
mkfile_dir=
echo "scriptdir="
scriptdir=
export PATH=
So we see that none of the local variables are operational. What is the way to get them activated in the gnu make installed by default on macOS ?
Make runs each command in a recipe in its own shell (unless declaring .ONESHELL). Any modified state such as variables is cleared for each command. And, any variables set are never communicated outside make. For this purpose you're more likely to want to source a bash script.
Make are for making files from other files.
There are several alternatives to set the variables:
# Global scope
VARIABLE := myglobal
# Target specific
mytarget: VARIABLE := targetspecific
# Prefix the command
myprefix:
VARIABLE=prefix env
I am trying to create something like a global variable that I will use in order to make my project easy to deploy for other developers.
I would like to have an .sh file where there is a variable defining the location of the project.
Later on I want to export this variable and make it accessable in every makefile that I am creating so that I can use this design to keep everything constant and in one place.
This is an example of what I am trying to build:
Creating and exporting the variables in script.sh:
#!/bin/bash
DIRECTORY='some path value here'
Importing the values in multiple Makefiles:
# start script and fetch the value
VAR := $(shell ./script.sh | sed -n '/^result: /s/^.*: //p')
all:
#echo VAR=$(VAR)
I would like to see how other people are dealing with the same problem.
Being a better developer is my goal here. :)
Feedback always welcomed.
Environment variables exported in the shell are visible from make, so in a shell script like this:
#!/bin/sh
VAR=value
export VAR
make $*
The Makefile will start with VAR defined to value. That's one way to get variables from a shell script into make.
If you don't want the shell script to run make, you can have a user source it:
$ source script.sh
$ make
The variables set in the script will be visible to make this way too.
Or course there doesn't seem to be any reason you need a shell script here. Stick your configuration into a fragment of a Makefile (which would look almost exactly like your shell script, but not use quotes for multiple word values) and then include Makefile.inc in your main makefile.
Also note that syntax like this:
#!/bin/sh or another commment
VAR=value
export VAR
It equally valid included in a Makefile or sourced into a shell script. So sometimes it's possible to use the same include file in both places!
I didn't find anything about that, and i am trying to wrote this rule in my Makefile.
setenv:
#echo "export DYLD_LIBRARY_PATH=."
#echo "export DYLD_INSERT_LIBRARIES=$(NAME).so"
#echo "export DYLD_FORCE_FLAT_NAMESPACE=1"
#echo "# Run eval $$(make setenv)"
So by running eval $(make setenv) in my terminal, the environment variable will be set.
But it's starting an infinite loop.
I've also try with:
\$(make setenv)
but nothing work ... What is the correct syntax for this ?
EDIT:
\$$(make setenv) Did the trick !
If you're setting environment variables for other recipes, note that:
Using $(shell export ...) won't work: $(shell ...) always spawns a new shell, so anything that is exported into it won't be available outside of that particular invocation;
Using export shell commands in a recipe will only work if .ONESHELL is used (not recommended), because each recipe line runs in a different shell.
The typical way to export environment variables to sub-makes and sub-shells is to use export as a Makefile directive, like this:
export DYLD_LIBRARY_PATH=.
export DYLD_INSERT_LIBRARIES=$(NAME).so
export DYLD_FORCE_FLAT_NAMESPACE=1
Outside any recipe.
I want to run a script inside a makefile like this
all: a b
a:
cd ~/trials; \
. ./sx.sh
b:
echo $(bn)
sx.sh do this
export bn=1
I don't see the variable in my terminal while issuing make command. My aim is to run a script before compiling my project for those script specific settings.
You can't assume that the commands issued by make are all processed by the same instantiation of the shell. Make does not open a shell and feed it commands one-by-one and nor does it save the commands into a file and then feed it into a shell. It usually spawns a shell for each command like this:
$(SHELL) -c 'cd ~/trials; . ./sx.sh'
which means you cannot alter the environment and have it inherited by later commands.
The best way is to use make variables to store the specifics you wish to pass to the commands and use those variables in appropriate places.
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)
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.
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.
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.
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
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.
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.