Makefile Pattern Rule is found but recipe does not run - makefile

I have a makefile that has the following pattern rule to create an implicit rule:
%.cpp:
$(warning foo)
When I check the output of make -d I see that this implicit rule is being found and matching a file. I verify that when I remove the pattern rule, the output of make -d no longer shows a match. However, even when the implicit rule is found, the warning doesn't show up. The recipe isn't running, even though the implicit rule matches.
What gives?

That recipe tells make how to create a %.cpp file (and gives it no prerequisites).
When are you expecting it to be run?
It will not run for any existing *.cpp files as the lack of prerequisites means that make considers the files up to date.
Try running make totally-doesnt-exist.cpp and you should see the warning.

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

Target dependency: Makefile no rule to make target error

Here is the make file that I am running,
.PHONY: build
build: pre_build_script $(OUTPUTDIR)/%.cpp
$(OUTPUTDIR)/%.cpp: $(INTXTDIR)/%.txt
python.exe $(SOMEDIR)/somepythonscript.py $(INTXTDIR) $(OUTPUTDIR)
.PHONY: pre_build_script
pre_build_script:
pythonscript.exe $(PREBUILDDIR)
This is the output that I get:
$ make build
pythonscript.exe $(SAMPLEDIR)
make: *** No rule to make target '../obj/CPP/%.cpp', needed by 'build'. Stop.
Looks like I'm missing on some sytanx as I get this error inspite of declaring the target dependency. Any suggestions?
This means make cannot find a file named $(OUTPUTDIR)/%.cpp, a prerequisite for the first rule.
You cannot use % as a wildcard anywhere in a rules like this:
build: pre_build_script $(OUTPUTDIR)/%.cpp
it needs to be a part of pattern rule or a static pattern rule.
You can use $(wildcard $(OUTPUTDIR)/*.cpp) to get a complete list of files, but it's an anti-pattern (pun intended). You are supposed to either exactly know what files are used in what rules, or (know it even better and) create a generic pattern rule.
The second pattern rule (one using somepythonscript.py) is supposed to work on a single source-target file pair, $(INTXTDIR)/%.txt -> $(OUTPUTDIR)/%.cpp. The command seems to process all the files in the directory, which is not incremental: it will redo all the work even if only one file was updated.

Make not using Match Anything rule for prerequisite

So, I have a Makefile with 2 pattern rules, one of them is a terminal Match-Anything; the target is about.html (for example):
vpath %.md $(SOURCE_DIR)
HEADER := assets/navbar.part
%.html : %.md $(HEADER)
pandoc [...] $< -o $#
%::
cp $(SOURCE_DIR)/$# $#
If I execute make assets/navbar.part, and then make about.html (for example), everything works fine (navbar.part uses the match anything, and about.html uses the first rule). But if I try to make about.html without having navbar.part present, make does:
Find the prerequisite about.md
?? Gives up on fulfilling $(HEADER)
Tries to use the match anything rule to generate about.html
I was expecting that make would:
Find the prerequisite about.md
Make the prerequisite $(HEADER) using the match-anything rule
With all the prerequisites fulfilled, finally execute the first rule
From reading the debug trace, it seems like Make never really tries to fulfill the $(HEADER) prerequisite:
Considering target file 'about.html'.
File 'about.html' does not exist.
Looking for an implicit rule for 'about.html'.
Trying pattern rule with stem 'about'.
Trying implicit prerequisite 'about.md'.
Found prerequisite 'about.md' as VPATH '../website/about.md'
Trying rule prerequisite 'assets/navbar.part'.
Trying pattern rule with stem 'about.html'.
Found an implicit rule for 'about.html'.
Considering target file 'about.md'.
Finished prerequisites of target file 'about.md'.
No need to remake target 'about.md'; using VPATH name '../website/about.md'.
Finished prerequisites of target file 'about.html'.
Must remake target 'about.html'.
cp -f ../website/about.html about.html
Any ideas?
After digging the manual, I found section 10.8 that states:
For each pattern rule in the list:
Find the stem s, which is the nonempty part of t or n matched by the ‘%’ in the target pattern.
Compute the prerequisite names by substituting s for ‘%’; if the target pattern does not contain a slash, append d to the front of each prerequisite name.
Test whether all the prerequisites exist or ought to exist. (If a file name is mentioned in the makefile as a target or as an explicit prerequisite, then we say it ought to exist.)
Because the $(HEADER) does not meet the definition of ought to exist:
No file exists when the rule is tried
No rule with that explicit target exists
it fails; however, it suceeds if we try to make specifically $(HEADER), and then try to make about.html it suceeds, because by then $(HEADER) is an existing file.

Inferred rules in makefile

I'd like to know what's wrong with my makefile where I'm using inferred rules:
nvcc=/usr/local/cuda-6.5/bin/nvcc
opts="-O3 -arch=sm_35 -rdc=true -lcudadevrt -Xcompiler -fopenmp -lpng"
base: ignore dynamic predict
%: ./../source/%.cu
$(nvcc) $> $(opts) -o $#
The error I get:
make: *** No rule to make target `ignore.exe', needed by `base'. Stop.
Of course there's no such a rule, but shouldn't make assume that ignore is hidden in %?
First, your error message doesn't match your makefile (nowhere in your makefile is the target ignore.exe mentioned). This makes me cautious that there maybe other relevant differences between what you're running and what you've shown us.
In any event, a rule like %: ./../source/%.cu will match a target if and only if there's a prerequisite that matches the pattern as well. So if your target is ignore.exe and the target pattern is % that means that the % in the prerequisite will expand to ignore.exe as well. So make will look for a prerequisite ./../source/ignore.exe.cu. If that file exists (or can be made itself) then make will try to build the target. If it doesn't exist and can't be created, then make will ignore that rule and keep looking for more rules that might match the target and where the prerequisite exists or can be built.
If none are found, then you get the error you see (No rule to make target)

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).

Resources