I'm trying to use GNU make's SECONDEXPANSION (using 3.81, 3.80 and earlier do not support SECONDEXPANSION) as described in the documentation, to recurse through a hierarchy of targets by implicit rules. The hierarchy is defined by macros/variables:
.SECONDEXPANSION :
top00.subblocks := mid00 mid01
mid00.subblocks := bottom00
wanted : top00.recurse ;
works_but_not_wanted : top00.onelevel ;
%.recurse : %.report $$(addsuffix .recurse,$$($$*.subblocks)) ;
%.onelevel : %.report $$(addsuffix .report,$$($$*.subblocks)) ;
%.report :
#echo REPORT: $*
If I try make wanted, it will give:
make: *** No rule to make target `top00.recurse', needed by `wanted'. Stop.
If I try make works_but_not_wanted it will give:
REPORT: top00
REPORT: mid00
REPORT: mid01
This is not what I want, since it's not reporting bottom00, will only recurse one level down for obvious reasons. But the target wanted fails. It seems GNU make is having trouble with the recursive behavior.
Any suggestions?
This is documented behavior:
No single implicit rule can appear more than once in a chain.
Related
Consider the following simplified Makefile :
target :
(recipe)
target-mt : (add some flags)
target-mt : target
This example works as intended : make target-mt add a few flags and proceeds with compiling target.
Now, since the *-mt pattern happens quite often, with always the same flags, I want to make this effort common. So let's simplify with a Makefile pattern rule :
target :
(recipe)
%-mt : (add some flags)
target-mt : target
This works as intended, and now all later *-mt targets receive the same additional set of flags.
Now, notice that the dependency of something-mt is always something. So I'm tempted to generalize this relation even more :
target :
(recipe)
%-mt : (add some flags)
%-mt : %
This one doesn't work.
make: *** No rule to make target `target-mt'. Stop.
This seems at odd with general formulation of pattern rules, such as the canonical example :
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
I presume there must be a reason for this failure, and I presume it might be related to the fact that the dependency is a pure %, not something more defined like %.c. But I couldn't find anything related to such a restriction in the documentation (linked above).
Questions are :
1) Is there an explanation for this behavior ?
2) Is there another way to achieve the same objective ?
You can't declare a pattern rule with no recipe. Or rather, you can, but it doesn't do what you want here: instead it cancels the pattern rule.
You could add a dummy recipe, like this:
%-mt: % ; #:
(: is a shell no-op operator).
Or you could just not use this and go back to the way it was. It's a little hard to understand the full context from this limited example.
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.
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.
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 : ;
I have a simple Makefile like this:
%.t1: %.t2
%.t2:
echo "t2"
When I type
make x.t2
it works fine. But when I type
make x.t1
I get
make: *** No rule to make target 'x.t1'. Stop.
If I modify the %.t1 target to say
%.t1: %.t2
echo
Then it works. Why doesn't it work without a command? I'm using GNU make 4.0 on Fedora 23.
A pattern rule with no recipe does not add a rule, it cancels implicit rules. See http://www.gnu.org/software/make/manual/make.html#Canceling-Rules:
You can cancel a built-in implicit rule by defining a pattern rule with the same target and prerequisites, but no recipe. For example, the following would cancel the rule that runs the assembler:
%.o : %.s
A semi-colon can be added to tell make that it has an empty recipe:
%.t1: %.t2 ;
%.t2:
echo t2
Which yields:
$ make x.t1
t2