GNU Make manual says, the most "specific" implicit rule is chosen, which is a good thing. Except... if there is a rule for which no implicit prerequisites are needed to be made, it is chosen even if it is more "general". See:
> touch existing
> cat Makefile
%.o: existing
#echo general
foobar%.o: foobar%.i
#echo specific
foobar%.i: ;
> rm foobar0.i
> make -r foobar0.o
general
> touch foobar0.i
> make -r foobar0.o
specific
IMHO, the most specific rule should be always chosen, regardless if there is 0 implicit prerequsites, and especially, whether such prerequisites already exist or not. But I don't want to ask "why" here.
Instead, can someone suggest to me, how to force the desired behaviour. I always want the most specific rule that applies, regardless. Is there a way to force that?
well, OK I can do this:
%.o: %.dummy
#echo general
%.dummy: ;
I just don't like this kind of thing. Is there a less ugly way.
Related
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.
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.
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".
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.
It looks to me like Makefile rules can be roughly classified into "positive" and "negative" ones: "positive" rules create missing or update outdated files, while "negative" ones remove files.
Writing prerequisites for "positive" rules is quite easy: if the target and the prerequisite are file names, make by default runs the recipe if the target is missing or outdated (a missing file in this context may be viewed as an infinitely old file).
However, consider a "negative" rule, for example for target clean. A usual way to write it seems to be something like this:
clean:
rm -f *.log *.synctex.gz *.aux *.out *.toc
This is clearly not the best way to do:
rm is executed even when there is nothing to do,
its error messages and exit status need to be suppressed with -f flag, which has other (possibly undesirable) effects, and
the fact that there were nothing to do for target clean is not reported to the user, unlike what is normal for "positive" targets.
My question is: how to write a Makefile rule that shall be processed by make only if certain files are present? (Like what would be useful for make clean.)
how to write a Makefile rule that shall be processed by make only if certain files are present? (Like what would be useful for make clean.)
You can do it like so:
filenames := a b c
files := $(strip $(foreach f,$(filenames),$(wildcard $(f))))
all: $(filenames)
$(filenames):
touch $#
clean:
ifneq ($(files),)
rm -f $(files)
endif
Example session:
$ make
touch a
touch b
touch c
$ make clean
rm -f a b c
$ make clean
make: Nothing to be done for 'clean'.
Useful perhaps for some purposes, but it strikes me as a strained refinement for make clean.
This can be easily remedied:
clean:
for file in *.log *.synctex.gz *.aux *.out *.toc; do \
if [ -e "$file" ]; then \
rm "$$file" || exit 1; \
else \
printf 'No such file: %s\n' "$file" \
fi \
done
The if statement is necessary unless your shell supports and has enabled nullglob or something similar.
If your printf supports %q you should use that instead of %s to avoid possible corruptions of your terminal when printing weird filenames.
A meta-answer is: are you sure you want to do this?
The other answers suggest to me that the cure is worse than the disease, since one involves an extension to POSIX make (ifneq), and the other uses a compound command which spreads over seven lines. Both of these are sometimes necessary expedients – I'm not criticising either answer – but both are things I avoid in a Makefile if I can. If I found myself wanting to do this in a clean rule, perhaps for the reason you mention in your comment to #MikeKinghans' answer, I'd try quite hard to change the rest of the Makefile to avoid needing this.
Reflecting on your three original points in turn:
rm is executed even when there is nothing to do: so what? The alternatives still need to, for example, expand the *.log *.synctex.gz ... so there's only miniscule efficiency gain to avoiding the rm. Make is a high-level tool which generally does not concern itself with efficiency.
its error messages and exit status need to be suppressed with -f flag: the -f flag doesn't generally suppress errors and the exit status, it merely indicates to rm that a non-existing or non-permissioned file is not to be regarded as an error.
the fact that there were nothing to do for target clean is not reported to the user: should the user really care?
The last point is the most interesting. People asking about make, on Stackoverflow and elsewhere, sometimes make things hard for themselves by trying to use it as a procedural language – make is not Python, or Fortran. Instead, it's a goal programming language (if we want to get fancy about it): you write snippets of rules to achieve sub-goals, so that the user (you, later) doesn't have to care about the details or the directory's current state, but can simply indicate a goal, and the program does whatever's necessary to get there. So whether there's is or isn't anything to do, the user ‘shouldn't’ care.
I think the short version of this answer is: it's idiomatic to keep make rules as simple (and thus as readable and robust) as possible, even at the expense of a little crudity or repetition.