【发布时间】:2021-05-02 18:15:26
【问题描述】:
我有一个学校项目,我想编写一个 Makefile,我看到了一些使用 Makefile 和多个源目录和多个可执行文件的示例,但仍然无法将它正确地实现到我的 Makefile。
PS:我正在使用 doctest 进行单元测试(我无法更改它)。
这是项目结构(我无法更改):
.
├── bin
├── build
├── extern
│ └── doctest.h
├── include
│ ├── file1.hpp
│ └── file2.hpp
├── src
│ ├── file1.cpp
│ └── file2.cpp
├── tests
│ ├── file1-test.cpp
│ └── file2-test.cpp
└── Makefile
我有以下目录:
-
bin: 对于所有可执行文件。 -
build:对于所有对象 (.o)。 -
extern: 用于 doctest 标头(这是我存储任何其他库的地方) -
include:对于所有标题 (.hpp)。 -
src:所有类 (.cpp)。 -
tests:用于所有单元测试(还有.cpp)
您可以看到file1.cpp 是一个类,file1.hpp 是类头,file1-test.cpp 是类的单元测试。
在上面的示例中,我有 2 个测试文件,但在项目的最后我会有更多,并且对于每个测试文件,我都会有一个可执行文件。
我的目标:
-
我想运行
make并编译所有单元测试(tests/目录中的所有.cpp)。 -
我希望所有可执行文件都存储在
bin/目录中,所有二进制文件都存储在build/目录中。
这是我的 Makefile:
BIN_DIR = ./bin/
BUILD_DIR = ./build/
EXTERN_DIR = ./extern/
INCLUDE_DIR = ./include/
SOURCE_DIR = ./src/
TESTS_DIR = ./tests/
vpath %.cpp $(SOURCE_DIR) $(TESTS_DIR)
CXX = clang++
CXXFLAGS = -Wall -std=c++11 -g -O3 -I$(INCLUDE_DIR) -I$(EXTERN_DIR)
EXEC_FILES = file1-test file2-test
BIN = $(addprefix $(BIN_DIR), $(EXEC_FILES))
all: $(BIN) | $(BIN_DIR)
$(BUILD_DIR)%.o: %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -c -o $@ $^
$(BIN_DIR) $(BUILD_DIR):
mkdir -p $@
$(BIN_DIR)file1-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file1-test.o
$(CXX) -o $@ $^
$(BIN_DIR)file2-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file2.o $(BUILD_DIR)file2-test.o
$(CXX) -o $@ $^
clean:
-rm -f $(BIN_DIR)* $(BUILD_DIR)*
它运行良好,但我觉得它正在做一些多余的事情,我可以通过更多的 Makefile 艺术知识来避免,尤其是在这里:
$(BIN_DIR)file1-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file1-test.o
$(CXX) -o $@ $^
$(BIN_DIR)file2-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file2.o $(BUILD_DIR)file2-test.o
$(CXX) -o $@ $^
目前这个 Makefile 是正确的,因为我只有 2 个可执行文件,但我最终会得到 15+ 个,我不想每个可执行文件有 15 倍:
$(BIN_DIR)xxx-test: $(BUILD_DIR)xxx.o etc.
$(CXX) -o $@ $^
我到底需要什么...:
基本上,我需要编写一个通用规则来获取给定目标的所有适当依赖项。
在阅读了多篇文章后,我认为这都是关于自动依赖的。
我很确定最终结果会像这样,但遗憾的是我无法让它在我的情况下工作:
$(BIN_DIR)%: ???
@$(CXX) -o $@ $^
我已经看过这个(以及关于该主题的许多其他帖子):http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/,但我仍然无法弄清楚。
那么我该如何编写一个可以完成这项工作的表达式,有人可以给我一个工作示例或类似的东西吗?
编辑 1:
基于此帖子:Makefile (Auto-Dependency Generation)。
我将这些行添加到我的Makefile:
SRC = $(wildcard $(SOURCE_DIR)*.cpp)
SRC += $(wildcard $(TESTS_DIR)*.cpp)
这个想法是从源目录(src 和tests)中获取所有.cpp。然后我将-MDD 选项添加到我的CXXFLAGS 变量中,为每个目标创建一个.d 文件(至少这是我认为它正在做的事情):
CXXFLAGS = -Wall -std=c++11 -g -O3 -I$(INCLUDE_DIR) -I$(EXTERN_DIR) -MMD
最后,我添加了这个:
$(BIN_DIR)%: $(SRC)
$(CXX) -o $@ $^
-include $(SRC:.cpp=.d)
我期望它做什么:
-
创建一个
.d文件,其中包含每个目标的所有依赖项。 -
获取
.d文件中的依赖项并将它们转换为.o以获取给定目标所需的所有对象。
但它似乎没有达到我的预期。
编辑 3:
经过一些更改,我最终得到了这个Makefile:
BIN_DIR := bin/
BUILD_DIR := build/
EXTERN_DIR := extern/
INCLUDE_DIR := include/
SOURCE_DIR := src/
TESTS_DIR := tests/
DEP_DIR := .dep/
DEPENDS := $(patsubst %.o, $(BUILD_DIR)$(DEP_DIR)%.d, $(notdir $(wildcard $(BUILD_DIR)*.o)))
EXE := $(addprefix $(BIN_DIR), Coord-test Fourmi-test)
OBJS_1 := $(addprefix $(BUILD_DIR), Coord.o)
OBJS_2 := $(addprefix $(BUILD_DIR), Coord.o Fourmi.o)
CXX := clang++
CXXFLAGS := -Wall -std=c++11 -g -O3 -I$(INCLUDE_DIR) -I$(EXTERN_DIR)
vpath %.cpp $(SOURCE_DIR) $(TESTS_DIR)
all: $(EXE)
$(BUILD_DIR):
mkdir -p $@ $@/$(DEP_DIR)
$(BIN_DIR):
mkdir -p $@
$(BUILD_DIR)%.o: %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -MMD -MP -MF $(BUILD_DIR)$(DEP_DIR)$(notdir $(basename $@).d) -c $< -o $@
$(BIN_DIR)%: $(BUILD_DIR)%.o | $(BIN_DIR)
$(CXX) -o $@ $^
$(BIN_DIR)Coord-test: $(OBJS_1)
$(BIN_DIR)Fourmi-test: $(OBJS_2)
.PRECIOUS: $(BUILD_DIR)%.o
-include $(DEPENDS)
clean:
-rm -f $(BIN_DIR)* $(BUILD_DIR)* $(BUILD_DIR)$(DEP_DIR)*
它正在工作,但我必须为每个新的可执行文件添加OBS_X。
我也想分解这个,但我不知道这是否可能?如果有人可以告诉我。
$(BIN_DIR)%: $(BUILD_DIR)%.o | $(BIN_DIR)
$(CXX) -o $@ $^
$(BIN_DIR)Coord-test: $(OBJS_1)
$(BIN_DIR)Fourmi-test: $(OBJS_2)
【问题讨论】:
标签: c++ makefile project-structure