Reordering commands in a Makefile - makefile

I have the following makefile
.PHONY: target1
target1: target2
command1
My job is to run command1 before target2. For that, I have split command1 into command1 and command2 and rewritten the Makefile as follows:
.PHONY: target1
target1:
command1
target1: target2
command2
But when I run this Makefile, it is only executing target2 and command2. command1 is not run.

A simple solution would be to rename the first target1 to something else and call it before the target2 rule. Something like:
.PHONY: target1 target1_cmd
target1_cmd:
command1
target1: target1_cmd target2
command2
This will run command1, whatever is in target2 and then run the command2.
I'm not sure I get everything that you are trying to do but let me know if you need more details and explanation.

If command1 is the first step to build target2, simply add it in its recipe:
target1: target2
command2
target2:
command1
<rest of target2 recipe>
If you want to execute command1 before building target2, what's missing in your problem statement is a third target which recipe is command1. If command1 creates a file target3 then it is easy:
target1: target2
command2
target2: target3
<target2 recipe>
target3:
command1
If command1 does not create any file, you can use an empty marker file as an indicator that command1 has been executed:
target1: target2
command2
target2: target3
<target2 recipe>
target3:
command1
touch "$#"
Finally, if target1 and target2 shall be built each time you invoke make, just declare all these as phony:
.PHONY: target1 target2 target3
target1: target2
command2
target2: target3
<target2 recipe>
target3:
command1

Related

Is it a good practice to list multiple .PHONY directives in Makefile?

I understand Makefile allows multiple .PHONY targets in the file:
.PHONY: target1
...
.PHONY: target2
but is it a good practice?
Why don't we just list all the phony targets in a single top-line such as:
.PHONY: target1 target2

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

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.

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.

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