目录
实战项目概述
本实战练习将带领你完成一个简单的 C++ 项目,并使用 CMake 来构建它。这个项目将涉及多个模块、库、外部依赖,并且将涵盖跨平台构建、目标管理和自定义构建步骤等高级特性。
我们的项目是一个数学库,包含几个计算模块(如加法、乘法),并将其与一个简单的应用程序(用于展示计算结果)结合。我们还将使用 CMake 来管理源代码和依赖。
项目结构与需求
项目结构如下:
MathLib/
├── CMakeLists.txt
├── include/
│ └── mathlib.h
├── src/
│ ├── add.cpp
│ └── multiply.cpp
└── app/
├── CMakeLists.txt
└── main.cpp
- MathLib:数学库,包含加法和乘法模块。
- app:一个简单的应用程序,调用数学库并展示计算结果。
项目需求
- MathLib:
- 包含两个功能模块:加法(add.cpp)和乘法(multiply.cpp)。
- 提供公共头文件
mathlib.h
,声明加法和乘法函数。
- 应用程序:
- 引用
MathLib
,实现一个简单的main.cpp
来使用加法和乘法功能。
- 引用
- 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_libraries
将 MathLib
库链接到应用程序中。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 来配置和构建一个多模块项目。我们探讨了目标管理、依赖关系、跨平台构建、外部项目、以及自定义构建步骤等高级特性。
可以通过进一步优化和扩展,例如添加更多的测试、完善跨平台支持、引入外部依赖管理工具等,来提升项目的可维护性和可移植性。
发表回复