一文学会CMakeLists.txt: CMake现代C++跨平台工程化实战

你能学到什么?

朋友们好久不见,我是alibli,好久没有更新博客了。今天本人将通过构造一个实际的虚拟小项目,来让你彻底掌握CMake跨平台工程构建,学会CMakeLists.txt语法。该项目实现了一个简单的平方、立方的计算程序,只为演示工程构建方法。

每一行代码都会有非常非常详细的解释!

你将掌握如下内容:

  1. 构建静态库
  2. 构建动态库
  3. 构建可执行程序
  4. 动态库如何调用静态库
  5. 可执行程序如何调用动态库

项目整体构建

项目目录:

bash 复制代码
calculator_project/
├── CMakeLists.txt                 # 外层主 CMake 文件
├── math_utils/                    # 静态库源码
│   ├── CMakeLists.txt
│   ├── MathUtils.h
│   └── MathUtils.cpp
├── calculator/                    # 动态库(依赖静态库)
│   ├── CMakeLists.txt
│   ├── Calculator.h
│   └── Calculator.cpp
└── app/                           # 主程序
    ├── CMakeLists.txt
    └── main.cpp

外层CMakeLists.txt

bash 复制代码
# calculator_project/CMakeLists.txt

# 1. 指定项目所需的最低 CMake 版本
#    如果用户系统中的 CMake 版本低于 3.10,会报错
cmake_minimum_required(VERSION 3.10)

# 2. 定义项目名称为 "CalculatorProject"
#    LANGUAGES CXX 表示这是一个 C++ 项目
#    CMake 会自动查找 C++ 编译器(如 g++)
project(CalculatorProject LANGUAGES CXX)

# 3. 设置 C++ 标准为 C++17
#    要求编译器必须支持 C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 4. 禁用编译器特定的扩展(如 GNU 扩展)
#    强制使用标准 C++,提高可移植性
set(CMAKE_CXX_EXTENSIONS OFF)

# 5. 启用测试支持(即使现在不用,也先打开)
#    后续可以用 ctest 命令运行测试
enable_testing()

# 6. 添加子目录 math_utils
#    CMake 会进入 math_utils/ 目录并读取其 CMakeLists.txt
#    该目录将构建一个静态库
add_subdirectory(math_utils)

# 7. 添加子目录 calculator
#    该目录将构建一个动态库,依赖上面的静态库
add_subdirectory(calculator)

# 8. 添加子目录 app
#    构建主程序,链接动态库
add_subdirectory(app)

静态库构建

进入math_utils目录

CMakeLists.txt

bash 复制代码
# calculator_project/math_utils/CMakeLists.txt

# 1. 定义一个静态库目标,名为 "math_utils"
#    STATIC 表示生成静态库(.a 文件)
#    源文件列表:MathUtils.cpp
add_library(math_utils STATIC
    MathUtils.cpp
)

# 2. 设置目标 math_utils 的头文件搜索路径
#    PUBLIC 表示:
#      - math_utils 自己需要这些头文件(PRIVATE 部分)
#      - 链接 math_utils 的目标也能看到这些头文件(INTERFACE 部分)
#    ${CMAKE_CURRENT_SOURCE_DIR} 是当前目录(即 math_utils/)
#    所以其他代码可以 #include "MathUtils.h"
target_include_directories(math_utils
    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
)

# 3. 关键:启用 PIC,以便被动态库链接
set_target_properties(math_utils PROPERTIES
    POSITION_INDEPENDENT_CODE ON
)

# 4. 为 math_utils 添加编译定义(可选)
#    这里定义一个宏 MATH_UTILS_VERSION="1.0"
#    在 MathUtils.cpp 中可以用 #ifdef MATH_UTILS_VERSION 条件编译
target_compile_definitions(math_utils
    PRIVATE MATH_UTILS_VERSION=\"1.0\"
)

# 5. 输出一条状态信息,帮助调试
#    构建时会显示:-- Building static library: math_utils
message(STATUS "Building static library: math_utils")

MathUtils.h

cpp 复制代码
// calculator_project/math_utils/MathUtils.h
  2
  3 #ifndef MATH_UTILS_H
  4 #define MATH_UTILS_H
  5
  6 // 简单的数学工具类(静态库提供)
  7 class MathUtils {
  8 public:
  9     // 计算平方
 10     static double square(double x);
 11
 12     // 计算立方
 13     static double cube(double x);
 14 };
 15
 16 #endif // MATH_UTILS_H

MathUtils.cpp

cpp 复制代码
// calculator_project/math_utils/MathUtils.cpp

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

// 实现平方函数
double MathUtils::square(double x) {
    return x * x;
}

// 实现立方函数
double MathUtils::cube(double x) {
    return x * x * x;
}

// 如果定义了版本宏,打印版本(用于验证独立编译)
#ifdef MATH_UTILS_VERSION
#include <iostream>
void print_version() {
    std::cout << "MathUtils Version: " << MATH_UTILS_VERSION << std::endl;
}
#endif

动态库构建

进入calculator目录

CMakeLists.txt

bash 复制代码
# calculator_project/calculator/CMakeLists.txt

# 1. 定义一个共享库(动态库),名为 "calculator"
#    SHARED 表示生成 .so 文件(Linux)或 .dll(Windows)
#    源文件:Calculator.cpp
add_library(calculator SHARED
    Calculator.cpp
)

# 2. 设置 calculator 的头文件路径
#    PUBLIC:自己用 + 暴露给使用者
target_include_directories(calculator
    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
)

# 3. 链接依赖:calculator 依赖 math_utils 静态库
#    PRIVATE 表示 math_utils 仅 calculator 内部使用,不暴露给主程序
#    但主程序仍能通过 calculator 调用 MathUtils 的功能
target_link_libraries(calculator
    PRIVATE math_utils
)

# 4. 为动态库添加版本号
#    这会影响生成的文件名,如 libcalculator.so.1.0
set_target_properties(calculator PROPERTIES
    VERSION 1.0
    SOVERSION 1
)

# 5. 输出状态信息
message(STATUS "Building shared library: calculator (depends on math_utils)")

Caculator.h

cpp 复制代码
// calculator_project/calculator/Calculator.h

#ifndef CALCULATOR_H
#define CALCULATOR_H

// 计算器类,使用 MathUtils 提供的功能
class Calculator {
public:
    // 计算一个数的平方(调用静态库)
    double square(double x);

    // 计算一个数的立方(调用静态库)
    double cube(double x);
};

#endif // CALCULATOR_H

Caculator.cpp

cpp 复制代码
// calculator_project/calculator/Calculator.cpp

#include "Calculator.h"
#include "MathUtils.h"  // 包含静态库头文件

// 使用 MathUtils::square
double Calculator::square(double x) {
    return MathUtils::square(x);
}

// 使用 MathUtils::cube
double Calculator::cube(double x) {
    return MathUtils::cube(x);
}

可执行程序构建

进入app

CMakeLists.txt

bash 复制代码
# calculator_project/app/CMakeLists.txt

# 1. 创建可执行文件 "app",源文件 main.cpp
add_executable(app
    main.cpp
)

# 2. 链接 app 与动态库 calculator
#    PRIVATE:仅 app 使用
target_link_libraries(app
    PRIVATE calculator
)

# 3. 确保 app 能找到 calculator 的头文件
#    因为 calculator 的 PUBLIC include 路径会被继承
target_include_directories(app
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
)

# 4. 添加一个测试(可选)
#    创建一个测试,运行 app
add_test(
    NAME test_app_run
    COMMAND app
)

main.cpp

cpp 复制代码
// calculator_project/app/main.cpp

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

int main() {
    Calculator calc;

    std::cout << "Square of 5: " << calc.square(5) << std::endl;   // 25
    std::cout << "Cube of 3: " << calc.cube(3) << std::endl;       // 27

    return 0;
}

构建&测试

进入根目录,即calculator_project目录

构建,为了保持工作目录干净新建build目录。

bash 复制代码
mkdir build
cd build
cmake ..
make

运行

bash 复制代码
./app/app

运行结果显示为

bash 复制代码
Square of 5: 25
Cube of 3: 27
相关推荐
奔跑吧邓邓子1 小时前
【C++实战(74)】深入C++安全编程:密码学实战之旅
c++·安全·实战·密码学·安全编程
板鸭〈小号〉1 小时前
Socket网络编程(1)——Echo Server
开发语言·网络·php
明天会有多晴朗1 小时前
C语言入门教程(第1讲):最通俗的C语言常见概念详解与实战讲解
c语言·开发语言·c++
爱上妖精的尾巴1 小时前
5-20 WPS JS宏 every与some数组的[与或]迭代(数组的逻辑判断)
开发语言·前端·javascript·wps·js宏·jsa
Larry_Yanan1 小时前
QML学习笔记(二十四)QML的Keys附加属性
c++·笔记·qt·学习·ui
gopher95111 小时前
Go 语言的 panic 和 recover
开发语言·golang
豆沙沙包?1 小时前
2025年--Lc165--H637.二叉树的层平均值(二叉树的层序遍历)--Java版
java·开发语言
小蒜学长2 小时前
springboot二手儿童绘本交易系统设计与实现(代码+数据库+LW)
java·开发语言·spring boot·后端
李小白662 小时前
Python文件操作
开发语言·python
龙木之森2 小时前
纯 C++ 开发的 Telegram Bot 框架
c++·tui·telegram·bot