Makefile : last resort match anything pattern - makefile

According to the GNU make guide, "The rules you write take precedence over those that are built in. 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."
So I wrote this testing makefile to do a little experiment (GNUmakefile is the name of this testing makefile) :
% ::
#echo "last resort implicit rule is working"
.DEFAULT_GOAL = src/hello.o
src/hello.o :
GNUmakefile : ;#used to prevent remaking this makefile, although in this case it is unnecessary.
My file organization is illustrated as the following :
GNUmakefile(#ordinary file)
src(#directory)
----hello.c(#ordinary file)
I was expecting it to output "last resort implicit rule is working", since src/hello.o will match the target pattern % :: and this is a terminal match anything implicit rule. According to the Implicit rule search algorithm specified in GNU make guide, this rule should apply.
However, when I run make , it output cc -c -o src/hello.o src/hello.c.
I figured out that in fact src/hello.o was matched against the built-in implicit rule. When I run make -r , it output "last resort implicit rule is working". And the output of make -d attested this.
But I think this behavior is contradicting what is specified in GUN make guide.
Can anyone help?
By the way, I read the last resort rule in GUN make guide, it says "So such a rule’s recipe is used for all targets and prerequisites that have no recipe of their own and for which no other implicit rule applies.". Is this the solution to my question? I doubt that, because I think this depends on whether last resort rule is defined and where the last resort rule is defined because orders matters when searching for implicit rule using the algorithm specified in GNU make guide.

It works fine with some ancient make at my workplace...
[teve#madar mktest]$ tree
.
├── GNUmakefile
└── src
└── hello.c
1 directory, 2 files
[teve#madar mktest]$ cat GNUmakefile
% ::
#echo "last resort implicit rule is working"
.DEFAULT_GOAL = src/hello.o
src/hello.o :
GNUmakefile : ;#blablabla
[teve#madar mktest]$ make
last resort implicit rule is working
[teve#madar mktest]$ make --version
GNU Make 3.81
[...]
... and it does not work with one-step less ancient make:
[teve#madar mktest]$ make
cc -c -o src/hello.o src/hello.c
[gergelyc#sauron mktest]$ make --version
GNU Make 3.82
[...]
Given that the current versions are 4.x, I feel super lucky to have exactly these two versions with the behaviour-change.
I tried to look at occurrences of implicit, built, order, last and match in a changelog ending with 3.82, but I have not found anything obvious.
Canceling the built-in rule with an empty %o : %c works, by the way.

Related

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.

Why is Make ignoring an explicit pattern rule?

I'm using GNU Make 4.0 to compile code on an IBM i system. Make is inexplicably choosing the wrong rule to build one type of object.
On this platform, program objects are built from modules, which are compiled from source code. There is also a convenience shortcut command that will create a program directly from a single piece of source code by creating a temporary module from the source code and then building a program from that. The problem I'm running into is that Make is using the shortcut command (crtbndrpg) instead of the two-step version (crtrpgmod + crtpgm), even though the target rule specifies that the program should be built from a module and not the shortcut.
There are two makefiles: a generic one that describes how to create IBM i objects, and a project-specific one that describes object dependencies for all items in this project and includes the generic one. My generic makefile looks like this (edited for simplicity):
# `IBMiMake`, a generic makefile that describes how to create IBM i objects.
OBJPATH := $(CURDIR)
override OBJPATH := $(shell echo "$(OBJPATH)" | tr '[:lower:]' '[:upper:]')
%.MODULE: %.RPGLE
$(eval crtcmd := crtrpgmod module($(OBJLIB)/$*) srcstmf('$<') $(CRTRPGMODFLAGS))
#system "$(crtcmd)" > $(LOGPATH)/$(notdir $<).log
%.PGM: %.RPGLE
$(eval crtcmd := crtbndrpg pgm($(OBJLIB)/$*) srcstmf('$<') $(CRTBNDRPGFLAGS))
system "$(crtcmd)" >$(LOGPATH)/$(notdir $<).log 2>&1
%.PGM:
$(eval crtcmd := crtpgm pgm($(OBJLIB)/$*) module($(basename $(filter %.MODULE,$(notdir $^)))) $(CRTPGMFLAGS))
system "$(crtcmd)" >$(LOGPATH)/$#.log 2>&1
The project-specific makefile looks like this (also edited for simplicity):
# `xpmake`, to create objects in this project.
ROOTDIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
IBMIMAKE := $(ROOTDIR)/../SDE/IBMiMake
include $(IBMIMAKE)
# AB2001.B.MODULE -- CRTRPGMOD
AB2001.B.MODULE: AB2001.B.RPGLE
# AB2001.B.PGM -- CRTPGM
AB2001.B.PGM: AB2001.B.MODULE
To build the object in question:
bash-4.2$ make AB2001.B.PGM OBJPATH:='/qsys.lib/xp33make.lib' -f xp33make/xpmake -d --no-builtin-rules
What should happen: It should first create the module using the crtrpgmod command, which it does. It should then create the program using the crtpgm command. Instead of creating the program via crtpgm, however, it for some reason tries to use the crtbndrpg command to directly build the program from source code. The only thing I can think of is that perhaps Make is seeing AB2001.B.MODULE as an intermediate file and opting to bypass the crtrpgmod step. Could this be true? How do I get make to follow my rules and not try to overthink things?
Here is the output:
GNU Make 4.0
Built for powerpc-ibm-aix5.3.0.0
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile 'xp33make/xpmake'...
Reading makefile '/home/SMEEP/Source/xp33make/../SDE/IBMiMake' (search path) (no ~ expansion)...
Updating makefiles....
Considering target file '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
Looking for an implicit rule for '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
No implicit rule found for '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
Finished prerequisites of target file '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
No need to remake target '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
Considering target file 'xp33make/xpmake'.
Looking for an implicit rule for 'xp33make/xpmake'.
No implicit rule found for 'xp33make/xpmake'.
Finished prerequisites of target file 'xp33make/xpmake'.
No need to remake target 'xp33make/xpmake'.
Updating goal targets....
Considering target file 'AB2001.B.PGM'.
File 'AB2001.B.PGM' does not exist.
Looking for an implicit rule for 'AB2001.B.PGM'.
Trying pattern rule with stem 'AB2001.B'.
Trying implicit prerequisite 'AB2001.B.CLLE'.
Trying pattern rule with stem 'AB2001.B'.
Trying implicit prerequisite 'AB2001.B.RPGLE'.
Found an implicit rule for 'AB2001.B.PGM'.
Considering target file 'AB2001.B.RPGLE'.
Looking for an implicit rule for 'AB2001.B.RPGLE'.
No implicit rule found for 'AB2001.B.RPGLE'.
Finished prerequisites of target file 'AB2001.B.RPGLE'.
No need to remake target 'AB2001.B.RPGLE'; using VPATH name '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'.
Considering target file 'AB2001.B.MODULE'.
Looking for an implicit rule for 'AB2001.B.MODULE'.
Trying pattern rule with stem 'AB2001.B'.
Trying implicit prerequisite 'AB2001.B.C'.
Trying pattern rule with stem 'AB2001.B'.
Trying implicit prerequisite 'AB2001.B.CLLE'.
Trying pattern rule with stem 'AB2001.B'.
Trying implicit prerequisite 'AB2001.B.RPGLE'.
Found prerequisite 'AB2001.B.RPGLE' as VPATH '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'
Found an implicit rule for 'AB2001.B.MODULE'.
Pruning file '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'.
Pruning file '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'.
Finished prerequisites of target file 'AB2001.B.MODULE'.
Prerequisite '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE' is older than target 'AB2001.B.MODULE'.
Prerequisite '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE' is older than target 'AB2001.B.MODULE'.
No need to remake target 'AB2001.B.MODULE'; using VPATH name '/QSYS.LIB/XP33MAKE.LIB/AB2001.B.MODULE'.
Finished prerequisites of target file 'AB2001.B.PGM'.
Must remake target 'AB2001.B.PGM'.
system "crtbndrpg pgm(XP33MAKE/AB2001.B) srcstmf('/home/SMEEP/Source/xp33make/AB2001.B.RPGLE')" >/home/SMEEP/Source/xp33make/Logs/2016-11-14_11.42.55-Mon/AB2001.B.RPGLE.log 2>&1
Putting child 30016df0 (AB2001.B.PGM) PID 1155363 on the chain.
Live child 30016df0 (AB2001.B.PGM) PID 1155363
Reaping losing child 30016df0 PID 1155363
/home/SMEEP/Source/xp33make/../SDE/IBMiMake:476: recipe for target 'AB2001.B.PGM' failed
Removing child 30016df0 PID 1155363 from chain.
Your example is still difficult to read: creating a minimal example is usually best (that is, construct an example that uses touch etc. to create files, and doesn't depend on your environment).
Also, the use of $(eval ...) inside the recipe to create a make variable assignment is a bit confusing. Don't think that just because you do this in the recipe there's some kind of scoping involved: those variables are still globally assigned.
In any event, the problem is that you have two ways to build a target that matches %.PGM:
%.PGM: %.RPGLE
%.PGM:
You apparently want to use the second one, but if the stem of a matching pattern rule is has equal length (here both have the same stem, .PGM) then make will always choose the first pattern that you define so it will always choose the first one if it can.
So, it will always use crtbndrpg to build that target, as long as make can figure out how to build %.RPGLE, so that pattern rule will match.
I'm not sure if they're omitted in the simplifying process, but your explicit rules lack their recipes.
Pattern rules with no recipe mean canceling any existing implicit rules.
https://www.gnu.org/software/make/manual/html_node/Canceling-Rules.html

a surprising (?) behaviour of GNU Make when using ``%`` as target

Consider the following Makefile
foo:
#echo '$#'
test:
#echo '$#'
#echo '---'
# Catch-all target
%: test
#echo '+++'
#echo '$#'
When issuing make bar the following is the console output:
$ make bar
test
---
+++
Makefile
+++
bar
I would like to understand the origin of Makefile which shows it is received as argument at some point, and also how to get rid of it in such a scheme. This is using
GNU Make 4.1
Built for x86_64-apple-darwin13.4.0
GNU make treats the makefile itself as a target that needs to be updated. See How Makefiles Are Remade:
... after reading in all makefiles, make will consider each as a goal target and attempt to update it. If a makefile has a rule which says how to update it (found either in that very makefile or in another one) or if an implicit rule applies to it (see Using Implicit Rules), it will be updated if necessary...
If you know that one or more of your makefiles cannot be remade and you want to keep make from performing an implicit rule search on them, perhaps for efficiency reasons, you can use any normal method of preventing implicit rule look-up to do so. For example, you can write an explicit rule with the makefile as the target, and an empty recipe (see Using Empty Recipes).
Hence, the catch-all-target % is used to update Makefile.
Makefiles often do not have to be updated, so it is customary to add an empty rule for that:
Makefile : ;

How to makefile parse

At the make manual said:
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.
I don't understand how the dependency graph constructed? Consider the following makefile:
%.o: %.z
echo This is overriden implicit rule
default: foo.o
clean:
rm -f fmake test_second
%.o: %.c
echo This is customized implicit rule
After make command
echo This is customized implicit rule
This is customized implicit rule
is displayed, but I'm expexted that
echo This is overriden implicit rule
This is overriden implicit rule
will be, because in make rule only overrides if both the target and the prerequisite patterns match. In this case I think that %.o: %.z implicit rules matched to pattern already.
I've been doing a lot of work with Makefiles in a very, very large codebase for the last year or so. I am heartily sick of make(1s)!
The answer, in general, is "last declaration wins". You also have to contend
with the default make suffix rules (on Solaris these are found in /usr/share/lib/make/make.rules).
So if you want your overridden implicit rule to stand, place it last in the
Makefile hierarchy. If you want to flush the suffixes list, you can do either
or both of
1 add a .SUFFIXES:
line to your Makefile,
2 call make with -r
in MAKEFLAGS (env var) or on the make invocation command line.
[Also, you can prepend "#" to the start of your command to just see the output
of it, rather than the
echo [output goes here]
as well as the actual
[output goes here]
You could also gather insight by using one of the debugging options that
make(1s) allows. On Solaris, that's -d, -dd, -D or -DD. For GNU Make, it's
-d or --debug. Caution, though, dump the output from the command to a file,
because there is a lot of it.
You might want to read http://freecode.com/articles/what-is-wrong-with-make, as a piece of on-the-side illumination.

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