【问题标题】:Compiling both C and CPP source in a single makefile target在单个 makefile 目标中编译 C 和 CPP 源
【发布时间】:2018-04-05 07:54:49
【问题描述】:

我有一个makefile,我在其中同时使用C 源代码和CPP 源代码。下面是来自 makefile 的一段 sn-p 代码。有没有办法结合以下两个目标来编译这两种文件类型?

#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/

提前致谢

【问题讨论】:

  • CFLAGS 包含特定于 C++ 的标志,通常用于 C 源代码。 CXXFLAGS 是标准 C++ 标志变量。您通常还应该使用 $(CC) 作为 C 编译器。
  • 使用明确的规则来构建以.c.cpp 作为源的目标文件可能不是一个好主意。 Make 已经内置了这些。只需在CFLAGS.c-files)和CXXFLAGS.cpp-files)中指定您需要的标志。大多数你定义的变量,你真的不应该。它不可能为用户覆盖那些 - 只附加到 CFLAGSCXXFLAGS 变量并且根本不定义 CXX
  • @Someprogrammerdude 不是 CFLAGS 特定于 C 而不是 C++?
  • @KamiKaze 我的意思是说CFLAGS 中显示的Makefile 包含C++ 编译器特定的标志。因此,不应将其用于当前 Makefile 中的 C 源代码(这是 CFLAGS 的用途)。
  • 这是可能的(使用definesevals 等),但最终结果比有两个规则更混乱。这是几天前讨论过的here(阅读cmets)。

标签: c++ c makefile gnu-make


【解决方案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)以解决我们可能遇到的源文件不同的情况扩展名但名称相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-05
    • 2018-11-22
    • 2016-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多