Reputation: 141
I have never been able to make Pattern Rules work for me since university. I do EXACTLY what the examples say and it just never works. All I ever get is the error:
make: *** No rule to make target '<whatever>.o', needed by 'all'. Stop.
This is my current make file:
all: test clean
test : $(ODIR)/weight_nodeTest.o
$(LINK) $(RUN)/$@ $^
$(ODIR)/%.o : $(TEST)/%.cpp $(SRC)/%.h
$(COMPILE) $(ODIR)/$@ $^
clean :
rm -f $(RUN)/*
rm -f $(ODIR)/*
When I put in the specific files instead of wildcards, it works perfectly. Can anybody give me some insight into what I am doing wrong??
Upvotes: 2
Views: 1053
Reputation: 101061
I think people must be confused by pattern rules because they think that they're very complex. But pattern rules are actually very simple: they're just matching text. As Renaud says it's much harder to explain since you don't have a full example here, but let's assume it's like this:
ODIR = obj
TEST = test
SRC = src
test : $(ODIR)/weight_nodeTest.o
...
$(ODIR)/%.o : $(TEST)/%.cpp $(SRC)/%.h
$(COMPILE) $(ODIR)/$@ $^
After the makefile is parsed and the rules are expanded, make has the equivalent of this in its internal database:
test : obj/weight_nodeTest.o
...
obj/%.o : test/%.cpp src/%.h
$(COMPILE) $(ODIR)/$@ $^
So, make wants to build test
. To build test
it wants to build obj/weight_nodeTest.o
.
There's no explicit rule for obj/weight_nodeTest.o
so make looks through its catalog of implicit rules. It will find your pattern rule and it sees that obj/%.o
matches the target it wants to build, obj/weight_nodeTest.o
. The STEM here is the part that matches the %
, so the stem is weight_nodeTest
.
But, that's not the end of the match process. Consider that there are lots of different ways to build an object file: make could have patterns that build object files from C source files, C++ source files, Fortran, COBOL, Rust, etc. etc. In other words, the same pattern target may have many rules that match it, with different prerequisites. So before we can know if this pattern rule is correct make first much check the prerequisites.
In this case the stem is weight_nodeTest
and we substitute that for the pattern in the prerequisites, so the prerequisites are test/weight_nodeTest.cpp
and src/weight_nodeTest.h
.
Make will check that those files exist (or it can figure out how to build them from other prerequisites).
If ALL the prerequisites exist or can be built, then the pattern matches.
If ANY of the prerequisites don't exist and can't be built, then the pattern doesn't match and make goes looking for some other pattern than can be used.
That's it, that's all there is.
Most often when I see people write pattern rules that include BOTH a source file and a header file as prerequisites the problem is that they don't have a header file for every source file. That means their pattern will match correctly to build any object file where there is both a source and header file, and it will not match correctly to build any object where the header file is missing.
Generally, you don't want to add header files as patterns in your target rules unless you are 100% sure there will always be an associated header.
Also, Renaud is quite right, you never want your compile rule to use anything other than plain $@
as the target to be built. That variable will be set to the path of the target make expects your recipe to build. If you build some other file, it will not work right. If plain $@
is not the path that you want, then your pattern rule is not written correctly.
Upvotes: 3