Makefile works %.c, does not work %.cpp

2019-08-22 13:22发布

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?

标签: c++ gnu-make
3条回答
时光不老,我们不散
2楼-- · 2019-08-22 13:31

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.

查看更多
迷人小祖宗
3楼-- · 2019-08-22 13:37

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!

查看更多
Animai°情兽
4楼-- · 2019-08-22 13:48

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.

查看更多
登录 后发表回答