大目熊 · 9月6日 · 广东

STM32F103基于CMake+Ninja+CLang构建工程

脱离 IDE 开发 MCU:用 CMake + Ninja + Clang 构建 STM32 工程

传统 MCU 开发几乎离不开 CubeIDE、Keil 这类集成开发环境。但如果想完全掌控工程构建的每一个细节、定制自己的自动化工作流,就可以把 IDE 拿掉——用 CMake + Ninja + Clang 从零搭一套命令行构建流程。

因为整个构建过程都可以用纯命令完成,所以 Windows、Linux、macOS 能共用同一套流程;实际写代码时再配一个前端编辑器即可,最常用的是 VS Code。

完整的从零搭建过程请看B站链接:
【STM32F103基于CMake+Ninja+Clang构建工程】 https://www.bilibili.com/vide...

环境准备

在具体搭建工程之前,注意要安装好这些工具:

工具用途
STM32CubeMX本文工程基于 CubeMX 生成的 HAL 库开发,需要用它生成底层代码
CMake + Ninja构建系统
Arm 官方 Clang交叉编译器(注意:不是 ST 修改过的 Clang)
STM32CubeProgrammer烧录程序

三、先让 CubeMX 生成一个 CMake 工程

先新建一个工程文件夹,在里面建一个 cubemx 目录,用来保存 CubeMX 生成的文件。

打开 CubeMX 工程,可以看到已经配置了外部晶振、串口和时钟树。点击 Project Manager,选择生成 CMake 工程,然后点击 Generate Code

来看一下这个 CMake 工程,入口在 cubemx 目录下的 CMakeLists.txt

改造工程:重新组织目录与脚本

接下来基于 CubeMX 生成的 CMake 工程来改造。核心设计原则是:

CubeMX 生成的代码作为一个依赖库加入工程,不依赖外层代码。

所以一些应用层文件需要放到外层目录,CMake 脚本也会改成更现代化的写法(面向 target,而不是面向全局变量)。

这里创建一个 app 目录,先把 CubeMX 生成的一些应用层代码文件(如 main.c 等)拷贝过来。

目标目录结构

project/
├── CMakeLists.txt          # 根脚本:全局配置,不生成可执行文件
├── CMakePresets.json       # 指定工具链配置
├── cmake/
│   └── toolchain.cmake     # 工具链与标志位
├── app/
│   ├── CMakeLists.txt      # 生成最终的可执行程序
│   └── *.c / *.h           # 应用层代码
├── cubemx/
│   ├── CMakeLists.txt      # 生成静态库(底层驱动代码)
│   ├── STM32F103C8T6_FLASH.ld   # 链接脚本(从 cubemx 生成目录复制出来)
│   └── <CubeMX 生成的代码>/
└── .vscode/
    └── tasks.json          # 集成构建命令

根目录 CMakeLists.txt

基于 cubemx 目录的 CMakeLists 来改。

根脚本负责全局配置,不生成可执行文件,所以生成目标相关的部分都可以删掉,然后添加 appcubemx 子目录:

cmake_minimum_required(VERSION 3.22)

# 全局配置:语言标准、编译类型默认值等
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_EXTENSIONS ON)

add_subdirectory(app)
add_subdirectory(cubemx)

app 目录下的 CMakeLists.txt

app 目录负责生成最终的可执行程序。先删除一些没必要的配置,然后:

add_executable(app
    main.c
    # 其他应用层源文件
)

target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(app PRIVATE cubemx)

几个关键点:

  • 定义可执行程序名称为 app
  • 为这个目标添加这几个源文件
  • 把当前目录添加到头文件路径
  • 链接 cubemx——这个库由 cubemx 目录下的 CMakeLists 生成

cubemx 目录下的 CMakeLists.txt

cubemx 目录下也要有一个 CMakeLists.txt。

注意:这里为了避免和 CubeMX 自己生成的 CMakeLists.txt 冲突,可以把 CubeMX 生成的文件放到下一级目录,我们自己的 cubemx/CMakeLists.txt 则基于 CubeMX 生成的子脚本来修改。

改造要点:

  • 把代码文件路径改一下
  • 有几个 CubeMX 生成的源文件已经拷贝到 app 了,这里就不要重复添加
  • 改成生成一个静态库,包含 CubeMX 生成的底层驱动代码
  • 其他非必要的配置先删掉
add_library(cubemx STATIC
    <驱动源码 .c>
    <启动文件 .s>
)

# 头文件路径与宏定义通过接口库传递,任何链接 cubemx 的目标都会自动继承
target_include_directories(cubemx PUBLIC ${include_dirs})
target_compile_definitions(cubemx PUBLIC ${defines})

现在关于代码构建的 CMake 脚本就完成了。


五、改造工具链配置

然后来看下工具链配置,我们基于 CubeMX 的工具链配置来改。

5.1 去掉编译器前缀

这里配置工具链的前缀。Arm 官方 Clang 编译器没有前缀,所以改一下:

# ST / gcc 风格:arm-none-eabi-
# Arm 官方 clang:无前缀
set(TOOLCHAIN_PREFIX "")
set(CMAKE_C_COMPILER   clang)
set(CMAKE_ASM_COMPILER clang)

配置构建与集成到 VS Code

现在工具链配置也完成了,就可以在 CMakePresets.json 里指定工具链的路径,尝试编译一下:

{
  "version": 6,
  "configurePresets": [
    {
      "name": "default",
      "binaryDir": "${sourceDir}/build",
      "toolchainFile": "${sourceDir}/cmake/toolchain.cmake",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    }
  ]
}

为了方便,这里通过 VS Code tasks 集成构建命令。主要是设置:

  • 构建工具(CMake / Ninja)的路径
  • CMake 的相关构建任务

其中 "CMake Build"默认的构建任务,它依赖 "CMake Configure" 任务,所以执行默认构建任务时会先执行配置任务

于是直接通过快捷键 Ctrl + Shift + B 构建就行了。


总结与后续

基于 CMake + Ninja + Clang 的工程开发流程可以说是跑通了。

但目前烧写程序是通过 CubeProgrammer 实现的,无法像 Keil、IAR 这些传统 IDE 一样一键就能下载,比较麻烦。

后续可以集成 probe-rs,配合 VS Code 可以做到一键烧写和单步调试probe-rs 的搭建会放到另外的视频单独讲解。


推荐阅读
关注数
1
文章数
7
业余开发者
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息