从何下手
首先有这样的教程,非常的“从入门到入门”。👌
如果想要完整地了解一下 CMAKE 的机制和语法,可以跟着这个教程走完全程。但是教程有如下的问题
Note
- 仅仅是学习和了解,无法用于生产环境。教程是基于学习环境,使用的 C++,以及默认的 C 编译器(在我的环境中是 clang ),编译出的也是仅可在桌面运行的 exe 。我们当然是使用 arm_gcc 进行编译,或者至少要会指定其他的 gcc 工具,才可以将工程用于生产。
- 项目结构过分复杂,不利于初学理解。本来就不能用于生产了,整个软件又太复杂,cmakelist 文件过多,对初学者不友好。
所以教程可以先只看 Step1~3 就好了。
其中涉及到的软件工具,需要自行下载并且把可执行文件路径添加到环境变量
- Cmake
- MinGW64
- arm-none-eabi-gcc
或者使用我的文件站中打包好的 便携 vscode 环境
然后用stm32cubemx随便生成一个 debuglink 的项目,生成项目的工具链选择 CMAKE。然后分析一下他生成的这个项目。
下载软件工具
Cmake 和 MinGW64 建议使用 MSYS2 的 MINGW64 分支环境安装,手动安装会有依赖问题导致难以进行,或者依赖分散不利于模块化。
安装 MSYS2 后打开其中的 mingw64.exe ,打如下两条指令
安装完成后将 MSYS2 的 mingw64/bin 文件夹路径添加进系统环境变量的 path
arm-none-eabi-gcc 需要在官网下载,MSYS2 中下载的不完全,会缺失 GDB 工具。
在 Arm GNU Toolchain Downloads – Arm Developer 官网下载或者是我的文件镜像 arm-gcc。
解压 or 安装后,确认将其中的 bin 文件夹路径添加进系统环境变量的 path。
一个最简单的工程
在 stm32cubemx 中随便生成一个简单的 cmake 工程,大致结构如下。与 cmake 有关的如图。

根文件夹

./cmake

./cmake/stm32cubemx
可执行主构建
生成的主构建文件是根目录下的 CMakeLists.txt这也是我们使用cmake ../类似的指令生成原生构建系统所调用的CMakeLists.txt
值得注意的是,这个 CMakeLists.txt 没有直接地引入任何源码,而是仅定义了一些配置。这在后续修改可执行主构建的 CMakeLists.txt 时应当保持。
他有
这两个部分会使用间接方式引入所有的源码文件,在cmake/stm32cubemx中另有一个CMakeLists.txt,其中定义了名为stm32cubemx的工程并且引入了所有的包含路径和源码文件,使用targetlinklibraries的方式进行间接引入,后续会详细介绍该文件。
工具链指定
可执行主构建中有这样一句话
这句话将./cmake文件夹下的gcc-arm-none-eabi.cmake文件引入了,这里的 include 和 C 语言一样,只是进行文本替换,也就是将 gcc-arm-none-eabi.cmake 文件的所有内容都替换到了这一行,从而达到指定工具链的目的。这个文件内容如下。
可以看到,就是制定了编译工具链,并且将一些编译器参数在这里一一指定,例如在汇编器中加入传参“ -masm=auto”,就可以在
这一句后加入
其中的${CMAKE_ASM_FLAGS}意味着将此前设定的CMAKE_ASM_FLAGS通通填在前面,实现额外添加的效果。
工程源码引入
前两个相关文件中,我们指定了 cmake 生成配置,工具链参数配置,现在要引入事实上的源码文件。
可执行主构建中有这样一句话
将./cmake/stm32cubemx全部引入,其中事实上有效的只有CMakeLists.txt,其他文件都没有实际生效,不用理会。这个文件内容如下。
那么好,这里就是引入工程实际源码文件和包含目录的地方了,以stm32cubemx为 cmake 项目名。还记得主构建中有以下的部分吗?
stm32cubemx这个 cmake 项目中实现与源码相关的引入。
vscode 配置 cmake
1.配置文件
在以下站点下载 cmake 配置文件,并在 vscode 中导入
2.修改用户配置
导入配置文件后会下载诸多所需的插件,要修改用户设置,将各个工具链的路径添加到合适的设置项。
启用上一步导入的配置文件,在设置中 (用户分栏) 搜索 arm toolchain path 有类似如下的项。
Cortex-debug: Arm Toolchain Path
Path to the GCC Arm Toolchain (standard prefix is "arm-none-eabi" - can be set through the armToolchainPrefix setting) to use. If not set the tools must be on the system path. Do not include the executable file name in this path.
点击此项下方的 在 settings.json 中编辑 ,编辑这个条目类似如下,将其中的路径改为自己 arm-none-eabi-gcc 的 bin 路径。
在设置中 (用户分栏) 搜索 JLink GDBServer Path 有类似如下的项。
Cortex-debug: JLink GDBServer Path
Path to the JLink GDB Server. If not set then JLinkGDBServer (JLinkGDBServerCL.exe on Windows) must be on the system path.
点击此项下方的 在 settings.json 中编辑 ,编辑这个条目类似如下,将其中的路径改为自己 JLinkGDBServerCL.exe 的 bin 路径。由于我给出的例子通常都是编写的 JLink 调试任务,并且利用 JLink 的 RTT 打印功能,所以使用 JLinkGDBServer ,如果使用 OpenGDBServer ,自行修改对应的 GDBServerPath,只是恐怕编写调试任务有些困难。
3.编写 vscode 任务
需要进行 CMAKE 脚本以及程序的调试,需要自行编写 debug 任务,在 .workspace 文件的 "launch" 部分编写如下,如果没有 "launch" 部分可以写在最下方。
其中 "executable" 部分填写为实际的编译产出,"device" 填写为真正的芯片型号,"svdFile" 部分填写真正的 svd 文件所在(如果没有,删除这个条目)。
共创建了两个任务,分别调试 CMAKE 生成脚本,以及程序,在 vscode 调试窗选择对应的任务开始即可。
总结
stm32cubemx 生成的 cmake 项目,个人觉得非常合理非常易懂,分为三个部分清晰明了。
- 可执行主构建:定义 cmake 项目的各种通用配置,比如 C 标准、是否使用 C 艹等等编译器、源码无关的事情,并引入另外两个部分。
- 编译工具链的指定:定义使用什么编译器,依据目标平台不同而不同
- 源码的引入:这一层就类似使用其他 IDE 了,仅需要将 源码、包含目录、全局 define 一一定义
之所以想要换成 cmake,是因为工程越来越庞大,而且想要将各个软件功能都模块化抽离管理,IDE 在分软件包这方面还是差一些,cmake 每个功能模块独立自己的 CmakeList 就好,除了硬件驱动都可以抽象化使其平台无关。
拓展
我的 modbus 协议栈展示了一种功能模块的先进用法。
功能库的 CmakeList.txt 如下
而主构建中使用这样的方法调用
首先是子构建是 INTERFACE 库,因为是一个功能库,不可能独立运行,而是需要实际的应用软件调用这个功能库。
示例主构建就是展示如何使用功能库,这里分别使用 INTERFACE 以及 PRIVATE 属性进行 define 和 include path 了两次。 其中 INTERFACE 标签在这里代表在子构建中生效,而在这个主构建中不生效。 而 PRIVATE 标签在这里代表只在主构建中生效,而在子构建中不生效。
所以事实上是在两个 CmakeList.txt 中都生效了,可以使用 PUBLIC 这个标签属性来代表两个中都生效,示例进行了精细的控制。