目录

  1. 实战项目概述
  2. 项目结构与需求
  3. CMakeLists.txt 配置
  4. 构建与编译
  5. 目标管理与依赖
  6. 自定义构建步骤与测试
  7. 多平台支持与交叉编译
  8. 总结与优化
  9. 参考资料

实战项目概述

本实战练习将带领你完成一个简单的 C++ 项目,并使用 CMake 来构建它。这个项目将涉及多个模块、库、外部依赖,并且将涵盖跨平台构建、目标管理和自定义构建步骤等高级特性。

我们的项目是一个数学库,包含几个计算模块(如加法、乘法),并将其与一个简单的应用程序(用于展示计算结果)结合。我们还将使用 CMake 来管理源代码和依赖。


项目结构与需求

项目结构如下:

MathLib/
├── CMakeLists.txt
├── include/
│   └── mathlib.h
├── src/
│   ├── add.cpp
│   └── multiply.cpp
└── app/
    ├── CMakeLists.txt
    └── main.cpp

  • MathLib:数学库,包含加法和乘法模块。
  • app:一个简单的应用程序,调用数学库并展示计算结果。

项目需求

  1. MathLib
    • 包含两个功能模块:加法(add.cpp)和乘法(multiply.cpp)。
    • 提供公共头文件 mathlib.h,声明加法和乘法函数。
  2. 应用程序
    • 引用 MathLib,实现一个简单的 main.cpp 来使用加法和乘法功能。
  3. CMake 管理
    • 使用 CMake 管理整个项目的构建过程,包括 MathLib 和应用程序。
    • 使用 target_link_libraries 管理 MathLib 作为应用程序的依赖。

CMakeLists.txt 配置

1. 根目录 CMakeLists.txt

在项目的根目录下创建 CMakeLists.txt,并定义项目名称、版本以及最低 CMake 版本要求:

cmake_minimum_required(VERSION 3.10)
project(MathApp VERSION 1.0)

# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 添加子目录
add_subdirectory(MathLib)
add_subdirectory(app)

这里:

  • add_subdirectory(MathLib)add_subdirectory(app) 将分别处理 MathLib 和应用程序的 CMake 配置。

2. MathLib 目录的 CMakeLists.txt

MathLib 目录中,创建 CMakeLists.txt,配置 MathLib 库:

# 指定 MathLib 库包含目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

# 添加源文件
add_library(MathLib STATIC
    src/add.cpp
    src/multiply.cpp
)

# 设置 MathLib 库的目标名称
target_include_directories(MathLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

这里:

  • add_library(MathLib STATIC ...) 将生成一个静态库 MathLib
  • target_include_directories(MathLib PUBLIC ...) 确保 MathLib 库的头文件可以被其他项目引用。

3. app 目录的 CMakeLists.txt

app 目录中,创建 CMakeLists.txt,配置应用程序:

# 添加可执行文件
add_executable(MathApp main.cpp)

# 链接 MathLib 库
target_link_libraries(MathApp PRIVATE MathLib)

这里:

  • add_executable(MathApp main.cpp) 创建一个名为 MathApp 的可执行文件。
  • target_link_libraries(MathApp PRIVATE MathLib)MathLib 静态库链接到应用程序中。

构建与编译

1. 创建构建目录

为了保持源代码目录的整洁,首先在项目根目录创建一个单独的构建目录:

mkdir build
cd build

2. 运行 CMake 配置

在构建目录中,运行以下命令来配置项目:

cmake ..

CMake 会自动查找源代码目录中的 CMakeLists.txt 文件,并生成适合当前平台的构建文件。

3. 编译项目

使用以下命令来编译项目:

cmake --build .

CMake 将根据生成的构建文件开始编译 MathLib 和应用程序。

4. 运行应用程序

编译完成后,运行生成的应用程序:

./app/MathApp

假设 main.cpp 的内容如下:

#include <iostream>
#include "mathlib.h"

int main() {
    std::cout << "Addition: " << add(3, 4) << std::endl;
    std::cout << "Multiplication: " << multiply(3, 4) << std::endl;
    return 0;
}

输出:

Addition: 7
Multiplication: 12


目标管理与依赖

CMakeLists.txt 中,我们通过 target_link_librariesMathLib 库链接到应用程序中。CMake 会自动处理库和目标的依赖关系,确保构建过程中 MathLib 先于应用程序编译。

target_link_libraries(MathApp PRIVATE MathLib)

这表示 MathApp 依赖于 MathLib,并且链接方式为 PRIVATE,即只有 MathApp 使用 MathLib


自定义构建步骤与测试

1. 自定义构建命令

有时,我们需要在构建过程中执行自定义命令,例如生成文件或运行脚本。可以使用 add_custom_command 来实现这一点。

例如,我们想在构建时生成一个文件:

add_custom_command(
    OUTPUT generated.txt
    COMMAND echo "This is a generated file" > generated.txt
    DEPENDS some_input_file.txt
    COMMENT "Generating generated.txt"
)

2. 添加测试

可以使用 CMake 的 add_test 命令来添加单元测试。例如,使用 Google Test 测试库:

enable_testing()

add_executable(MyTest test_main.cpp)
target_link_libraries(MyTest PRIVATE MathLib)
add_test(NAME MyTest COMMAND MyTest)


多平台支持与交叉编译

CMake 可以为不同平台生成构建文件,支持 Windows、Linux、macOS 等操作系统,并支持交叉编译。通过设置工具链文件,可以指定交叉编译工具。

例如,为 ARM 平台编译:

cmake -DCMAKE_TOOLCHAIN_FILE=toolchain-arm.cmake ..

工具链文件 toolchain-arm.cmake 包含目标平台的相关配置,如交叉编译器路径、系统名称等。


总结与优化

通过本实战练习,你已经了解了如何使用 CMake 来配置和构建一个多模块项目。我们探讨了目标管理、依赖关系、跨平台构建、外部项目、以及自定义构建步骤等高级特性。

可以通过进一步优化和扩展,例如添加更多的测试、完善跨平台支持、引入外部依赖管理工具等,来提升项目的可维护性和可移植性。


参考资料