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

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

Related

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.

Static pattern rules in Makefiles

I was looking at Make documentation and I thought that the below would call first the little then the big target, but it stops after big with no attempts to proceed to little.
targets = bigoutput littleoutput
$(targets): %output : %
#echo Done
little:
#echo in little
big:
#echo in big
Here's the output:
in big
big > bigoutput
I thought that the static pattern rules were the answer to being able to process multiple targets by following unique prerequisites for each. What am I missing?
Thanks!!
Make's concept of the "default goal" is independent of everything else. No matter what you do, it always is only a single target.
To work around it, use all: $(targets) as the first line.
Static pattern rules are useful for a different purpose: when you have multiple generate files that have names that match the pattern, but need to be built using different rules.

GNU make empty recipe vs. no recipe

Looking at the GNU make manual, what exactly is the difference between an empty recipe and no recipe (for example see one instance in Rules without Recipes or Prerequisites)? More importantly, when should one use/avoid each of these two recipes?
In my current understanding, one should always use
target: ;
because sometimes an implicit rule could defeat one's purpose of no rule.
A given target can have only one recipe. If you declare an empty recipe then you've now given that target that recipe and it won't be searched for via implicit rules. Also if you try to give that same target another recipe, then make will complain.
"No recipe" just means you're adding more prerequisites to an existing target or, if you don't list prerequisites, you're just informing make that this is a target you're interested in. But you're not overriding any recipe lookup that make will do elsewhere.
It's definitely not true that one should always use one or the other: the one you use depends on what you're trying to achieve.
I don't know what you mean when you say defeat one's purpose of no rule so I can't respond to that... what are you trying to achieve when you say "no rule"?

Lack of recursive expansion in rule prerequisites

I have a makefile that basically looks like this:
DIRS = a
all : $(DIRS)
DIRS += b
a b:
# echo $#
I was surprised to discover that only a gets printed. Why? I thought the whole advantage of recursive expansion was that I can expand my variables in arbitrary order for convenience. Is there a way to get the behavior I want for the prerequisites of all?
The problem is that make has already expanded $(DIRS) by the time you append to it.
From 3.7 How make Reads a Makefile:
GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values, implicit and explicit rules, and constructs a dependency graph of all the targets and their prerequisites. During the second phase, make uses these internal structures to determine what targets will need to be rebuilt and to invoke the rules necessary to do so.
It’s important to understand this two-phase approach because it has a direct impact on how variable and function expansion happens; this is often a source of some confusion when writing makefiles. Here we will present a summary of the phases in which expansion happens for different constructs within the makefile. We say that expansion is immediate if it happens during the first phase: in this case make will expand any variables or functions in that section of a construct as the makefile is parsed. We say that expansion is deferred if expansion is not performed immediately. Expansion of a deferred construct is not performed until either the construct appears later in an immediate context, or until the second phase.
...
Rule Definition
A rule is always expanded the same way, regardless of the form:
immediate : immediate ; deferred
deferred
That is, the target and prerequisite sections are expanded immediately, and the recipe used to construct the target is always deferred. This general rule is true for explicit rules, pattern rules, suffix rules, static pattern rules, and simple prerequisite definitions.
You can always add prerequisites to targets.
So you could add all: b when you know what b is to add it to the prerequisite list for all.
You could also put all: at the top (for the default target selection) and then put all: $(DIRS) at the bottom to use the full DIRS value as prerequisites.
Lastly you could use Secondary Expansion to force an extra expansion phase that should do what you want here.
.SECONDEXPANSION:
all: $$(DIRS)

Makefile generator creates two files

I have a generator program that creates two version files, say ver.h and ver.cpp. My ultimate build target depends on both of these files, and the rule for building both is that one program. If I did this:
build : ver.h ver.cpp
ver.h ver.cpp :
./gen/version/program
then a parallel build could run program twice, which, while not bad is just excessive. I figure I could have them both depend on a phony target:
ver.h ver.cpp : do-version-impl
do-version-impl:
./gen/version/program
.PHONY : do-version-impl
Is that the best way to do this? It smells a little funny to have to introduce a phony rule to do this.
Using the phony target as the prerequisite is a bad idea. program will be run even if ver.* files exist, which is a false positive error.
More subtly, GNU Make is only guaranteed to update its file timestamp, if that file is a target of a rule with a recipe. So here, even though program is always run, anything that in turn depends on ver.* files might not get updated at all!
In my opinion it is best to not make up unnatural patterns for each target, but instead, go explicit:
There is a "main" file that you are generating, that is ver.cpp. Use the "no-op" recipe ; for the other one, which can be put on the same line like this:
ver.h: ver.cpp ;
ver.cpp: Makefile
./gen/version/program
This method starts with what you wrote, but adds the very important ;.
If you did not have a natural candidate for the "main" file, then in my opinion it is best to use a "sentinel":
ver.h ver.cpp: sentinel ;
sentinel: Makefile
./gen/version/program
touch $#
Again, this method is similar to one of your methods, but very importantly, does not use a phony, but a real file.
See 10.5.1 Introduction to Pattern Rules specifically the last paragraph:
10.5.1 Introduction to Pattern Rules
...
A pattern rule need not have any prerequisites that contain ‘%’, or in fact any prerequisites at all. Such a rule is effectively a general wildcard. It provides a way to make any file that matches the target pattern. See Last Resort.
...
Pattern rules may have more than one target. Unlike normal rules, this does not act as many different rules with the same prerequisites and recipe. If a pattern rule has multiple targets, make knows that the rule’s recipe is responsible for making all of the targets. The recipe is executed only once to make all the targets. When searching for a pattern rule to match a target, the target patterns of a rule other than the one that matches the target in need of a rule are incidental: make worries only about giving a recipe and prerequisites to the file presently in question. However, when this file’s recipe is run, the other targets are marked as having been updated themselves.
So you could use something like this:
v%r.h v%r.cpp:
./gen/version/program
I believe you need that odd patterning to have make consider the pattern to match (I don't believe it will match % against an empty string as ver%.h ver%.cpp would need). (I can't find reference to this in the manual at the moment though.)

Resources