Is there an automatic variable for all grouped targets in Makefile? - makefile

Not seeing anything in documentation, but I could be missing something. If I have:
a b &: c
echo "targets are $???"
$# will only show a or b, but not both. Is there anything that will expand to a b?

No, I don't think you've missed anything as also pointed out in the comment. Behavior of $# is as specified / documented:
During the execution of a grouped target’s recipe, the automatic variable ‘$#’ is set to the name of the particular target in the group which triggered the rule.
Would using a variable be an acceptable solution to address your need?
GRP_1 := a b
$(GRP_1) &: c
echo "targets are $(GRP_1)"

Related

Invoking a Make target in a loop with an argument

I am designing a simple makefile that defines one target which takes an argument, and I would like to define a second target that invokes the first target in a loop, once per every variable defined in an array variable at the top of the Makefile.
my_loop_var = var1 var2
my_thing:
echo $MY_VAR
all:
invoke my_thing once for each value of my_loop_var
What is the right way to solve this?
Note: $MY_VAR will probably expand as Y_VAR because make will try to expand variable M, which is probably undefined, and concatenate Y_VAR to the result. Use $(VARNAME) to expand make variable VARNAME. It is only with single-character variable names that you can expand with $X.
There is not really a "right way". There are many ways. The most straightforward from your specifications (but the less natural) would be something like:
my_loop_var := var1 var2
my_thing:
echo "$(MY_VAR)"
.PHONY: all my_thing
all:
for v in $(my_loop_var); do $(MAKE) my_thing MY_VAR="$$v"; done
The recipe of all is a shell loop that re-invokes make with the my_thing goal and with each value in my_loop_var passed as the value of make variable MY_VAR.
Note the $$v to escape the first expansion that make always performs before passing the recipe to the shell. With just $v make would expand the recipe as ... MY_VAR="" ... and the result would not be what you expect.
Note also the use of the MAKE make variable instead of directly calling make (have a look at the documentation if you want to understand why it is better like this).
all and my_thing are declared as phony because they are not real file names that their recipes create, and make needs to know this kind of things.
But a much more make-ish way would be something like:
my_loop_var := var1 var2
my_thing_targets := $(addprefix my_thing_,$(my_loop_var))
.PHONY: all $(my_thing_targets)
all: $(my_thing_targets)
$(my_thing_targets): my_thing_%:
echo "$*"
Here we define as many my_thing_something targets as there are something values in my_loop_var. And explain make how to build such targets with a static pattern rule. In the recipe of a pattern rule the $* automatic variable expands as the part that matched the % pattern. So, this static pattern rule says that if we need to build my_thing_something, the recipe is echo "something".
We declare all these my_thing_something targets as prerequisites of all such that if you type make or make all, make will build all the my_thing_something targets.
This second solution is better for at least two reasons. First, make is invoked only once, which is better, at least for performance. Second, make can parallelize the build of the my_thing_something if you use the -j N option (to allow make to run up to N jobs in parallel). This also is better for performance.
But it is also a matter of style. Very frequently if you use shell loops in your recipes, especially to invoke make again, it is the sign that you did not really understand what make is intended for and how it works. The make language is not a scripting language (even if the recipes are written in shell language, which is a scripting language); make is designed to "loop" over all targets to build, without the need for explicit loops.

How do you use (GNU) make's "simply expanded" variables in build rules and not get the last definition?

I have a complicated set of rules I need to write to generate a rather large number of "parameterised" output files and thought that, rather than expand them all out by hand, I could repeatedly "include" a template file with sets of rules and use (GNU)make's facility for allowing "simply expanded" variables to avoid the pain.
(In the past I've always been using the "recursively expanded" variable approach, so this is new to me)
As a trivial example of what I thought would work, I tried putting the following in a Makefile
Targ:=A
Param1:=Pa
Param2:=Qa
$(Targ):
#echo expect A, get $(Targ), Target is $#. Params are $(Param1) and $(Param2)
Targ:=B
Param1:=Pb
Param2:=Qb
$(Targ):
#echo expect B, get $(Targ), Target is $#. Params are $(Param1) and $(Param2)
Targ:=C
Param1:=Pc
Param2:=Qc
$(Targ):
#echo expect C, get $(Targ), Target is $#. Params are $(Param1) and $(Param2)
The eventual plan was to replace the rules with an include file containing dozens of different rules, each referencing the various "parameter" variables.
However, what I get is...
prompt> make A
expect A, get C, Target is A. Params are Pc and Qc
prompt> make B
expect B, get C, Target is B. Params are Pc and Qc
Essentially, unlike each rule's target, which is picking up the intended definition, the $(Targ), $(Param1), and $(Param2) in each rule's command is instead being run with the final definition.
Does anyone know how to prevent this, i.e. how do you force the command to use the definition at the time it is encountered in the Makefile?
Simple vs recursive expansion makes no difference here; regardless of which you use you'll see the same behavior. A GNU make variable is global and obviously can have only one value.
You have to understand when variables are expanded. The documentation provides a detailed description of this. Targets and prerequisites are expanded when the makefile is read in, so the value of Targ as the makefile is being parsed is used.
Recipes are expanded when the recipe is to be invoked, which is not until after all makefiles are parsed and make starts to build targets. At that time of course the variable Targ has its last set value.
Without knowing what your makefile really does it's hard to suggest an alternative. One option is to use target-specific variables:
Targ := A
$(Targ): LocalTarg := $(Targ)
$(Targ):
#echo expect A, get $(LocalTarg), Target is $#
Another option is to use constructed variable names:
Targ := A
Targ_$(Targ) := $(Targ)
$(Targ):
#echo expect A, get $(Targ_$#), Target is $#
Apologies for answering my own question, but I now realised it is possible to solve the issue I was having by running make recursively.
E.g. if the parameter variables for the rules are Targ, Param1 and Param2 then
#Set up "default" values for the parameters (As #madscientist points out,
#these will safely be overridden by the defs on the #(make) commands below
Targ=XXXXXXXXXX
Param=XXXXXXXXXX
Param2=XXXXXXXXXX
Recursing=
#
# define N (==3) templated rule(s)
#
$(Targ)%a:
#echo Run Combo_a $(Targ) $(Param1) $(Param2) $#
$(Targ)%b:
#echo Run Combo_b $(Targ) $(Param2) $(Param1) reversed $#
$(Targ)%c:
#echo Run Combo_c $(Param1) $(Targ) $(Param2) mixed again $#
#
#Enumerate "M" (==2) sets of parameters,
# (Except if we are already recursing because unrecognised targets may cause
# it to descend forever)
#
ifneq ($(Recursing), Yes)
Set1%:
#$(MAKE) Targ=Set1 Param1=foo Param2=bar Recursing=Yes $#
Set2%:
#$(MAKE) Targ=Set2 Param1=ray Param2=tracing Recursing=Yes $#
endif
This then allows N*M different combos for N+M typing cost.
eg. (removing messages from make re recursion)
>make Set1.a
Run Combo_a Set1 foo bar Set1.a
>make Set2.c
Run Combo_c ray Set2 tracing mixed again Set2.c

How the location of target impacting the behaviour of makefile

I wrote a simple Makefile as below:
.PHONY: all A B
A:
#echo "in target A"
B:
#echo "in target B"
all: A B
the output is
in target A
but if I modified the Makefile as below:
.PHONY: all A B
all: A B
A:
#echo "in target A"
B:
#echo "in target B"
the output become
in target A
in target B
what part of Makefile manual should I read more carefully to understand the difference?
what part of Makefile manual should I read more carefully to understand the difference?
Which part of the manual to study depend on which make manual you are reading, but the explanation for the behavior you observe is simple: when you run make without designating any targets to build, make builds the default target, which is the first target appearing in the makefile whose name does not consist of a period ('.') followed by uppercase letters.
In particular, the target name "all" has no special significance to make. Its use is simply a widespread convention, and to make the all target work as you expect (that is, for it to be the default target), it must be positioned first in the makefile. There are makefiles that have an "all" target that is intentionally positioned elsewhere so that a different one is the default. When it's not the default, you can still build it explicitly, of course, by naming it on the command line: make all.
when running make without any goal, the first goal in out Makefile will be exectued.
You can manage the default goal using .DEFAULT_GOAL variable.
Read https://www.gnu.org/software/make/manual/html_node/Goals.html for more information

How to get all the rules in a makefile to remember the name of the top-level (wildcard) target

When I look all over the place for a simple thing and can't find it, it makes me wonder whether I'm doing something completely the wrong way. I have used frameworks where you type make targetname where targetname is not known by the makefile, so it has to pick up targetname as a makefile variable and figure out its dependencies from there. I'm trying to do that, but I can't figure out how, and apparently no one does this, because I can't find anyone talking about how to do it. They talk about everything else under the sun, but not how to get make hooplah to execute using hooplah.html as the top-level target.
A lot of searching and guessing has gotten me as far as the failing makefile below, and I'm so frustrated that here I am risking life and limb by asking a question on SO. In case it keeps me from harm, I'll mention that I've read this SO answer, and this, this, and this, as well as digging through a number of pages in the GNU makefile documentation, all to no avail.
I want to type make page-72 on the command line and get make to treat page-72.html as its top-level dependency throughout the makefile, not just in the top-level rule. The other rules need to know about page-72.html, but I can't figure out how to give them the information.
I've read about MAKECMDGOALS, but it looks like that's only useful for checking for specific target names; I'm looking for something that will allow any target name and treat it as an output filename. Below is what I have. It shows me page-72 due to the % target, and the $#.html dependency works, but no variable I have found yet allows the $#.html rule to know the name of the target that was specified on the command line.
%: $#.html
#echo "Top: dollar-at = $#"
$#.html:
#echo "html: $#, $%, $<, $?, $^, $+, $|, $*"
I get the following output:
html: .html, , , , , , ,
Top: dollar-at = makefile
Top: dollar-at = index
Am I getting this conceptually wrong? Is it just not done this way? Bonus points if anyone can help me get rid of Top: dollar-at = makefile. Cheers
Yes, you are getting it completely wrong :).
In none of the places you looked did anyone attempt to use an automatic variable such as $# in a prerequisite list as you've done above, and in fact that cannot work. Automatic variables are only set within the recipe of a rule, not within the prerequisite list.
As a result, after make expands your targets and prerequisites the $# variable is unset there and it expands to the empty string. So your rules look like this:
%: .html
#echo "Top: dollar-at = $#"
.html:
#echo "html: $#, $%, $<, $?, $^, $+, $|, $*"
Maybe that helps explain why you're getting the output you see.
In a pattern rule the stem (the part that matches the % pattern) must be the same in the target and prerequisite.
You want to write your rule like this:
%: %.html
#echo "Top: dollar-at = $#"
%.html:
#echo "html: $#, $%, $<, $?, $^, $+, $|, $*"
However, I really don't understand what you're trying to do. I don't know what you mean by a "top level dependency throughout the makefile". And I don't see, from the example you've given, how you expect make to build a x.html file.
To write a makefile, you need to create for yourself a set of steps that say: I want to build this target. To build it, it will use these prerequisites. And given those prerequisites, it will use this set of commands. Then, you repeat that recursively for any of the prerequisites that need to be built. You don't have to write rules for source files (things that don't have to be built). They already exist.
Once you have that set of steps it's pretty straightforward to turn them into makefile rules.

Target-specific variables in a makefile & prerequisites

I'm seeing unexpected results for target-specfic variables in GNU make.
What I want is to set a target-specific variable that affects dependencies. I can use .SECONDEXPANSION to achieve that.
some-target: DEP := debug-dep
debug: some-target
.SECONDEXPANSION:
some-target: $$(DEP)
#echo $^
debug-dep:
make debug prints debug-dep.
Now I read that make defines target-specific variables for descendant rules:
When you define a target-specific variable that variable value is also in effect for all prerequisites of this target, and all their prerequisites, etc.
But when I change my makefile to have the variable set on "parent" target:
debug: DEP := debug-dep
debug: some-target
.SECONDEXPANSION:
some-target: $$(DEP)
#echo $^
debug-dep:
and do make debug I get a blank line.
This seems to contradict the documented behavior of target-specific variables. Is there something that I am missing?
This is sort of similar to make: Using target specific variables in prerequisites, but what I am doing isn't working.
I believe the issue here is that target-specific variables are not set until the targets are being run (if you add #echo '$(DEP)' to your some-target body in that second case you will see that it is set) but that second expansion happens immediately after the initial read-in phase.
I was going to say that I'm actually surprised that this works in the first case at all (and speculate as to why) but then I pulled up the manual for a minute and while reading about .SECONDEXPANSION I found the following:
[T]he true power of this feature only becomes apparent when you discover that secondary expansions always take place within the scope of the automatic variables for that target. This means that you can use variables such as $#, $*, etc. during the second expansion and they will have their expected values, just as in the recipe. All you have to do is defer the expansion by escaping the $. Also, secondary expansion occurs for both explicit and implicit (pattern) rules.
Which explains your behaviour exactly. The expansion only sees variables set in the scope of the target and the prerequisite inheriting only happens at target evaluation time (since it depends on target prerequisites).
All variables are set in the first read-in phase. It is true no matter it is a global variable, or a target-specific variable (or a pattern-specific variable).
There is no such thing that is like the other answer says
target-specific variables are not set until the targets are being run
See the example Makefile below,
GA = ga
GB = $(GA)
GC := $(GA)
a: aTA = $(GA)
a: aTB := $(GA)
a: aTC = $(aTA)
a: b;
GA = ga2
b: bTA = $(aTA)
b: bTB := $(aTA)
b: bTC := $(bTA)
b:;
After the first read-in phase, all variables are set (therefore, aTB is ga, not ga2). They are as follows respectively,
GA is literal ga2
GB is literal $(GA)
GC is literal ga
aTA is literal $(GA)
aTB is literal ga
aTC is literal $(aTA)
bTA is literal $(aTA)
bTB is literal (empty)
bTC is literal (empty)
Although they are all set, they are not visible everywhere, they have scope. E.g.,
Global variables' scope is everywhere
Target-specific variables' scope is
the target's other target-specific variables
the recipe of the target
the recipes of the target's prerequisites
This is the only reason that we could see bTA is eventually expanded to ga2 if we use bTA in the target b's recipe.
the prerequisite-literal appearing in the target's rule when using .SECONDEXPANSION
This is why the 1st case in OP's question works.
The following is NOT the scope of a target-specific variable,
everywhere in the parent target
the target-specific variables of the target's prerequisites
This is why bTB and bTC are both empty.
the (sub) prerequisite-literal appearing in the rule of the target's prerequisites (whether using .SECONDEXPANSION or not)
This is why the 2nd case in OP's question doesn't work.

Resources