Cmake学习
0 推荐一个教程
- B站视频链接:【C/C++】CMake 保姆级教程 - 爱编程的大丙 - Bilibili
- 对应的教程文章:CMake 保姆级教程(上)、CMake 保姆级教程(下)
1 预知识
1.1 不同操作系统对C语言的编译
1.1.1 Windows操作系统
在Windows系统中,有一个最常用的集成开发环境IDE:Visual Studio,一般而言,不是特别复杂的工程都可以在这个Visual Studio中一次性完成。
如果我们不用Visual Studio呢?那怎么开发c语言工程呢。
第一步:使用文本编辑器编写 C 语言源代码文件
- 要做什么:新建文件,编写符合 C 语言语法的代码,保存为以 .c 为后缀名的源代码文件(例如 main.c、calc.c)。
- 推荐工具:
- 基础款:记事本(Windows 自带)、Notepad++(轻量、支持语法高亮,比记事本更友好);
- 进阶款:VS Code(免费、有功能强大的插件)、Sublime Text。
第二步:安装并配置 C 语言编译器(核心环节)
- 要做什么:安装一款 C 语言编译器,配置系统环境变量(可选但强烈推荐),确保能在命令行中直接调用编译器命令。
- 为什么要这么做:
- 编译器是连接 C 语言源代码和机器码的核心桥梁,它的作用是将人类可读的
.c源文件(高级语言)编译(compile) 转换为计算机可识别的二进制目标文件(通常以.o或.obj为后缀名); - 没有编译器,
.c源文件只是一堆纯文本,无法被计算机执行,这是编译型语言开发的必要环节; - 配置环境变量的目的是:无需在命令行中输入编译器的完整路径(如
D:\MinGW-w64\mingw64\bin\gcc.exe),只需直接输入gcc即可调用编译器,简化后续操作。
- 编译器是连接 C 语言源代码和机器码的核心桥梁,它的作用是将人类可读的
- 推荐工具:
- MinGW-w64(Windows 环境首选,免费开源、轻量,兼容 GCC 编译器,支持 32/64 位系统);
- TDM-GCC:另一个 MinGW 的打包版本,安装简单。
- MSYS2 + GCC:更现代、更新及时的环境。
- MSVC(微软编译器,Visual Studio 自带,若不想装完整 VS,可安装「Visual Studio Build Tools」单独获取,但是不推荐此时用 MSVC,因为它通常绑定在 Visual Studio 中,命令行使用较复杂 )。
❓问题1:MinGW-w64、MSVC等都是C 语言编译器吗?
✅不完全是,二者不能简单等同于 “C 语言编译器”,性质有明确区别。
MSVC:包含 C/C++ 编译器,是一套完整的编译工具链(狭义上可称其编译器)
严格来说,MSVC(Microsoft C/C++ Compiler,微软 C/C++ 编译器)的核心编译器组件是 cl.exe(对应 C 语言编译,也支持 C++),我们日常说的 “MSVC”,其实是一套完整的 Windows 平台 C/C++ 编译工具链(包含编译器、链接器、库文件、头文件、编译辅助工具等)。
它可以直接编译 C 语言源代码,是 C 语言编译器的一种,但 “MSVC” 这个称呼的范畴大于 “单一 C 编译器”,只是在日常开发中,我们常简化将其称为 “MSVC 编译器”。
MinGW-w64:不是编译器,是一套Windows 平台下的开源工具集 / 编译环境
MinGW-w64 的核心是把 Linux 平台下的 GCC 编译工具链移植到 Windows 系统中,让开发者能在 Windows 上直接使用 GCC 相关工具,它本身不具备编译器的核心功能,只是一个 “载体” 或 “环境包”。
这套工具集中包含了 C 语言编译器(gcc.exe)、C++ 编译器(g++.exe)、链接器(ld.exe)、调试器(gdb.exe)、C/C++ 标准库、以及适配 Windows 系统的相关依赖文件,方便开发者在 Windows 上进行跨平台 C/C++ 开发。
❓问题 2:GCC、G++ 又是什么?
✅GCC 和 G++ 都属于GNU 工具链中的核心编译工具。
- gcc全称:GNU Compiler Collection(GNU 编译器集合),注意 “Collection” 是 “集合” 的意思,早期 GCC 仅指 GNU C Compiler(GNU C 语言编译器),后来功能扩展,支持 C、C++、Java、Go 等多种语言,因此更名为 “编译器集合”。
- g++可以简单理解为gcc在c++语言上的拓展,它支持 C++ 语言的所有语法特性,默认链接 C++ 标准库(同时兼容 C 语言标准库),针对
.cpp后缀文件进行处理;另外,g++也可以兼容编译 C 语言代码(会将.c文件当作 C++ 代码处理,语法要求更严格),但反之gcc无法直接编译 C++ 代码(缺少 C++ 标准库链接和语法支持)。❓问题 3:MinGW-w64、MSVC 等和 GCC、G++ 有什么联系和区别?
✅核心目标一致:无论是 MinGW-w64、MSVC,还是 GCC、G++,最终目的都是将 C/C++ 高级语言源代码转换为对应平台可执行的二进制文件,支撑 C/C++ 项目的编译构建,是编译型语言开发的核心工具。
MinGW-w64 与 GCC、G++ 是 “载体与核心” 的关系:GCC、G++ 的原生运行平台是 Linux/Unix,而 MinGW-w64 的核心价值就是将 GCC、G++ 等 GNU 工具链移植并打包,使其能在 Windows 系统上正常运行—— 也就是说,你在 Windows 上通过 MinGW-w64 调用的
gcc.exe和g++.exe,本质上就是移植后的 GNU C/C++ 编译器,MinGW-w64 为其提供了 Windows 平台的运行环境、系统适配库、辅助工具等支撑。【注意,并不是说gcc、g++不能在Windows上运行,而是“可以直接运行”但并不能“能生成可用的 Windows 程序”,它还是按 Linux 的方式生成 ELF 文件、链接 glibc,那这个程序Windows 根本无法执行! “MinGW-w64 不单单只是个打包的作用”,它是 GCC 的 Windows 后端实现,重写了运行时和链接逻辑 】
MSVC 是微软专属的 Windows C/C++ 完整工具链,暂时可以理解为微软家不用gcc,自己自研了另一套编译工具。
第三步:手动编译源代码(预处理 → 编译 → 汇编 → 链接)
要做什么:打开命令行工具(CMD 或 PowerShell),切换到
.c源文件所在目录,执行编译器命令,完成编译操作。具体操作:
预处理(Preprocessing)
1
gcc -E main.c -o main.i
- 生成
main.i:展开所有#include、#define、处理条件编译等。 - 🔍 为什么:C 语言的宏、头文件等是“文本替换”机制,必须在真正编译前处理完毕。
- 生成
编译(Compilation to Assembly)
1
gcc -S main.i -o main.s
- 生成
main.s:将 C 代码转为汇编语言(与 CPU 架构相关)。 - 🔍 为什么:编译器前端将高级语言逻辑转化为低级但人类仍可读的汇编指令。
- 生成
汇编(Assembly to Object Code)
1
gcc -c main.s -o main.o
- 生成
main.o(或.obj):将汇编代码转为二进制目标文件(机器码,但尚未可执行)。 - 🔍 为什么:汇编器把助记符(如
mov,call)翻译成 CPU 能直接执行的二进制操作码。
- 生成
链接(Linking)
1
gcc main.o -o main.exe
- 生成
main.exe:将目标文件与标准库(如printf所在的 libc)合并,生成完整可执行文件。 - 🔍 为什么:你的程序调用了库函数(如
printf),这些函数的实现不在你的.c文件中,链接器负责“拼接”所有模块,并解析函数地址。
- 生成
1.1.2 Linux操作系统
在Linux操作系统下,集成开发环境不常见,也没有太多使用的。因为在Liunx环境下,大多数是基于命令行界面进行开发,那它里面就把源代码编辑、工程管理等拆分为了很多步骤。简单说就是把Windows中Visual Studio一次性完成的功能分开步骤来做了。
首先,Liunx下著名的代码编辑器——Vi、Vim
其次,Liunx下预处理、编译、汇编、链接——gcc/g++
当程序很简单,只有几个儿源文件时,直接就可以用gcc命令编译它。可是,如果我们的程序包含几十上百个源文件时该咋整?用gcc命令逐个去编译时,就发现很容易混乱而且工作量大,所以出现了make工具。
1.2 Make工具
1.2.1 Make简介
make工具可以看成是一个智能的批处理工具。它本身并没有编译和链接的功能,而是用类似于批处理的方式一通过调用makefile文件中用户指定的命令来进行编译和链接的。
1.2.2 makefile文件
简单的说就像一首歌的乐谱,make工具就像指挥家,指挥家根据乐谱指挥整个乐团怎么样演奏,make工具就根据makefile中的命令进行编译、汇编和链接的。
所以,makefile文件中肯定就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。
makefile在一些简单的工程完全可以人工拿下。但同样的问题,当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改,这时候就出现了下面的CMake工具。
1.2.3 CMake工具
CMake可以更加简单的生成makefile文件给上面那个make用。当然CMake还有其他更牛X功能——就是可以跨平台生成对应平台能用的makefile,我们就不用再自己去修改了。
- 在Windows操作系统中,若安装了Visual Studio,就可以使用CMake生成Visual Studio的工程文件;
- 在Liunx操作系统中,CMake用于生成Make的输入文件——makefile;
可是CMake根据什么生成makefile文件呢?
它又要根据一个叫CMakeLists.txt文件(学名组态档)去生成makefile。
从上面捋下来,看起来整个过程就像是套娃——只要哪个过程人工处理变复杂了,就开发一个工具简化人的工作。到这里暂时中介套娃了,程序员就必须自己手写CMakeLists.txt文件了
2 快速上手教程
2.1 初步体验
十分注意,下面的演示错了,就因为一个中文路径,导致我浪费了一上午查找原因。所以,要使用CMake,必须把工程建在全英文目录下面。
本节通过一个小项目,先来看一下Cmake最简单的用法。
首先,创建一个项目文件夹:hellowaorld,并用VSCode打开这个文件夹
然后,创建几个文件:
1 | // helloworld.c文件 |
1 | // myhead.h文件 |
1 | // hello.c文件 |
1 | // world.c文件 |
上述文件的目录结构如下:
1 | - helloworld |
接下来,再在hellowaorld文件夹下创建一个文件CMakeLists.txt,这是CMake的项目配置文件,文件名称必须是这个,不能随意。此外,虽然这个文件的后缀是.txt,但它不是简单的文本文档,在CMake中是一个脚本文件,CMake会解析其中的指令,并根据指令生成相应的构建文件。
1 | # 指定CMake的最小版本号,通过cmake --version命令查到下载的CMake版本号为4.2.1 |
上面这三条指令就是一个最简单的CMakeLists.txt,下面就可以执行 cmake命令生成项目了:
1 | # 注意,下面这里只是演示,实际一定要把项目建立在全英文目录下面 |
可以看到,一下子生成了很多文件(这里我已经把工程移动到D盘下面了,保证全英文目录):
我的电脑上安装了Visual Studio,因此默认生成了Visual Studio的工程文件。
但是,可以看到生成的工程文件和源码混合到了一起,非常不便于代码的管理,所以我们要单独创建一个目录,将生成的构建文件保存到这个目录中,一般会将这个目录定义为build。然后进入到这个目录下面,执行cmake ..注意是两个点,这样所有的工程文件就在build目录下面了,源文件不受影响。
这样,我们就可以使用Visual Studio打开HELLOWORLD.sln了(注意:ALL_BUILD、ZERO_CHECK在打开项目后要关闭)。
上面使用的CMake默认的配置,我们可以使用下面的命令:
1 | cmake -G |
列出所有的生成器Generators,其中带*号的是默认生成器
1 | Generators |
可以看到,其中有MinGW生成器,我们可以使用下面的命令,来生成MinGW的工程,同样,为了不污染源代码,这里先新建了一个文件夹bulid_mingw:
1 | $ cmake -G "MinGW Makefiles" .. |
可以看到,生成了一个Makefile文件,这样在Windows系统就可以使用minGW中的make命令来直接生成目标文件,也就是可执行程序helloworld.exe。而在Linux系统下可直接使用make命令生成可执行程序。
这里有点要注意的是,minGW的make程序名字叫做minGW32-make,因此直接在此文件夹下的命令行中输入minGW32-make就可以生成helloworld.exe。双击即可运行。
此外,不使用minGW32-make命令,还可以使用cmake命令生成可执行文件,命令是cmake --build .。
可以看到通过使用CMake生成目标文件,我们可以不用了解实际的构建系统的命令。各类不同的构建系统都可以使用统一的配置文件。这对跨平台开发程序非常方便















