How to get list of sub-targets which got hit in a makefile? - bash

I have a makefile as follows,
all: target1
#echo "$(USER)"
target1: target2
#echo "$(HOME)"
target2:
#echo "$(SHELL)"
If I execute make all, I will get some output as expected. But is there way to know which targets got hit when ran that command. In this case, make all invoked target1, target2. If I had done make target1 then only target2 would have invoked.
One very bad solution I did was adding echo statement in all my targets as follows,
all: target1
#echo "Running $#"
#echo "$(USER)"
target1: target2
#echo "Running $#"
#echo "$(HOME)"
target2:
#echo "Running $#"
#echo "$(SHELL)"
Is there any good solution without having to add such prints?

First of all, when you run
make target1
You should see first target2 then target1 executed..
If you want to see how make orders the targets and executes them, you can run make -d.
Alternatively, if you want to see the shell command lines that are executed without actually running them, the option --dry-run exists but does not indicate the actual target names.

Related

Double Dollar "$$#" target name in GNU Make

I have a rule from OP-TEE (uses large makefile include and make invocation trees to compile two operating system kernels and applications) with some immediately expanded variables -- as far as I can tell, there is no second expansion relevant here, since the double double dollar is in the rule and thus not subject to second expansion. It should always be expanded in the second phase:
$(link-out-dir$(sm))/$(user-ta-uuid).elf: $(objs) $(libdeps) \
$(link-script-pp$(sm))
#$(cmd-echo-silent) ' LD $$#'
echo Target '$#', '$$#', "$#", "$$#"
In the output, one can see that all occurrences of $#and $$# are expanded by make, not by sh, but the single dollar ones are not filled with the correct value, and the double ones did not escape themselves:
echo Target '', 'out/someuuid.elf', "", "out/someuuid.elf"
Target , out/someuuid.elf, , out/someuuid.elf
What i was expecting was:
echo Target 'out/someuuid.elf', '$#', "out/someuuid.elf", "$#"
Target out/someuuid.elf, $#, out/someuuid.elf,
Which mechanism of make could be the reason for the expansion to work differently here?
This target is nested two layers deep in other makefiles and four make invocations, thus it's a bit difficult to find out what the buildchain has configured differently here.
I cannot reproduce this behaviour with a minimal makefile:
all: target1 target2 target3
.PHONY: target1 target2 target3 all
.SUFFIXES:
target1:
echo Target1 '$#', '$$#', "$#", "$$#"
# should make no difference, since used in immediate context on rule specification
TARGET2 := target2
TARGET3 = target3
$(TARGET2):
echo Target2 '$#', '$$#', "$#", "$$#"
$(TARGET3):
echo Target3 '$#', '$$#', "$#", "$$#"
yielding the expected output with $# expanding to the target name and $$# expanding to a string or empty list of positional shell parameters:
echo Target1 'target1', '$#', "target1", "$#"
Target1 target1, $#, target1,
echo Target2 'target2', '$#', "target2", "$#"
Target2 target2, $#, target2,
echo Target3 'target3', '$#', "target3", "$#"
Target3 target3, $#, target3,
Specifying .SECONDEXPANSION does not change the results, as expected.
Syntax highlighting can be tricky -- I wasn't aware of the whole target being content of a variable itself -- some targets above there was a define gen-link-t beginning a multiline variable, ending some targets below.
The target was actually invoked after generation using $(eval $(call gen-link-t)) at the end of the file, instead of being read in line-by-line -- causing the first expansion of $$ to $ to happen when expanding the variable within the $(call), making the call return the $ as plain text. The second evaluation happened when make was reading this target again via $(eval)

How to prevent the prerequisite of a target from expanding when the target is not used?

In a Makefile with multiple targets, how can one prevent the prerequisites of targets that are not being used from expanding? See the following example:
thisexpands = $(warning Expanded!)
.PHONY: target1
target1: $(thisexpands)
#echo Target 1
.PHONY: target2
target2:
#echo Target 2
Calling target2 forces thisexpands to expand, even though it is lazily evaluated and it and target1 are never used.
In my real world case expanding thisexpands when calling target1 is an issue, because it is a shell command that prints errors when called out of context of target1 and it's parent targets(not shown here).
Makefiles are fully parsed before the first rule is run. As part of parsing, all the targets and prerequisites must be expanded. You can find details of when expansion happens for different parts of a makefile in How make Reads a Makefile in the GNU make manual.
One way is to use recursion:
thisexpands = $(warning Expanded!)
target1: ; $(MAKE) target1-recurse T1_DEPS='$(value thisexpands)'
T1_DEPS =
target1-recurse: $(T1_DEPS)
#echo Target 1
This doesn't work:
You can probably defer expansion by using secondary expansion, something like this:
.SECONDEXPANSION:
target1: $$(thisexpands)
Be very careful that you escape the prerequisite list appropriately.
There's no way to cancel the expansion completely. However, you can use the conditional assignment based on the value of $(MAKECMDGOALS):
thisexpands = $(if $(filter target1,$(MAKECMDGOALS)),$(warning Expanded!))
.PHONY: target1
target1: $(thisexpands)
#echo Target 1
.PHONY: target2
target2:
#echo Target 2
Note that it works if target1 is only built explicitly (make target1) and not by default, or as a part of building another target.

Impose an order for the prerequisites of a target

I have a makefile snippet:
all: $(objects)
fresh: clean all
clean: ;rm $(objects)
Here, I want to ensure that when I do make fresh - clean should precede all.
But how can I make sure this, given that when I do make all, clean should not be made?
I can imagine that one way could be like this
fresh: clean
make all
Is it the right (or the only) way to solve this issue?
If you use GNU make:
all:
#echo $#
#sleep 1
#echo end $#
clean:
#echo $#
#sleep 1
#echo end $#
fresh:: clean
fresh:: all
.PHONY: clean fresh all
Please note the double colon after targets fresh! See the documentation:
The double-colon rules for a target are executed in the order they
appear in the makefile.
If you run make -j2 fresh it shows it works as expect:
clean
end clean
all
end all
But with fresh:: clean all doesn't work properly parallel (maybe unexpected).
With BSD make:
all:
#echo $#
#sleep 1
#echo end $#
clean:
#echo $#
#sleep 1
#echo end $#
fresh: clean all
#echo $#
.ORDER: clean all
.PHONY: clean all fresh
Note the line begin with .ORDER. It works well in parallelization too (see man make). Without parallelization the order of dependencies in line fresh: counts.
As you already suggest in your question, calling make recursively on the same makefile for the target all in a recipe whose prerequisite is clean:
# At the very beginning of the makefile
CURRENT_MAKEFILE := $(lastword $(MAKEFILE_LIST))
# ...
.PHONY: fresh
fresh: clean
$(MAKE) -f $(CURRENT_MAKEFILE) all
This imposes an order, since the target fresh depends on the prerequisite clean, clean's recipe will be executed before fresh's recipe, which in turn will execute all's recipe.
Note that I'm using here $(MAKE) instead of make for the recursion.

If comparison in make file

I have a makefile. I need to check the exit status of a command and the performing comparison, if exit status is 0 then perform some display action. But i am getting the same message if its success or failure for both the scenario.
Please find the below code and Help me what is the right way to do this:-
FILES = test1.sh test2.sh
manoj: $(FILES)
ls $(FILES)
$(eval exitstatus="$(shell echo $$?)")
#echo $(exitstatus)
ifeq (0,$(exitstatus))
$(error something going wrong..........)
endif
clean: pwd
Getting same output as :
testmake.mk:4: *** something going wrong........... Stop.
for both ifeq ifeq (0,$(exitstatus)) and ifneq ifeq (0,$(exitstatus))
I want to perform some action if the condition is success otherwise nothing want to do.
In the recipe shell commands are used, not make directives.
And when target's recipe is executed that means all its prerequisites do exist:
manoj: $(FILES)
#echo "$(FILES) do exist at this point."

Makefile: defining rules and prerequisites in recipes

I have a setup where the files I want to process with make are dependent on the output of another program. Building the program and all its prerequisites
is also a complicated task so I would like to use make for this as well. Now my problem is, that it doesn't seem that one can generate rules and prerequisites in Makefile recipes. Consider the following code:
bar:
echo target1 target2 target3 > bar
foo: bar
$(eval BAR := $(shell cat bar))
define FUN
$(1):
touch a$(1)
endef
ifdef BAR
$(foreach i,$BAR,$(eval $(call FUN,$(i))))
endif
blub: foo $(BAR)
I replaced a big set of complicated recipes that lead to the generation of the list of files I want to have in the end by the bar recipe. In reality, producing the content of bar is very complicated and should be done by a set of Makefile recipes and cannot just be done by (as the above suggests):
BAR:=$(shell echo target1 target2 target3)
I would like to put the foreach loop into the recipe for foo but that fails with prerequisites cannot be defined in recipes which makes sense and is also explained in function define in makefile
But it seems that when I do make blub that at the time when foo eval's BAR to a different value, the prerequisites for blub are not re-evaluated.
So I think ultimately I'm looking for two things:
how do I generate recipes dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?
how do I update the prerequisites of a target (blub in this case) dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?
Thank you!
EDIT: SOLUTION
With the help of #user657267 the following seems to solve my problem:
.PHONY: all
all: blub
-include bar.make
.PHONY: blub
blub: $(BAR)
echo $^
bar.make: Makefile
printf 'BAR=target1 target2 target3\n' > $#
printf 'target1 target2 target3:\n' >>$#
printf '\ttouch $$#' >> $#
.PHONY: clean
clean:
rm -f target1 target2 target3 bar.make
Sounds like you should be using make's self-remaking features
-include bar.make
blub: $(BAR)
#echo $^
bar.make:
#echo BAR := target1 target2 target3 > $#
#echo target1 target2 target3: ; touch $$# >> $#
Obviously the recipes for bar.make are contrived, in the real world they'd probably invoke some kind of script that outputs a valid makefile.

Resources