GNU make: variables in pattern rules - makefile

How variables are expanded in pattern rules and static pattern rules? Patterns are matched using global variable values, but recipes can use target specific and pattern specific variable values. Did I get it right?
Thanks.

I think the manual is quite clear on this; at least for target-specific variables, but the way I understand it, it works the same for pattern-specific variables. It states (on target-specific variable values):
these values are only available within the context of a target's recipe
So they are not used in the patterns, but only in the recipes.

Related

Variable assignment in Makefile Prerequisites

I'm looking through the Linux kernel code to try and understand how the image is built.
In the scripts/makefile.build Makefile, there are some lines that look like this:
$(real-objs-m) : part-of-module :=y
$(real-objs-m) : quiet_modtag := [M]
$(multi-objs-m) : modname=$(modname-multi)
They don't look like target-and-prerequisites lines nor static pattern rules.
I've been already googled a lot, but nothing seems an answer.
What do these syntaxes mean?
This is target-specific variable values.
From the documentation https://www.gnu.org/software/make/manual/html_node/Target_002dspecific.html
This feature allows you to define different values for the same variable, based on the target that make is currently building. As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).
There is one more special feature of target-specific variables: 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. (unless those prerequisites override that variable with their own target-specific variable value).

Makefile rule with no target

I'm debugging a makefile, and in a macro expansion it creates a rule with no target (as so:)
: | directoryA
#echo running $#
...
I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.
With my current version of make (gnu Make 4.2.1), it's not killing me, but I'm just wondering whether this is considered undefined behavior or whether this is supported, and if so, what it should do.
I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.
Different makes may behave differently. They may even exhibit variant handling of specific makefile syntax matters depending on the content of the makefile -- for example, a makefile may be interpreted differently if it starts with a rule for the .POSIX: special target than an otherwise identical makefile without that rule is interpreted.
Overall, however, if you want some sort of general idea of what should be considered correct then the POSIX standard's defintion of make is a reasonably good baseline. It says:
Target rules are formatted as follows:
target [target...]: [prerequisite...][;command]
[<tab>command<tab>command...]
line that does not begin with <tab>
Target entries are specified by a <blank>-separated, non-null list of
targets, then a <colon>, [...]
(emphasis added). It furthermore goes on to say that
Applications shall select target names from the set of characters
consisting solely of periods, underscores, digits, and alphabetics
from the portable character set
, from which we can infer that the syntax description is talking about the rule text after macro expansion, since macro references can appear in the target lists of rules (or literally anywhere in a makefile, per the spec), but the characters $, (, ), {, and } appearing in macro references are not among those that can appear in targets.
That specification of makefiles' expected contents does explicitly state that target lists are non-empty, and it is reasonable to treat it as authoritative where your specific make's documentation does not override it.
I'm just wondering whether [an empty target list] is considered undefined behavior or
whether this is supported
Your combination of makefile and runtime macro values does not conform to the requirements of POSIX make. The spec does not define what should happen in this case, so in that sense the behavior is undefined, but "undefined behavior" isn't as strong a concept in this area as it is in, say, the C and C++ language specifications.
In view of that, I would account it a makefile flaw for any rule's target list to be empty (after macro expansion). Although the make you are presently using may accept it without complaint, other makes, including future versions of your present make, may reject it or worse.
Rule does expect one or more targets, there really are no two ways about it in the docs. For instance GNU make docs notation:
targets : prerequisites
recipe
Or 1p section manpage:
target [target...]: [prerequisite...][;command]
Illumos:
target [:|::] [dependency] ... [; command] ...
[command]
...
After all how would you refer to a target that had no name? I would assume no target rule should be an error...
However, I've tried different flavors of make (BSD, Illumos, GNU) and with varying degree of leniency (GNU make for instance seemed to also not care about syntax of prerequisites any more) or lack thereof they all seemed to have processed the line and possibly following tab indented block as a rule (with a recipe)... which then was ignored (also for the purpose of determining the default target).
I guess a rationale for this actually being consider valid Makefile... you could end up in this situation also with:
$(VAR):
#echo foobar
other:
#echo barbaz
In case VAR is undefined or empty, you'd end up with a such empty target as well.

GNU Make recursively expanded variables examples

Could somebody provide a real-world example of using recursively expanded variables (REV)? In the docs or various blog posts people give only useless toy examples, like
foo = $(bar)
bar = $(ugh)
ugh = Huh?
I cannot find a real use for REV besides creating custom functions with $(call). I also found that in the past people were using REV to supply additional parameters to a compiler for specific targets but that trick is considered outdated now because GNU Make has target-specific variables.
Both recursively expanded variables and simply expanded variables recurse their expansions. The major difference is when that expansion happens.
So your example above works just fine with simply expanded variables if you invert the assignments:
ugh := Huh?
bar := $(ugh)
foo := $(bar)
So the major thing that recursively expanded variables get you is the freedom to assign values in whatever order you need (which means you don't need to worry about inclusion order for included makefiles, etc.).
In a project at work we have a dozen or so included makefiles that have inter-dependent relationships. These are expressed through the usage of known-format variable names (e.g. module A generates an A_provides variable, etc.) Modules that need to utilize the things that module A provides can then list $(A_provides) in their makefiles.
With simply expanded variables (which we had been using until somewhat recently) this meant that the inclusion of the generated makefiles required a manually sorted order to force the inclusion of assigning makefiles before consuming makefiles (into other variables).
With recursively expanded variables this order does not matter. (This would not be the case if the variables were used in any immediately evaluated context in these makefiles but luckily they are not, they only set variables that are used later in the main makefiles.)
Well, one simple example are variables which contain commands for recipes; perhaps:
buildc = $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
%.o: %.c
$(buildc)
I probably wouldn't write a compile rule like this this way, but if you have a much more complex recipe it can be very useful.
Personally I don't consider "additional parameters ... for specific targets" (by which I assume you mean recursively defined variables such as $($*_FLAGS)) to be outdated or obsoleted by target-specific variables, by any stretch. If nothing else recursively defined variables are much more portable than target-specific variables.
It just means that recursively defined variables are set at the time of definition only!
The best example I can find is this
x := foo
y := $(x) bar
x := later
and is equivalent to
y := foo bar
x := later

Make Variables from Parent Shell Script

In a makefile I'm reading, there are many references to a variable, projdir, defined and exported in the shell script that calls make; there are many instances of $(projdir) in the makefile.
From the make manual at http://www.gnu.org/software/make/manual/make.html#Reference, there are only two types of variables: recursively expanded variables and simply expanded variables. It seems projdir is neither one.
Question 1: Since the makefile works, it must be true that makefiles can access shell variables defined in the parent shell environment. Why is this not documented (or perhaps I did not find the correct documentation)?
Question 2: Unrelated to question 1, I see in Section 6.2 the line all:;echo $(foo). Why is the semicolon ; needed here?
Question 1. Environment variables automatically become make variables. This is explained in section 6.10:
Variables in make can come from the environment in which make is run. Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value.
Question 2: Putting a semicolon after a rule name and optional prerequisites allows you to start the recipe on the same line. This is explained in section 4.2:
The first recipe line may appear on the line after the prerequisites, with a tab character, or may appear on the same line, with a semicolon.
They used this syntax in the example in 6.2 for brevity, so they could show the whole rule inline in the sentence; I think it's rarely used in practice.
From the make manual:
Variables in make can come from the environment in which make is run. Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value.
As to your second question:
Why is the semicolon ; needed here?
Without the semicolon the right-hand side of : would specify the list of dependencies. The semicolon terminates that (empty) list.
Variables have both a flavor and an origin.
Expansion type is a flavor.
make contains a flavor function which can be used to find the type of variable in question. It will return one of undefined, recursive or simple.
Variables also have an origin which is where their value has come from. What you are seeing here is one of those possible origins.
The origin function will tell you the origin of a variable.
There are seven possible origins: undefined, default, environment, environment override, file, command line, override and automatic.
So your projdir variable has a flavor of simple and an origin of environment.

Can I have more than one % sign in a makefile target?

So I have a makefile with a target dependency like this:
all: $(foreach lang, $(LANGS), $(foreach models,$(MODELS),targetName$(model).xml$(lang)))
and the targetName target looks like this:
targetName%.xml%: MODEL\=% targetName.xml*
But it doesn't work. I get this error:
make[1]: *** No rule to make target `targetNameMYMODEL.xmlen', needed by `all'. Stop.
however, calling 'all' with a hardcoded language in the targetName target like this works:
all: $(foreach lang, $(LANGS), $(foreach models,$(MODELS),targetName$(model).xmlen))
and calling 'all' without the language in either all or targetName works fine as well. I'm thinking perhaps Makefile doesn't like having two percent signs in the target name.
Also, since I sort of inherited this makefile, can someone tell me what that MODEL\=% means? There is another target that looks like this: MODEL%: ; but i'm not sure what the \=% means.
Edit:
So to clarify further based on this reponse:
I have a list of, say, 5 Models and a list of say 5 Languages, the goal is to generate 25 files, one for each combination of languages and models.
targetName%.xml target would originally build a file called targetName.xml but now I need it to build something like targetName.xml That's why I needed the two % signs.
I'm cycling through these two lists with a nested foreach as shown above, but I'm having a hard time passing those variables around to targets. I've tried exporting the language variable from the foreach statement, I've tried putting the contents of the targetName%.xml in a for loop to loop through the languages there. The latter doesn't work because there are Makefile commands (like eval for example) in the 'do' portion of the loop.
You're right, Make doesn't like two % symbols in the target name. That's just one of the ways in which Make's wildcard handling isn't all one might wish for. There is a way to generate all of the pattern rules iterating over the values of one variable (and using % for the other) automatically; it's a little ugly, but if that's what you want we can show you.
But this line is a mess:
targetName%.xml%: MODEL\=% targetName.xml*
Apart from the problem of two wildcards in the target, the last preq, targetName.xml* will mean exactly that: a target (or file) called targetName.xml*. The asterisk will not be expanded, not to a list of all existing files that start with targetName.xml, or anything else.
Then there's MODEL\=%, which indicates that the author of this makefile was a little confused (and didn't believe in testing). If the value of the wildcard is foo, then this will indicate a prerequisite which is a target (or file) named MODEL=foo. The \ "escapes" the =, so that Make will not abort, but that is simply suppression of a healthy error message. I think what the author had in mind was something like this:
targetName%.xml: MODEL=%
targetName%.xml: $(wildcard targetName.xml*)
do some things
The first rule is not specifying a prerequisite, it is setting a target-specific variable. So when Make tries to build targetNamefoo.xml by doing some things, the variable MODEL will have the value foo in the context of that command. The second rule has a preq list, generated by wildcard; you can't mix target-specific variables and preqs in one line.
We can give further advice, but it would help if we could see a little more clearly what you're trying to do.
Worth noting the official documentation on the matter:
10.5 Defining and Redefining Pattern Rules
You define an implicit rule by writing a pattern rule. A pattern rule looks like an ordinary rule, except that its target contains the character % (exactly one of them). The target is considered a pattern for matching file names; the % can match any nonempty substring, while other characters match only themselves. The prerequisites likewise use % to show how their names relate to the target name.
Thus, a pattern rule %.o : %.c says how to make any file stem.o from another file stem.c.
Note that expansion using % in pattern rules occurs after any variable or function expansions, which take place when the makefile is read. See How to Use Variables, and Functions for Transforming Text.
Source: https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html

Resources