在单个makefile目标中编译C和CPP源

时间:2018-04-05 07:54:50

标签: c++ c makefile gnu-make

我有一个makefile,我正在使用C源代码和CPP源代码。下面是makefile的一段代码。有没有办法结合以下两个目标来编译两种文件类型?

#definitions
OBJ_DIR := obj
DEP_DIR := dep

CXX := g++
DEBUG := -g -O0
OPT := -std=c++11 -Wextra -Wall -pthread
LFLAGS = $(DEBUG) $(OPT) $(INC)
CFLAGS = $(LFLAGS) -c

#auto-dependency generation (part 1)
DEP_FLAGS = -MT $@ -MMD -MP -MF $(DEP_DIR)/$*.Td
POSTCOMPILE = @mv -f $(DEP_DIR)/$*.Td $(DEP_DIR)/$*.d && touch $@

#compile object files from CPP source
$(OBJ_DIR)/%.o: %.cpp $(DEP_DIR)/%.d
    $(CXX) $(CFLAGS) $(DEP_FLAGS) $< -o $@
    $(POSTCOMPILE)

#compile object files from C source
$(OBJ_DIR)/%.o: %.c $(DEP_DIR)/%.d
    $(CXX) $(CFLAGS) $(DEP_FLAGS) $< -o $@
    $(POSTCOMPILE)

#auto-dependency generation (part 2)
$(DEP_DIR)/%.d: ;
.PRECIOUS: $(DEP_DIR)/%.d
include $(wildcard $(DEP_DIR)/*.d)

我尝试使用带有各种不同格式的通配符函数,但是没有用。

我正在使用Make 4.2。自动依赖生成代码取自http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/

提前致谢

1 个答案:

答案 0 :(得分:1)

使用正确的变量以及definecalleval功能,可能会出现以下情况:

EXT := c cpp

define rule =
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.$(1)
    $$(COMPILE.$(1)) $$< -o $$@
endef

$(foreach ext, $(EXT), $(eval $(call rule,$(ext)))) # NO SPACE before $(ext) here!!!

make 具有隐式变量和规则,尤其是许多COMPILE.*规则(您可以通过发出shell命令make -p | grep 'COMPILE.* ='来查看它们):

COMPILE.c   = $(CC)  $(CFLAGS)   $(CPPFLAGS) $(TARGET_ARCH) -c
COMPILE.cpp = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

CPPFLAGS用于预处理程序标志(cpp是GNU GCC工具链中的预处理程序可执行文件)。默认情况下,TARGET_ARCH在大多数平台上都是空的。

这是一个完整但极简主义的工作Makefile,具有更好的自动依赖关系生成(请注意,将.d文件放在与.o分开的文件夹中,无意义地使makefile复杂化):

TARGET  := executable
EXT     := c cpp

SRC_DIR := .
OBJ_DIR := obj
DEP_DIR := dep

CPPFLAGS  = -MMD -MP -MF $(@:$(OBJ_DIR)/%.o=$(DEP_DIR)/%.d)
CFLAGS   := -Wall -Wextra -pthread
CXXFLAGS := -std=c++11 $(CFLAGS)
LDFLAGS  := -pthread

SOURCE := $(foreach ext, $(EXT), $(wildcard $(SRC_DIR)/*.$(ext)))
OBJECT := $(SOURCE:$(SRC_DIR)/%=$(OBJ_DIR)/%.o)
DEPEND := $(OBJECT:$(OBJ_DIR)/%.o=$(DEP_DIR)/%.d)

define rule =
$(OBJ_DIR)/%.$(1).o: $(SRC_DIR)/%.$(1) | $(OBJ_DIR) $(DEP_DIR)
    $$(COMPILE.$(1)) $$< -o $$@
endef

.PHONY: all clean

all: $(TARGET)

$(TARGET): $(OBJECT)
    $(CXX) $(LDFLAGS) $^ -o $@

$(foreach ext, $(EXT), $(eval $(call rule,$(ext))))

$(OBJ_DIR) $(DEP_DIR):
    mkdir -p $@

-include $(DEPEND)

clean:
    $(RM) -r $(TARGET) $(OBJ_DIR) $(DEP_DIR)

另请注意,我选择将原始源文件扩展名(ccpp)添加到对象文件名(.c.o.cpp.o)以解决此问题我们可以在哪里遇到具有不同扩展名但名称相同的源文件。