10分钟学习CMake ①

一、为什么学习Cmake

在软件开发中,一个可执行文件从源代码 (.c / .cpp) 到最终运行的程序 (.exe / .out) 需要经历 预处理 → 编译 → 汇编 → 链接 四个核心步骤。

对于小项目,手写命令还可以完成;但在 大型项目、多文件工程、跨平台编译 中,这些步骤非常复杂,需要构建工具来帮助管理。

CMake 正是其中最主流的跨平台构建工具。

为了理解为什么要学习 CMake,必须先理解下面这些基础的构建流程

二、一般的可执行文件是如何生成的

1. 预处理(Preprocessing)

处理以 # 开头的指令,包括:

  • 展开头文件

    示例:#include <iostream> → 把对应头文件内容插入代码

  • 宏替换
    #define PI 3.14 → 所有 PI 替换为 3.14

  • 条件编译
    #ifdef DEBUG#if 0

  • 删除注释

📌 预处理器输出一个 .i(或 .ii)文件,纯 C/C++ 代码,无宏、无注释、无头文件引用。


2. 编译(Compilation)

将预处理后的 .i 文件翻译成汇编代码(.s 或 .asm):

  • 语法分析(解析 C/C++ 语句)

  • 语义分析

  • 生成中间代码

  • 优化代码

  • 生成汇编代码

📌 编译器输出汇编语言文件,接近底层 CPU 指令。


3. 汇编(Assembling)

将汇编代码 (.s) 转换为 机器码 ,生成 .o.obj 文件。

  • 把汇编指令翻译成 CPU 机器指令

  • 构建符号表(记录函数、变量的地址信息)

  • 每一个 .cpp 会生成一个独立的 .o / .obj

📌 汇编器输出目标文件(Object File),但此时还不能运行。


4. 链接(Linking)

将多个 .o 文件 + 库文件合成为最终可执行程序

主要作用:

  1. 符号解析

    比如 main.cpp 调用了 add(),链接器负责找到 add 在 math.o 中的位置。

  2. 地址重定位

    把所有函数、变量的"地址引用"转换为最终的实际运行地址。

  3. 连接静态库/动态库

    libopencv_world.a, libstdc++.so

  4. 生成最终可执行文件

    Windows:.exe

    Linux:无后缀(ELF)

📌 链接器输出最终可执行文件

✅ 三、CMake 中常用的命令

下面列出 最常用、最基础、最必须掌握 的 CMake 命令(已整理表达):

命令 作用说明
cmake_minimum_required() 指定 CMake 的最低版本要求
project() 设置项目名称、版本、语言等
add_executable() 生成可执行文件
add_library() 生成静态库或动态库
target_link_libraries() 链接库
target_include_directories() 添加头文件目录
set() 设置变量
message() 输出信息(调试用)
add_subdirectory() 添加子目录(管理大型项目必备)
find_package() 查找外部库,如 OpenCV、PCL、Ceres
file(GLOB ...) 扫描文件(自动收集源码)
install() 安装可执行文件或库

这些命令构成了 CMakeLists.txt 的基础写法。

四、CMakeLists.txt的编写

4.1. CMake 的使用步骤(概述)

编写 CMakeLists.txt 的典型步骤如下:

指定 CMake 最低版本

声明项目

设置编译选项(可选)

指定源文件

生成可执行文件或库

链接外部库(如 OpenCV)

设置头文件路径

执行 cmake 命令生成工程

使用构建工具编译

4.2、CMakeLists.txt 的具体写法

1. cmake_minimum_required()

作用:

指定当前项目可使用的 CMake 最低版本。如果版本过低,CMake 会报错,避免使用老版本带来的兼容性问题。

语法:

cmake_minimum_required(VERSION 3.14)

意思:

👉 要求 CMake 版本 至少是 3.14 才能构建该项目。


2. project()

作用:

定义项目名称、版本和使用的语言。

语法:

project(MyProject LANGUAGES CXX)

意思:

项目叫 MyProject ,主要使用 C++(CXX)。

也可以写得更详细:

project(MyProject VERSION 1.0 LANGUAGES C CXX)


3. add_executable()

作用:

告诉 CMake: "我要生成一个可执行程序,这个程序由哪些源文件组成"。

语法:

add_executable(目标名称 源文件列表)

比如:

add_executable(MyApp main.cpp) 单个.CPP

详细解释:

  • MyApp ------ 最终生成的可执行文件的名称

    ✔ Windows 下生成:MyApp.exe

    ✔ Linux / macOS 下生成:MyApp

  • main.cpp ------ 编译这个可执行文件所需的源代码文件

也可以是多个文件:

add_executable(MyApp main.cpp utils.cpp math.cpp)

多个文件中间可以用:空格 或者隔开


4. add_library()

作用:

生成一个库(静态库或动态库)。

库文件可以被其他程序调用。

add_library(MyLib math.cpp utils.cpp)

平台 动态库文件名 说明
Linux libMyLib.so so = shared object
macOS libMyLib.dylib Apple 独有格式
Windows MyLib.dll(以及对应的 MyLib.lib 导入库) Windows 动态库为 .dll
  • 生成静态库:libMyLib.aMyLib.lib

  • 静态库(Static Library)

平台 静态库文件名 说明
Linux libMyLib.a 自动加前缀 lib,扩展名为 .a
macOS libMyLib.a 与 Linux 相同
Windows MyLib.lib lib 前缀,扩展名 .lib

总结:

  • Unix 系(Linux/macOS) → lib + 名称 + .a

  • Windows → 名称 + .lib

  • 生成动态库:

  • libMyLib.solibMyLib.dylibMyLib.dll


作用:

告诉 CMake:

"把某个库链接到可执行文件或另一个库"。

示例:

target_link_libraries(MyApp PRIVATE MyLib)

意思:

MyApp 这个可执行文件要链接 MyLib 这个库。


6. target_include_directories()

作用:

为某个目标(可执行文件/库)指定头文件路径。

target_include_directories(MyApp PRIVATE ${CMAKE_SOURCE_DIR}/include)

意思:

让编译器去 include 目录里找头文件。


7. set()

作用:

设置变量(字符串、数字、路径、列表都可以)。

set(SRC main.cpp utils.cpp)


8. message()

作用:

打印信息,用于调试。

message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")


9. add_subdirectory()

作用:

用于多文件夹(大型工程)时,将子目录添加进来。

add_subdirectory(src)


10. find_package()

作用:

查找系统中的外部库,例如 OpenCV、PCL、Eigen。

find_package(OpenCV REQUIRED) target_link_libraries(MyApp PRIVATE ${OpenCV_LIBS})

4.3、CMakeLists.txt 的编写(带解释)

下面给一份最小可运行 + 每句话都有解释 的 CMakeLists.txt。


📌 示例项目结构

复制代码
MyProject/
│── CMakeLists.txt
│── main.cpp

📌 CMakeLists.txt

复制代码
# 1. 指定 CMake 最低版本(3.14 是常用稳定版本)
cmake_minimum_required(VERSION 3.14)

# 2. 定义项目名称为 MyProject,语言使用 C++
project(MyProject LANGUAGES CXX)

# 3. 指定 C++ 标准为 C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 4. 定义一个可执行文件
#    MyApp 是可执行程序的名字(最终生成 MyApp.exe 或 MyApp)
#    main.cpp 是构建这个程序需要的源文件
add_executable(MyApp main.cpp)

📌 main.cpp

复制代码
#include <iostream>

int main() {
    std::cout << "Hello CMake!" << std::endl;
    return 0;
}

🎯 五、构建步骤(适合教学)

在终端执行:

复制代码
mkdir build
cd build
cmake ..
cmake --build .

运行:

复制代码
./MyApp

输出:

复制代码
Hello CMake!
相关推荐
gcfer7 小时前
C/C++八股文知识积累5—项目从构建到运行的流程
make·cmake·c++八股·项目构建流程
PyGata8 天前
CMake学习笔记(一)
学习笔记·cmake·cmakelists
charlee449 天前
CMake构建学习笔记26-OpenBLAS库的构建
多线程·cmake·openblas·blas/lapack
charlee4410 天前
CMake构建学习笔记30-Ceres Solver库的构建
静态库·非线性优化·cmake·buildcppdependency·ceres solver
charlee4411 天前
CMake构建学习笔记28-gmp&mpfr库的构建
cmake
charlee4411 天前
CMake构建学习笔记27-初步完成C&C++自动化构建工具
跨平台·cmake·构建·依赖管理
羑悻的小杀马特15 天前
现代 CMake 项目构建完全指南:从基础配置到高级技巧的目标属性管理与智能依赖传递机制解析
cmake·项目构建·属性传递机制
Theliars20 天前
Ubuntu 上使用 VSCode 调试 C++ (CMake 项目) 指南
c++·vscode·ubuntu·cmake