make SECONDEXPANSION broken by implicit rule recursion? - makefile

I'd like to use .SECONDEXPANSION: as described on http://make.mad-scientist.net/secondary-expansion. I have the following makefile:
.SECONDEXPANSION:
x.deps := y.foo
%.foo: $$($$*.deps)
echo $#
Unfortunately, when I try make x.foo, I get
make: *** No rule to make target `.foo'. Stop.
Running it with -Rd, I get
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
Reading makefiles...
[...]
Updating goal targets....
Considering target file `x.foo'.
File `x.foo' does not exist.
Looking for an implicit rule for `x.foo'.
Trying pattern rule with stem `x'.
Trying rule prerequisite `y.foo'.
Trying pattern rule with stem `x'.
Trying rule prerequisite `y.foo'.
Looking for a rule with intermediate file `y.foo'.
Avoiding implicit rule recursion.
No implicit rule found for `x.foo'.
Finished prerequisites of target file `x.foo'.
Must remake target `x.foo'.
make: *** No rule to make target `x.foo'. Stop.
I guess it's not working because, according to the docs, "No single implicit rule can appear more than once in a chain." But that's exactly what I need -- for x.foo to resolve to y.foo, which resolves to a rule with no dependencies. My application demands the uniform (*.foo) naming scheme. Can anyone suggest a work-around? BTW, unfortunately, I must use make 3.81, not something more recent.

Related

Multiple stems (%) in a Makefile prerequisite

I'm trying to use the following Makefile to create the target foo.a with foo.foo.b as a prerequisite, using the stem character (%) as shown.
%.a: %.%.b
touch $#
However running touch foo.foo.b; make foo.a doesn't work with No rule to make target. The debug output below shows that the stem % is only expanded once. How to get the desired behavior of replacing all % in the prerequisite?
Considering target file 'sdf.a'.
File 'sdf.a' does not exist.
Looking for an implicit rule for 'sdf.a'.
Trying implicit prerequisite 'sdf.%.b'.
Looking for a rule with intermediate file 'sdf.%.b'.
Avoiding implicit rule recursion.
Trying pattern rule with stem 'sdf.%.b'.
Trying implicit prerequisite 'sdf.%.b,v'.
(..)
No implicit rule found for 'sdf.a'.
Finished prerequisites of target file 'sdf.a'.
Must remake target 'sdf.a'.
make: *** No rule to make target 'sdf.a'. Stop.
Side note: this seems like a trivial question but for some reason I can't find the answer, maybe I'm using the wrong search terms or overlooking something simple, sorry if that is the case.
The stem is only replaced once. If you wish to have stem contents inserted more than once, you would need to use secondary expansion, i.e.:
$ cat Makefile
.SECONDEXPANSION:
%.a: $$*.$$*.b
echo Making $# from $<
Output:
$ touch foo.foo.b
$ make -s foo.a
Making foo.a from foo.foo.b

GNU make - implicit rule is not used, but static pattern rule is

Consider the following makefile (and any hi.c):
.PHONY: analyze-%
hi: hi.c
gcc -o $# $<
%.json: %
touch $# # actually created by analysis-tool
analyze-%: %.json # why does this not work?
As my comment in the makefile points out, the implicit rule does not work:
$ make analyze-hi
make: *** No rule to make target 'analyze-hi'. Stop.
It only works after transforming it into a static pattern rule:
...
analyze-hi: analyze-%: %.json
Why is this the case? Shouldn't make be able to figure this out on its own, without me having to explicitly write the full target name? There is no ambiguity or anything (as far as I'm aware).
Pattern rules must have recipes. If they don't have a recipe then they're not creating a pattern rule, they're canceling one.
See https://www.gnu.org/software/make/manual/html_node/Canceling-Rules.html
A static pattern rule, contrary to what's implied by its name, is not actually creating an implicit rule (pattern or suffix rule). It's creating explicit rules, just based on a pattern. Explicit rules don't have to have recipes.

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

Why does make ignore this rule, and trigger an implicit one instead?

I have the following rule in my makefile:
$(TESTDIR)/%.test.out:$(TESTDIR)/%.test $(TESTDIR)/%.in
$< < $(patsubst %.out, %.in, $#) 2>&1 > $#
I expect that, when I invoke make
make testing/Candidate.test.out
(where TESTDIR=testing in the makefile), make should respond with
testing/Candidate.test < Candidate.test.in 2>&1 >Candidate.test.out
Instead, make responds with
cp testing/Candidate.test testing/Candidate.test.out
and make -d yields:
Considering target file 'testing/Candidate.test.out'.
File 'testing/Candidate.test.out' does not exist.
Looking for an implicit rule for 'testing/Candidate.test.out'.
Trying pattern rule with stem 'Candidate'.
Trying implicit prerequisite 'testing/Candidate.test'.
Trying implicit prerequisite 'testing/Candidate.in'.
Trying pattern rule with stem 'Candidate.test'.
Trying implicit prerequisite 'testing/Candidate.test'.
Found an implicit rule for 'testing/Candidate.test.out'.
Building with make -r:
make -r testing/Candidate.test.out
make: *** No rule to make target 'testing/Candidate.test.out'. Stop.
indicates that make is decidedly not recognizing my rule, but I can't see why not. Clearly make believes $(TESTDIR)=testing, based on the cp output. Clearly it also recognizes testing/Candidate.test.out as a valid target, because it attempts to build it (whereas it fails for testing/blah.test.out).
Is there something obvious I'm missing here?
One of the targets in the rule (%.in) is incorrect (should be %.test.in).

Ensuring a prerequisite exists for a pattern rule

I understand that an "explicit" pattern rule will take precedence on its implicit counterpart when its prerequisites can be made.
all: src/foo.o
src/%.o: makefile my_haeder.h src/%.c
echo Do something with those source files
If there is a typo for "my_header.h", the implicit rule for %.o will take precedence. Not only my recipe will not be executed, but touching the prerequisites will not trigger the rule. Actually it is the second point which is of interest for me.
The make documentation offers a verification using static pattern rules:
SET_OF_FILES=src/foo.o
all: src/foo.o
$(SET_OF_FILES): src/%.o: makefile my_haeder.h src/%.c
echo Do something with those source files
This results in:
gmake: *** No rule to make target `src/my_haeder.h', needed by `src/foo.o'. Stop.
Though a larger rule, that solution is nice, as long as I don't have to add a rule for which the stem could overlap:
SET_OF_FILES=src/foo.o src/subsrc/bar.o
all: src/foo.o
$(SET_OF_FILES): src/%.o: makefile my_header.h src/%.c
echo Do something with those source files
$(SET_OF_FILES): src/subsrc/%.o: makefile my_header.h src/subsrc/%.c
echo Do something with those other source files
Which results in:
makefile:8: target `src/foo.o' doesn't match the target pattern
makefile:9: warning: overriding commands for target `src/foo.o'
makefile:6: warning: ignoring old commands for target `src/foo.o'
makefile:9: warning: overriding commands for target `src/subsrc/bar.o'
makefile:6: warning: ignoring old commands for target `src/subsrc/bar.o'
The first message is here because I didn't bother $(filter)ing SET_OF_FILES. I don't know how to solve the next warnings, which for any reviewer would mean "something's wrong".
Is there another (more elegant) way to verify that the prerequisites are actually feasible, in order to avoid dropping the explicit pattern rule?
(using GNU Make 3.79.1 win32)
Add a separate rule to check for your prerequisites
all: prereqs src/foo.o
prereqs: Makefile my_header.h
src/%.o: src/%.c Makefile my_header.h
echo Do something with those source files
src/subsrc/%.o: src/subsrc/%.c Makefile my_header.h
echo Do something with those other source files
which will give you:
make
make: *** No rule to make target 'my_header.h', needed by 'prereqs'. Stop

Resources