GNU Make -- Pattern-Matched Dependencies - makefile

Let the file "prefix-hi.c" being present in the current directory ("> touch prefix-hi.c"). Then, create the following Makefile:
prefix-%.o: prefix-%.c prefix-%-generated.c
#echo Specific Rule
%.o: %.c
#echo General Rule
prefix-%-generated.c:
touch prefix-$*-generated.c
Making in two steps gives the sequence
> make prefix-hi-generated.c
touch prefix-hi-generated.c
> make prefix-hi.o
Specific Rule
Deleting the generated file and trying to build in one step results in
> rm -f prefix-hi-generated.c
> make prefix-hi.o
General Rule
That is, GNU Make does not recognize the opportunity to build "prefix-hi-generated.c" from the last rule. Adding an explicit rule
prefix-hi-generated.c:
touch prefix-hi-generated.c
changes everything. Now the one-step sequence results in
> rm -f prefix-hi-generated.c
> make prefix-hi.o
touch prefix-hi-generated.c
Specific Rule
From my angle, this behavior seems quirky.
Is there a rational explanation for things being the way they are?
How could one force GNU Make to apply the 'Specific Rule' for files starting with "prefix-" without using explicit rules?

This is explained fully in the GNU make manual
Specifically:
Note however, that a rule whose prerequisites actually exist or are mentioned always takes priority over a rule with prerequisites that must be made by chaining other implicit rules.
This is an explicit exception to the general rule that the most narrowly matching (shortest stemmed) rule will always be caused to match. The reason your last example works how you like, is because it isn't a pattern matching based rule at all so is checked before pattern matching is resolved.

Related

GNU Make: Ensure existence of prerequisite and disable implicit rule search

Question:
How can I disable implicit rule searches on a prerequisite while still ensuring that the prerequisite actually exists?
Background:
Consider the following initial Makefile:
b: a
#echo MAKING B
cp a b
a is a file which is required in order to make b. If the file a exists, make b runs successfully. If it doesn't exist, we obtain the following error:
make: *** No rule to make target `a', needed by `b'. Stop.`
This is exactly what we expected, however on inspecting the output of make --debug=a b, we see that even when a exists, make is searching through pre-defined implicit rules fitting a in order to see whether it can be re-made. For example, if the file a.c happened to exist, then make would try to compile a.c to produce the file a. To prevent this, we define an explicit rule for a with an empty recipe. This gives us the updated Makefile:
a: ;
b: a
#echo MAKING B
cp a b
The problem now is that the recipe for make b runs even if a does not exist, which results in a failure. Is there any other way to indicate that a should exist, while not searching for implicit rules to build a? I would like to do this without giving a recipe for a which checks its existence.
I'll try to sum up state of our discussion so far. Perhaps someone still pop's up with another/better insight.
Besides the option also mentioned in the question itself (see bellow for explainer on latest iteration for this approach):
a:
$(error missing file "$#")
b: a
#echo MAKING B
cp a b
In theory it should be possible to disable implicit pattern rule altogether or for specific (set) of target(s) by either defining a no recipe target rule (% : %.c) or defining a static pattern rule (a: % : %.c). Nonetheless the resulting behavior, in case there is an a.c file, seems to be the same as with an empty rule for a:. I.e. make b just proceeds without file a being present (and we'd later fail trying to access it).
Since at least some of the implicit rule seem to be implemented as suffix rules, it's possible to disable consideration of inputs like a.c by purging list of default suffices:
.SUFFIXES:
Or inhibit use of implicit built-in rules altogether by invoking make with -r (or --no-builtin-rules) option. These however are rather heavy handed as they impact processing of all the rules across the Makefile.
To work the comment in:
as mentioned disabling couple of the built in rules for C compilation would appear to yield the desired result, namely:
% : %.c
% : %.o
Would result with a.c present and no a in make: *** No rule to make target 'a', needed by 'b'. Stop.
However (like -r) it's rather intrusive as in all other targets relying on the implicit rule would be impacted. While at the same time it's not as very far reaching, because it does not cover other cases like a.C, a.cpp, a,v,...
Static rule should be able to replace pattern rules where applicable (a more specific rule being applied over the more generic one when matching). But indeed limiting its to a single target does basically put it on par with just a specific a: rule.
I am actually not sure what the rest of the tree looks like and what all possible build steps could occur. With current understanding I would still gravitate to explicit target with file existence check should files with colliding names be a possibility and concern.
Explanation for the latest version of simple failing rule:
As #Stein followed up on the topic, he actually very helpfully pointed out: Simple (always) failing rule for "building" a is perfectly sufficient. If a file of that name (a) exists, the rule for target a never gets to run its recipe. For the case the file is not there, we can just have a recipe that fails with an error message.

Why does GNU Make have a default rule to create file.out from file?

If you read the Catalog of Rules section of the GNU Make manual, it turns out that one of the suffixes that it recognizes is .out and there is a built-in rule:
%.out: %
# commands to execute (built-in):
#rm -f $#
cp $< $#
This means that if you have a file xyz in a directory, you can create xyz.out by simply typing make xyz.out.
My question is (two variants of the same question):
Who benefits from this rule?
In what circumstances is this used by people?
Obviously, I'm asking because I managed to run foul of the rule. I had some rules like:
test.01: ${PROGRAM} ${DRIVER} test.01.tst test.01.out ${DATA.01}
${DRIVER} ${D_FLAGS} $#
where the name test.01 is a phony target, but one of the dependencies is test.01.out. When actively run (not using make -n; that works fine), this gives me lots of errors like:
make[1]: Circular test.01 <- test.01.out dependency dropped.
I also tried dropping the .out suffix with:
.SUFFIXES:
.SUFFIXES: .sh
and that didn't seem to neuter the .out rule like I expected. Is that an expected feature of GNU Make?
I guess I'm going to have to work around this bug feature of GNU Make by changing my suffix to .req or something similar, but it is a nuisance and I'm left puzzled about why the .out rule is part of the standard GNU Make rule set.
I don't know the answer to your questions about the use of this rule. All I can say is that this rule already existed when GNU make was first checked into source control, in Jan 1992. It's not mentioned in any ChangeLog so probably it dates back to the very earliest versions.
The actual rule is defined as a pattern rule, so changing .SUFFIXES won't help. To get rid of it you can use:
%.out : %
(no recipe) which will delete the pattern rule.

Prioritizing pattern rules in Make

I have (roughly) this Makefile:
.PHONY: all
.SUFFIXES:
OUT = /www/web
all: $(OUT)/index.html
# rule 1
%.html: %.in
build_html $< $#
# rule 2
$(OUT)/%: %
cp $< $#
This Makefile has a problem, since there are two different ways to build $(OUT)/index.html:
build ./index.html (rule 1), then copy it to $(OUT) (rule 2).
copy ./index.in to $(OUT) (rule 2), then build $(OUT)/index.html (rule 1).
I want make to always prefer option 1. How can I indicate that there is a preferred order between these two pattern rules?
(I can think of a few hacky ways to accomplish it for this particular case, but I want a solution that is as general as possible---for instance, changing the pattern of rule 2 to $(OUT)/%.html: %.html will fix the problem, but loses generality since I need to repeat myself if I want to handle other kinds of files in the same way later.)
A quote from the GNU Makefile Manual:
It is possible that more than one pattern rule will meet these criteria. In that case, make will choose the rule with the shortest stem (that is, the pattern that matches most specifically). If more than one pattern rule has the shortest stem, make will choose the first one found in the makefile.
So, you can try to create rules which ensure shorter stems to take priority. Alternatively, you could use static pattern rules to limit the scope of what gets copied where, as so:
%.html: %.in
build_html $# $<
$(expected_out) : (OBJS)/% : %
cp $# $<
and then prepopulate $(expected_out) with what you want in there. Finally, you can add:
$(OUT)/index.html : index.html
somewhere in your makefile, as make prefers the 'shortest path' to building an object, which would only be one pattern rule in this case.
While #John's answer best fits my use-case (I know exactly what files belong in $(OUT)), there is also an alternative solution: mark the desired intermediate file as "precious".
.PRECIOUS: index.html
This will also instruct Make not to delete index.html, which it would otherwise do for you.
This works thanks to Make's algorithm for choosing implicit rules. Make favors rules whose dependencies exist or ought to exist, and a file "ought to exist" if it has an explicit rule or is a dependency of another rule. This applies even if it is a dependency of a special target like .SECONDARY, .INTERMEDIATE, or .PRECIOUS. For more info, also see the manual section on "Chains of Implicit Rules".

Special case pattern rules in Makefile

I have a generic rule for files with a given extension, but I want to add special cases for files with a prefix. I tried this:
special-%.dat: special-%.raw
echo "Running rule 1"
%.dat:
echo "Running rule 2"
but when I run make special-1.dat, it ignores the first rule and runs the second. Switching the order of the rules makes no difference. How can I fix this?
Does the file special-1.raw exist? If that file doesn't exist (and you have no rule that can create it) make will never choose this rule because the prerequisite is not available. That's not an error in itself: only if make can find NO rule that can build this target will it fail.
Running make -d will show you exactly how make is considering every target and its prerequisites, recursively.

gnumake and pattern rules

I'm using GNUmake to generate a deployment version of some web content from a source directory. I want to be rules that will run some files through compression tools (e.g. YUI compressor), and then for anything that doesn't have a rule, just copy it.
So for example:
# Rule with all the $(WWW_OUT_DIR)/*.* files as a prerequisite
all: $(WWW_OUT_FILES)
# Generic rule to perform compression on Javascript files.
$(WWW_OUT_DIR)/%.js: $(WWW_SRC_DIR)/%.js
$(YUI_COMP) $(YUI_COMP_OPTS) $< > $#
# Generic rule to perform compression on CSS files.
$(WWW_OUT_DIR)/%.css: $(WWW_SRC_DIR)/%.css
$(YUI_COMP) $(YUI_COMP_OPTS) $< > $#
# TDB Rule to magically handle everything else? (This doesn't work)
$(WWW_OUT_DIR)/%.%: $(WWW_SRC_DIR)/%.%
cp $< $#
How do I accomplish what that last rule is trying to do? I.e. For everything in $(WWW_OUT_FILES) that's not a .js or .css, just copy it? If possible, I want to retain the dependency on the corresponding input file.
You are almost right, the only thing to fix is the last pattern rule, just remove redundant percent symbol:
$(WWW_OUT_DIR)/%: $(WWW_SRC_DIR)/%
cp $< $#
Also keep in mind that as of GNU Make 3.82 pattern search algorithm has been modified a bit (from Changelog):
The pattern-specific variables and pattern rules are now applied in the
shortest stem first order instead of the definition order (variables
and rules with the same stem length are still applied in the definition
order). This produces the usually-desired behavior where more specific
patterns are preferred.
It is exactly what you want in case if you use the most recent version of Make. In order to get your Makefile compatible with other versions of GNU Make (including versions earlier than 3.82), the rule must be defined after other ones (as in the original question).
UPD.
A good example from here:
Prior to version 3.82, when gmake finds multiple matches during a pattern search, it prefers patterns declared earlier in the makefile over patterns declared later. As of 3.82, gmake instead prefers the pattern that results in the shortest stem. That sounds a bit confusing thanks to the jargon, but I think this will actually cause gmake to better adhere to the principle of least astonishment. Here’s an example:
all: sub/foo.x
%.x:
#echo "Prefer first match (stem is $*)."
sub/%.x:
#echo "Prefer most specific match (stem is $*)."
Compare the output from gmake 3.81 and 3.82:
gmake 3.81
Prefer first match (stem is sub/foo).
gmake 3.82
Prefer most specific match (stem is foo).
gmake 3.82 prefers the second pattern because it is a more specific match than the first. Note that this is a significant backwards-incompatibility compared with previous versions of gmake!

Resources