目录
5.3.CMakeLists.txt与生成的Makefile的关系
1.CMake构建过程的基本流程
CMake的构建过程可以分为三个主要步骤:配置(Configuration)、生成(Generation)和构建(Build)。下面我们将详细解析每个步骤。
1.配置(Configuration)
配置阶段是CMake解析CMakeLists.txt文件的过程。在这个阶段,CMake会读取CMakeLists.txt文件,并执行其中的命令。这些命令主要用于检查系统环境(例如编译器、库等),设置构建选项,以及定义构建目标(例如库、可执行文件等)。
CMakeLists.txt文件是CMake的核心,它定义了项目的构建规则和依赖关系。每个目录(包括子目录)中都可以有一个CMakeLists.txt文件。在配置阶段,CMake会从顶层目录的CMakeLists.txt文件开始,递归地处理每个子目录中的CMakeLists.txt文件。
2.生成(Generation)
生成阶段是CMake根据配置阶段的结果,生成实际的构建文件的过程。这些构建文件通常是Makefile文件,但也可以是其他类型的构建文件,例如Ninja构建文件,或者Visual Studio项目文件,这取决于你选择的构建工具。
在生成阶段,CMake会将CMakeLists.txt文件中定义的构建规则和依赖关系,转换为构建工具可以理解的形式。例如,如果你选择的构建工具是Make,CMake会生成Makefile文件。每个目录(包括子目录)中都会生成一个Makefile文件。
3.构建(Build)
构建阶段是使用构建工具(例如Make、Ninja或Visual Studio)根据生成的构建文件,编译源代码并链接生成目标文件的过程。
在构建阶段,构建工具会读取生成的构建文件,按照其中定义的规则和依赖关系,执行实际的编译和链接操作。构建工具会自动处理依赖关系,确保在编译和链接一个目标文件之前,其所有依赖的目标文件都已经被正确地编译和链接。
2.CMake构建的具体步骤
CMake 的构建流程分为几个主要步骤,从设置项目到生成和执行构建命令。
- 创建构建目录:保持源代码目录整洁。
- 使用 CMake 生成构建文件:配置项目并生成适合平台的构建文件。
- 编译和构建:使用生成的构建文件执行编译和构建。
- 清理构建文件:删除中间文件和目标文件。
- 重新配置和构建:处理项目设置的更改。
以下是详细的构建流程说明:
2.1.创建构建目录
CMake 推荐使用 "Out-of-source" 构建方式,即将构建文件放在源代码目录之外的独立目录中。这样可以保持源代码目录的整洁,并方便管理不同的构建配置。
创建构建目录:在项目的根目录下,创建一个新的构建目录。例如,可以创建一个名为 build 的目录。
mkdir build
进入构建目录:进入刚刚创建的构建目录。
cd build
2.2.使用 CMake 生成构建文件
在构建目录中运行 CMake,以生成适合当前平台的构建系统文件(例如 Makefile、Ninja 构建文件、Visual Studio 工程文件等)。
运行 CMake 配置:在构建目录中运行 CMake 命令,指定源代码目录。源代码目录是包含 CMakeLists.txt 文件的目录。
cmake ..
如果需要指定生成器(如 Ninja、Visual Studio),可以使用 -G 选项。例如:
cmake -G "Ninja" ..
如果需要指定构建类型(如 Debug 或 Release),可以使用 -DCMAKE_BUILD_TYPE 选项。例如:
cmake -DCMAKE_BUILD_TYPE=Release ..
检查配置结果:CMake 会输出配置过程中的详细信息,包括找到的库、定义的选项等,如果没有错误,构建系统文件将被生成到构建目录中。
2.3.编译和构建
使用生成的构建文件进行编译和构建。
不同的构建系统使用不同的命令。
使用 Makefile(或类似构建系统):如果使用 Makefile,可以运行 make 命令来编译和构建项目。
make
如果要构建特定的目标,可以指定目标名称。例如:
make MyExecutable
使用 Ninja:如果使用 Ninja 构建系统,运行 ninja 命令来编译和构建项目。
ninja
与 make 类似,可以构建特定的目标:
ninja MyExecutable
使用 Visual Studio:如果生成了 Visual Studio 工程文件,可以打开 .sln 文件,然后在 Visual Studio 中选择构建解决方案。
也可以使用 msbuild 命令行工具来编译:
msbuild MyProject.sln /p:Configuration=Release
2.4.清理构建文件
构建过程中生成的中间文件和目标文件可以通过清理操作删除。
使用 Makefile:运行 make clean 命令(如果定义了清理规则)来删除生成的文件。
make clean
使用 Ninja:运行 ninja clean 命令(如果定义了清理规则)来删除生成的文件。
ninja clean
手动删除:可以手动删除构建目录中的所有文件,但保留源代码目录不变。例如:
rm -rf build/*
2.5.重新配置和构建
如果修改了 CMakeLists.txt 文件或项目设置,可能需要重新配置和构建项目。
重新运行 CMake 配置:在构建目录中重新运行 CMake 配置命令。
cmake ..
重新编译:使用构建命令重新编译项目。
make
3.跨平台构建示例
1.Linux/macOS(CMake + Make)
# 配置构建环境
mkdir build && cd build
cmake .. # 默认生成 Makefile
# 编译
make -j$(nproc) # 并行编译(nproc 获取 CPU 核心数)
# 安装
make install
2.Windows(CMake + Ninja)
# 配置构建环境(使用 Ninja 加速)
mkdir build && cd build
cmake -G Ninja ..
# 编译
ninja
# 安装
ninja install
3.Windows(CMake + MSVC)
# 生成 Visual Studio 项目
mkdir build && cd build
cmake -G "Visual Studio 17 2022" ..
# 编译(使用 MSBuild)
cmake --build . --config Release
# 或直接打开 .sln 文件用 Visual Studio 编译
start my_project.sln
4.工具链与交叉编译
1.指定工具链文件
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm.cmake
2.工具链文件示例(arm-linux-gnueabihf)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# 指定交叉编译工具
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# 指定系统根目录
set(CMAKE_FIND_ROOT_PATH /path/to/arm-rootfs)
# 仅在根目录查找依赖
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
5.CMake构建后的项目结构解析
5.1.CMake构建后的目录结构
CMake构建完成后,会在项目的根目录下生成一个名为build
的目录。这个目录是CMake构建过程中所有中间文件和最终生成的目标文件的存放地。下面我们将详细解析这个目录的结构。
首先,我们来看一下build
目录的一级子目录:
- CMakeFiles:这个目录中存放的是CMake在构建过程中生成的临时文件,包括编译器检查的结果、Find模块(Find Modules)查找的结果等。这些文件主要用于CMake自身的需求,一般情况下,我们不需要关注这个目录的内容。
- Testing:如果你的项目中包含了CTest测试,那么这个目录将会被生成。它包含了所有CTest测试的结果。
- bin:这个目录中包含了所有的可执行文件(Executable Files)。如果你的CMake项目中包含了多个可执行文件,那么它们都会被放在这个目录中。
- lib:这个目录中包含了所有的库文件(Library Files)。无论是静态库(Static Libraries)还是动态库(Dynamic Libraries),都会被放在这个目录中。
接下来,我们再深入到CMakeFiles目录中,看一下它的二级子目录:
- project.dir:这个目录中包含了项目构建过程中的临时文件,如.o文件和.d文件。这些文件是编译器在编译源代码时生成的。
- CMakeOutput.log:这个文件记录了CMake在配置过程中的输出信息,包括编译器检查的结果、Find模块查找的结果等。
- CMakeError.log:这个文件记录了CMake在配置过程中遇到的错误信息。
以上就是CMake构建后的目录结构的基本情况。在实际的项目中,可能会根据项目的具体需求,生成更多的子目录和文件。但是,这些基本的目录和文件是你在任何一个使用CMake构建的项目中都能看到的。
5.2.构建生成的文件类型及其作用
CMake构建过程中会生成多种类型的文件,每种文件都有其特定的作用。下面我们将详细解析这些文件的类型和作用。
- CMakeFiles目录:这个目录中存放的是CMake在构建过程中生成的临时文件,包括编译器检查的结果、Find模块(Find Modules)查找的结果等。这些文件主要用于CMake自身的需求,一般情况下,我们不需要关注这个目录的内容。
- project.dir目录:这个目录中包含了项目构建过程中的临时文件,如.o文件和.d文件。这些文件是编译器在编译源代码时生成的。
- CMakeOutput.log文件:这个文件记录了CMake在配置过程中的输出信息,包括编译器检查的结果、Find模块查找的结果等。
- CMakeError.log文件:这个文件记录了CMake在配置过程中遇到的错误信息。
- Testing目录:如果你的项目中包含了CTest测试,那么这个目录将会被生成。它包含了所有CTest测试的结果。
- bin目录:这个目录中包含了所有的可执行文件(Executable Files)。如果你的CMake项目中包含了多个可执行文件,那么它们都会被放在这个目录中。
- lib目录:这个目录中包含了所有的库文件(Library Files)。无论是静态库(Static Libraries)还是动态库(Dynamic Libraries),都会被放在这个目录中。
以上就是CMake构建过程中生成的主要文件类型及其作用。理解这些文件的作用,可以帮助我们更好地理解CMake的构建过程。
5.3.CMakeLists.txt与生成的Makefile的关系
在CMake构建系统中,CMakeLists.txt文件和生成的Makefile文件之间存在着密切的关系。下面我们将详细解析这种关系。
CMakeLists.txt是CMake构建系统的核心文件,它定义了项目的构建规则和依赖关系。在执行CMake命令时,CMake会读取CMakeLists.txt文件,解析其中的构建规则和依赖关系,然后生成相应的Makefile文件。
Makefile文件是由CMake根据CMakeLists.txt文件生成的,它是Make构建工具可以直接读取的构建脚本。Makefile文件中包含了具体的编译命令和链接命令,以及源文件和目标文件之间的依赖关系。
在一个CMake项目中,通常会有多个CMakeLists.txt文件,每个目录下都可以有一个CMakeLists.txt文件。这些CMakeLists.txt文件中定义的构建规则和依赖关系,会被CMake合并到一起,生成一个或多个Makefile文件。
如果一个CMake项目中只有一个CMakeLists.txt文件,那么CMake会生成一个Makefile文件。如果一个CMake项目中有多个CMakeLists.txt文件,那么CMake会在每个CMakeLists.txt文件所在的目录下生成一个Makefile文件。这些Makefile文件中,顶层目录下的Makefile文件是主Makefile文件,它会调用其他目录下的Makefile文件。
总的来说,CMakeLists.txt文件和生成的Makefile文件之间的关系是:CMakeLists.txt文件定义了项目的构建规则和依赖关系,CMake根据CMakeLists.txt文件生成Makefile文件,然后Make根据Makefile文件执行具体的构建任务。
6.完整示例项目
1.项目结构
my_project/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ └── lib/
│ ├── utils.cpp
│ └── utils.h
└── tests/
└── test_main.cpp
2.CMakeLists.txt 示例
cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0.0)
# 添加可执行文件
add_executable(my_app src/main.cpp src/lib/utils.cpp)
# 设置 C++ 标准
set_target_properties(my_app PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
# 添加测试(可选)
if(ENABLE_TESTING)
enable_testing()
add_executable(my_test tests/test_main.cpp src/lib/utils.cpp)
add_test(NAME MyTest COMMAND my_test)
endif()
# 安装规则
install(TARGETS my_app DESTINATION bin)
3.构建命令
# 配置并编译(Debug 模式)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_TESTING=ON
cmake --build build
# 运行测试
ctest --test-dir build
# 安装到 /usr/local
sudo cmake --install build
7.总结
CMake的构建一个很复杂的工程,根据平台的不同构建规则和过程有所不同,CMake屏蔽了底层的实现差异,但是还是要去了解和熟悉,这会让我们在日后的使用过程当中少出差错,即便出了问题,也有助于我们很快的找到问题,很快的解决它。
相关链接
- CMake 官网 CMake - Upgrade Your Software Build System
- CMake 官方文档:CMake Tutorial — CMake 4.0.2 Documentation
- CMake 源码:https://github.com/Kitware/CMake
- CMake 源码:Sign in · GitLab