Reputation: 2524
I've got a Makefile that works good so far. Although, as it started growing, recompiling all the sources every time began to take too long. Here's a snippet from the working version:
CC=$(CROSS_COMPILE)g++
CFLAGS=-Wall -I./include -pg -O2
VPATH=./src:./include
all: dotgazer.cpp dotgazer/Dot.cpp
$(CC) $(CFLAGS) $^ -o dotgazer.out `pkg-config --libs opencv`
There are a lot more dependencies, but these two are enough to show what the problem is. I'm trying to move the compilation stage of each cpp
file to a separate target. When it comes to the top-level file (dotgazer.cpp
) it's not a problem and a general rule %.o: %.cpp
works fine. But I can't get the second dependency to work. Here's how it looks now:
CC=$(CROSS_COMPILE)g++
CFLAGS=-Wall -I./include -pg -O2
VPATH=./src:./include
all: dotgazer.o dotgazer/Dot.o
$(CC) $(CFLAGS) $^ -o dotgazer.out `pkg-config --libs opencv`
%.o: %.cpp
$(CC) -c $(CFLAGS) $^ -o $@
dotgazer/Dot.o: dotgazer/Dot.cpp
$(CC) -c $(CFLAGS) $^ -o $@
I've tried different variations of the Dot.o
rule but none of them seems to work. The error I get with the one above is:
Fatal error: can't create dotgazer/Dot.o: No such file or directory
How should I do that? I'd most prefer to have the .o
files in the same folders as their sources. Also, I'd be thankful for general rules (like %.o: %.cpp
) as there are lots of source files and I don't want the Makefile to get too bloated. Thank you!
Upvotes: 0
Views: 5167
Reputation: 2770
I think your Makefile
is a bit to specific and thus error-prone. I suggest to look at my following example that is way more generic than yours.
My example takes advantage of make
's catalouge of implicit rules. For cpp
-files exists a generic implicit rule already. So why should one not use it!?
The reference manual describes it as follows:
Compiling C++ programs
n.o is made automatically from n.cc, n.cpp, or n.C with a recipe of the form
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c
.
So if you have %.o
files as prerequisites like in the rule dotgazer.out: $(OBJS)
make
applies above implicit rule to all those files automatically. Assumed you have set valid values for CXX
, CPPFLAGS
and/or CXXFLAGS
.
Furthermore you usually don't need to add your sources by hand to a variable. Most of the time all the sources in your project's directory tree are needed to build the executable. If it's not the case you should consider to build a appropriate tree that reflects this.
Since find
is responsible to assign the sources to CPPFILES
we don't need to set VPATH
either. Due to our usage of find
and patsubst
we have only one explicit file name in our Makefile
. That make working on a real project with plenty of different sources much more smooth.
Of course you don't need the all
and the clean
rule. I just added these for convenience.
CXX=$(CROSS_COMPILE)g++
CPPFLAGS=-I./include
CXXFLAGS=-Wall -pg -O2
LDLIBS=`pkg-config --libs opencv`
CPPFILES=$(shell find . -name "*.cpp")
OBJS=$(patsubst %.cpp, %.o, $(CPPFILES))
all: dotgazer.out
@echo $(CPPFILES)
@echo $(OBJS)
dotgazer.out: $(OBJS)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDLIBS)
clean:
rm -f $(OBJS)
Upvotes: 2