Why `make` executes only the dependency? - makefile

I have the following Makefile:
compile:
echo a
run: compile
echo b
all: run
make all has the expected effect:
$ make all
echo a
a
echo b
b
But simply invoking make only executes compile target:
$ make
echo a
a
Why is this happening?

By default, make runs the first target, which in your case is compile: http://www.gnu.org/software/make/manual/html_node/How-Make-Works.html#How-Make-Works
If you want all to be the default target, list it first.

When you just execute make the first target will be executed by default. Its a convention to keep all as a first dependency even though it can be anywhere as you did unless you pass all to make. And even check out .PHONY.

Related

Export environment variables from child bash script in GNU Make

I have a script "set_env.py" that outputs the following uppon execution:
export MY_VAR_1=some_value
export MY_VAR_2=some_other_value
I cannot change this script, it is supplied in my current environment.
Further I have a Makefile that looks like this:
SHELL := /bin/bash
all: set_env
env | grep MY_VAR
set_env:
eval ./set_env.py
With this makefile I expected the grep to list my two variables, however it seems the environment is not set.
I suspect this is because make creates a sub-environment for each line and so the variables set on the first line will not be available in the second.
So the question is, how would I go about exporting the environment from the untouchable script in my makefile?
Actually, the output of the python is valid make.
One option then is to read the output of the python directly into the makefile.
The only fly in the ointment is that $(shell) doesn't cut the mustard.
include Environment.mk
PHONY: test
test:
env | grep MY_VAR
Environment.mk:
./set_env.py >$#-tmp
mv $#-tmp $#
How does this work?
The first thing that make tries to do is to ensure the makefile itself is up-to-date.
Since we have told it to include Environment.mk,
make must ensure that is up-to-date too.
Make finds a rule for Environment.mk
The python is run, creating Environment.mk
Environment.mk is read in, creating two make variables with the export attribute
The makefile is now up-to-date, so make proceeds on to the target (test in this case)
Make runs test's recipe, exporting any variables with the export attribute.
No recursion, but you should ensure the python always spits out make compatible syntax.
EDIT
As #raspy points out, this is not the whole story.
As it stands,
once Environment.mk has been created,
it will never be regenerated.
If set_env.py ever generates different output,
you should tell make what conditions these are by adding dependencies.
If set_env.py takes a trivial time to run,
I advise a simple .PHONY.
That way it will run every time you run make,
and Environment.mk will never be stale.
.PHONY: Environment.mk
Recursive make is your friend I'm afraid.
.PHONY: all
all:
eval $$(./set_env.py) && ${MAKE} test
.PHONY: test
test:
env | grep MY_VAR
There are a few moving parts here.
make all executes the shell command eval $(./set_env.py) && make test
The shell first does the command substitution
$(./set_env.py) is replaced by the export commands
The export commands are passed to the (shell) eval command
The environment variables are defined, but only for this shell invocation
The eval succeeds, so the execution passes to the command after the &&
Make runs recursively, but this second make has an augmented environment

I want to echo something at compile time.But it doesn't work for a cross compiler

I am working on a cross-compiler. I tried:
all:
; $(info $$var is [${var}])echo Hello world
But nothing is printed after running
$ make install
Instead a new file Makefile~ is created.
What should I do?
Try using #echo in the Makefile, which will suppress the echoing line and discards '#' before sending the line to the shell.
Typically you would use this for a command whose only effect is to print something, such as an echo command to indicate progress through the makefile.

Makefile: What does 'make $* clean' mean?

I know what make clean does.
But what does make $* clean do?
I'm not able to find a clear explanation anywhere.
As Ross says, we can't help because you haven't provided enough context. You need to provide at least the rule in which the make $* clean appears.
However, I'll guess it looks something like this:
%.xyz:
make $* clean
Here, $* is an automatic variable which will expand to the stem of the target (the text matching the % in the pattern). So, if you invoke make foobar.xyz, this rule would invoke make foobar clean: it would run a sub-make, build the foobar target, then build the clean target.
I've not seen anything quite like the above, although I can think of reasons for doing it. Far more common would be if you mistyped the command and it really said make -C $* clean, giving a rule like this:
%.xyz:
make -C $* clean
(note you should never use the static string make when invoking a sub-make; you should always use $(MAKE) or ${MAKE}). In this example running make foobar.xyz would run make -C foobar clean, which means change to the directory foobar and run the clean target there.
If it is invoked from a shell script, then $* is expanded to the arguments passed to the shell script.
#!/usr/bin/env bash
# filename clean.sh
make $* clean
The above shell script can be invoked like,
#./clean.sh --silent
Which will eventually pass the --silent to the make application and execute the following command.
#make --silent clean
Finally, $* in a shell-script is expanded by the shell, not by the make application.

Makefile that passes its command-line parameters to another script

In a project, I have a script called make.sh that builds the project and does some other stuff too. It is working well so far.
Then, just out of curiosity I've tried to create a Makefile that just passed its command-line parameters to this script so I could call it
make snapshot
instead of
./make.sh snapshot
this is the Makefile that I'm using right now
.PHONY: snapshot
%:
./make.sh $#
snapshot:
./make.sh snapshot
But this approach have some problems, I can't pass "build" as a parameter, because I have a "Build" directory (used by SCons), and I can't pass a second parameter to be passed to the script, like:
make upload 192.168.1.10
as make interprets it as two different targets...
Is there a way I can do this with the Makefile?
Yes, you can do it:
%:all
#true
all:
./make.sh $(MAKECMDGOALS)
but this is an abuse of Make. The idea is that Make should interpret its arguments as a set of targets, not an ordered list of general arguments. You should probably use a different tool.

How to handle setting up environment in makefile?

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.

Resources