tags:

views:

368

answers:

3

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?

+3  A: 

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.

Aiden Bell
What about: $(OBJECTS): $(BUILD_DIR)/Release/%.o: %.cpp
anon
BUt I do define the C++ build rule, its the $(OBJECTS): $(BUILD_DIR)/Release/%.o: %.cpp line in there, kind of hard to pick out
Charles
That rule isn't being activated. Break it up into a simpler form first. I suspect some expansion of `%` is happening incorrectly.
Aiden Bell
I tried running make on my old project with --no-builtin-rules and it worked fine. But the expansion problem is at least a lead I can look farther into, thanks
Charles
+3  A: 

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.

anon
When this gets confirmed. I will delete my waffle ;), also +1 for generally good advice
Aiden Bell
I wish I did not need to use it, like you said its a very devilish little variable. Trouble is my source folders are not flat, and I cannot have my bin folder ending up with the same directory tree structure that exists in the src dir.Using the vpath like this was my solution, and it took weeks to get right, that being said, it there is a better way I am all for it.I will try setting up up to not use the vpath and see what happens.
Charles
not using vpath works perfectly. eugggg vpaths, now I need to new solution to the build dir path problem.
Charles
Either way, VPATH voodoo is never good. I'm with Neil on being explicit. Some resolution/expansion is bad, at some level between VPATH, your variable creation and the what the rule expands to. Try echoing the $< and $@
Aiden Bell
A: 

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!

Charles