I have a set of makefiles I use to build a 'big' C project. I am now trying to reuse some in my C++ project and have run into this headache that I just cannot figure out.
The makefile looks like this
SOURCES = \
elements/blue.cpp
# Dont edit anything below here
VPATH = $(addprefix $(SOURCE_DIR)/, $(dir $(SOURCES)))
CXXFLAGS = $(OPT_FLAGS) -MMD -MF $(BUILD_DIR)/$*.d -D_LINUX -DNDEBUG -pipe
DCXXFLAGS = $(DEBUG_FLAGS) -MMD -MF $(BUILD_DIR)/$*.d -v -D_LINUX -D_DEBUG -pipe
OBJECTS := $(patsubst %.cpp, $(BUILD_DIR)/Release/%.o, $(notdir $(SOURCES)))
DOBJECTS := $(patsubst %.cpp, $(BUILD_DIR)/Debug/%.o, $(notdir $(SOURCES)))
$(OBJECTS): $(BUILD_DIR)/Release/%.o: %.cpp
+@[ -d $(dir $@) ] || mkdir -p $(dir $@)
$(CPP) $(INCLUDE) $(CXXFLAGS) $(DEFINES) -o $@ -c $<
Its a little complicated but what it does in C is build all the %.c files defined in SOURCES and put the object files in BUILD_DIR. It works great in c, but this does not work with cpp files. I get
make: *** No rule to make target `blue.cpp', needed by `build/Release/blue.o'. Stop.
Its like VPATH is not working at all. I tried
vpath %.cpp src/elements
but that does not work either.
Amazingly enough, renaming blue.cpp to blue.c and editing the makefile back to the %.c usage does work, it compiles just fine.
Am I going crazy here?
From your example, it looks like you don't have a Makefile rule being activated for compiling the C++ files. Maybe your %
are expanding incorrectly?
Try
$(OBJECTS): %.o: %.cpp
...
And specify the destination in the rule part, using $(basename ..)
where appropriate.
It works for C for blue.c
because Make has a built-in default rule for compiling C files. I suspect running Make with the --no-builtin-rules
option would cause the blue.c
file to stop working too.
From the docs,
Compiling C programs
n.o is made automatically from n.c with a command of the form $(CC) -c
$(CPPFLAGS) $(CFLAGS)'. Compiling C++
programs
n.o is made automatically from n.cc, n.cpp, or n.C with a command of
the form
$(CXX) -c $(CPPFLAGS)
$(CXXFLAGS)'. We encourage you to use
the suffix .cc' for C++ source files
instead of
.C'.
There is a default C++ rule, but it might not be kicking in for you because of another rule or bad variables. It is better to write the rule explicitly to be sure.
You need a rule such as:
%.o: %.cpp
$(CPP) $(CPP_OPTS) -c -o $@ $<
For compiling your object files from source, then you have:
executable: $(OBJECTS)
... compile objects into final blob ...
Where the objects of some format %.o
trigger the dependency. Or use Autotools/Autoconf to build your Makefile for you. Here is an example I wrote that just builds C++ files into a directory of objects:
SOURCES=$(wildcard path/to/src/*.cpp)
OBJECTS=$(SOURCES: .cpp=.o)
CC=g++
final: $(OBJECTS)
mv $(OBJECTS) /path/to/build_dir
%.o: %.cpp:
g++ -c -o $@ $<
Not a complete example by any means, but you get the idea. In the final
rule, you copy the object files, but you can do whatever here or change the -o
option to plonk build files in a specific location.
Do you really need VPATH - I've had nothing but trouble with it in the past. And in fact, I seem to remember that VPATH is dependent on extensions, so that would fit Aiden's theory. In my makefiles, I give the source directory SDIR explicitly:
SDIR = ./somewhere
...
$(ODIR)/%.o: $(SDIR)/%.cpp
$(CC) -c $(INC) -o $@ $< $(CFLAGS)
.
Edit: If you are wedded to the use of VPATH, then you need to investigate the use of the vpath directive (note case difference). For example:
vpath %.cpp foo:bar
looks for .cpp fies in foo and bar directories. But as I said, I've had nothing but trouble using this.
Ok guys I figured it out here and its a big mess of a bug.
After some more experimentation I went to post a bug on the make-bugs list and turned on debug output to tell them exactly what was going on. Turns out I should have done this before because it led me right to the solution.
I use an automatic dependency generation scheme developed from http://mad-scientist.net/make/autodep.html and amazingly enough that was breaking make. Trouble occurred in with this line
-include $(patsubst %.c, $(BUILD_DIR)/%.d, $(notdir $(SOURCES)))
I did not change that to %.cpp and for some reason trying to include blue.cpp caused make to not search for it using vpath when it tried to resolve
$(OBJECTS): $(BUILD_DIR)/Release/%.o: %.cpp
So the solution was just to port the makefile correctly, doh!