Riccardo Manfrin
Riccardo Manfrin

Reputation: 741

Makefile for mixed C/C++ sources

Suppose I have the following setup

CPPSRC+=path1/foo.cpp
CPPSRC+=path2/main.cpp

CSRC+=path3/zoo.c
CSRC+=path4/bar.c

I want to produce all object files .o into build/ folder (so I supposingly need both pathsubst and pattern matching).

I also need the .cpp to be compiled with g++ and related CXXFLAGS, whereas the .c need to be compiled with gcc and simplier CFLAGS.

I've come this far:

CPPOBJ := $(CPPSRC:%.cpp=%.o)
COBJ := $(CSRC:%.c=%.o)
OBJ := $(COBJ) $(CPPOBJ)
BUILTOBJ := $(addprefix $(BUILD_PATH)/,$(notdir $(OBJ)))

$(APP): $(OBJ)
    [...]

$(CPPOBJ): %.o: %.cpp
    @echo "[g++" $(BUILD_PATH)$(notdir $@)"]"
    $(SILENT)$(GPP) $(CXXFLAGS) $(INCLUDES) -c $< -o $(BUILD_PATH)$(notdir $@)

$(COBJ): %.o: %.c
    @echo "[gcc " $(BUILD_PATH)$(notdir $@)"]"
    $(SILENT)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $(BUILD_PATH)$(notdir $@)

but cannot get to reach $(COBJ): %.o: %.c prerequisite (in short the .c sources do not get compiled).

How to?

Upvotes: 0

Views: 3073

Answers (2)

Riccardo Manfrin
Riccardo Manfrin

Reputation: 741

How naive of me.. because I did have the .o files in the original path (not in build/) and my clean: only removed the build/ path, the .c prerequisites where never invoked and .o where not generated nor placed in the build/ folder.

Indeed my trick tried to fool make by making it produce the .o file in a position different than what prerequisites defined.

Minor addon: I don't need to land to the makefile with separated C/C++ sources lists; I can achieve separation with the following:

CPPSRC:=$(filter %.cpp,$(SRC))
CSRC:=$(filter %.c,$(SRC))
CPPOBJ:= $(CPPSRC:%.cpp=%.opp)
COBJ:= $(CSRC:%.c=%.o)
OBJ:= $(COBJ) $(CPPOBJ)
BUILTOBJ:= $(addprefix $(BUILD_PATH)/,$(notdir $(OBJ)))

Upvotes: 0

rustyx
rustyx

Reputation: 85341

What you're trying to achieve using gmake's pattern rules is impossible because you're losing path information when you strip the source subdirectory from the object file. So a generic pattern rule like %.o: %.cpp won't ever know that to compile build/foo.o it needs to look in path1/foo.cpp. Not to mention the increased possibility of a naming conflict.

You can solve it by recreating the subdirectory structure under build/, i.e. compile path1/foo.cpp to build/path1/foo.o, etc.

Once that's sorted, gmake is smart enough to resolve seemingly ambiguous rules, i.e. it will have no problem at all compiling a mix of .c and .cpp files, like in the example below:

APP = app
BUILD_PATH = build
CPPOBJ := $(CPPSRC:%.cpp=%.o)
COBJ := $(CSRC:%.c=%.o)
OBJ := $(COBJ) $(CPPOBJ)
BUILTOBJ := $(addprefix $(BUILD_PATH)/,$(OBJ))

$(APP): $(BUILTOBJ)
    $(CXX) $(CPPFLAGS) -o $@ $(BUILTOBJ) $(LDLIBS)    

$(BUILD_PATH)/%.o: %.cpp
    mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@

$(BUILD_PATH)/%.o: %.c
    mkdir -p $(@D)
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

Upvotes: 1

Related Questions