gpt4 book ai didi

c++ - 使用 Makefile 高效编译多个测试文件

转载 作者:行者123 更新时间:2023-11-30 05:07:44 25 4
gpt4 key购买 nike

我有一个具有以下结构的 C++ 项目:

/Project
Makefile
/src (.cpp source files)
...
/include (.h header files)
...
/libs
...
/build (.o object files)
...
/tests (target .cpp files I want to compile)
test1.cpp
test2.cpp
test3.cpp
...
/bin (output directory for compiled files)
...

对于我的测试文件中的测试,我希望能够

  • 单独编译它们,例如“做测试1”,“做测试2”

  • 一次性全部编译

但我希望能够无需为每个新测试文件定义新变量(例如 TARGET1、TARGET2...),也不需要向其中添加一堆新行我的每个新测试文件的 makefile。

例如,现在我有这样的东西:

CXX = g++
SRC_DIR = ./src
BUILD_DIR = ./build
LIB = -I libs
INC = -I include

SRCS = $(shell find $(SRC_DIR) -type f -name *.cpp)
OBJS = $(patsubst $(SRC_DIR)/%, $(BUILD_DIR)/%, $(SRCS:.cpp=.o))


TARGET1 ?= test1.cpp
TARGET2 ?= test2.cpp
TARGET3 ?= test3.cpp

all: $(OBJS)
$(CXX) ./tests/$(TARGET1).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET1)
$(CXX) ./tests/$(TARGET2).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET2)
$(CXX) ./tests/$(TARGET3).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET3)

$(TARGET1): $(OBJS)
$(CXX) ./tests/$(TARGET1).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET1)

$(TARGET2): $(OBJS)
$(CXX) ./tests/$(TARGET2).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET2)

$(TARGET3): $(OBJS)
$(CXX) ./tests/$(TARGET3).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET3)

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $@ $<

它可以完成工作,但可扩展性不是很好。我怎样才能做到这一点?

最佳答案

Make 还有一些您可以使用的技巧(未测试):

CXX = g++
SRC_DIR = src
BUILD_DIR = build
TEST_DIR = tests
BIN_DIR = bin
LIB = -I libs
INC = -I include

SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))

TESTS = $(wildcard $(TEST_DIR)/*.cpp)
TARGETS = $(patsubst $(TEST_DIR)/%.cpp,$(BIN_DIR)/%,$(TESTS))

all: $(TARGETS)

$(TARGETS): $(BIN_DIR)/%: $(OBJS)
$(CXX) $(TEST_DIR)/$*.cpp $(LIB) $(INC) $^ -o $@

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $@ $<

这里的主要技巧是 static pattern rule对于 $(TARGETS):在配方中 $* 扩展为模式的主干。其他技巧是更简单地使用 patsubst 和使用 wildcard 而不是效率较低的 shell find。请注意,只有当您的源文件位于 src 中时,这最后一个才有效,如果它们被组织在子目录的层次结构中则无效。

但这并没有回答您最棘手的要求:调用make testX 而不是make bin/testX 的方法。所以,这是最棘手的部分:

SHORTERTARGETS = $(patsubst $(TEST_DIR)/%.cpp,%,$(TESTS))

.PHONY: $(SHORTERTARGETS)

# $(1): short target
define TARGETS_rule
$(1): $(BIN_DIR)/$(1)
endef
$(foreach t,$(SHORTERTARGETS),$(eval $(call TARGETS_rule,$(t))))

您甚至可以使用此 foreach-eval-call 分解 Makefile 的其他部分:

CXX = g++
SRC_DIR = src
BUILD_DIR = build
TEST_DIR = tests
BIN_DIR = bin
LIB = -I libs
INC = -I include

SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))

TESTS = $(wildcard $(TEST_DIR)/*.cpp)
TARGETS = $(patsubst $(TEST_DIR)/%.cpp,$(BIN_DIR)/%,$(TESTS))
SHORTERTARGETS = $(patsubst $(TEST_DIR)/%.cpp,%,$(TESTS))

.PHONY: all $(SHORTERTARGETS)

all: $(TARGETS)

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $@ $<

# $(1): short target
define TARGETS_rule
$(1): $(BIN_DIR)/$(1)
$(BIN_DIR)/$(1): $(OBJS)
$(CXX) $(TEST_DIR)/$(1).cpp $(LIB) $(INC) $$^ -o $$@
endef
$(foreach t,$(SHORTERTARGETS),$(eval $(call TARGETS_rule,$(t))))

最后一个版本中最难理解的是食谱中需要$$(双重展开)。但是这里是GNU make manual是你的 friend 。

关于c++ - 使用 Makefile 高效编译多个测试文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47170575/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com