Wojtek
Wojtek

Reputation: 2524

Makefile - Dependency file in a folder "No such file or directory"

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

Answers (1)

user1146332
user1146332

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

Related Questions