用 xmake 搭建 STM32 HAL 工程与自定义 C 构建链

1245 字
6 分钟
用 xmake 搭建 STM32 HAL 工程与自定义 C 构建链

最近想把 STM32 的构建从 IDE 里挪出来,试了试 xmake。它的文档挺全的,就是没有现成的 STM32 模板或专页,得把”交叉编译""工具链""规则”这几块自己拼起来用。这篇记一下我实际折腾的过程,文档没说透的地方,我把当时的做法也写出来,供参考。

一、先看一个最小工程#

xmake create 出来的工程长这样(参考官方文档 create-project 页面):

hello
├── src
│ └── main.cpp
└── xmake.lua

最基础的 xmake.lua:

add_rules("mode.debug", "mode.release")
target("hello")
set_kind("binary")
add_files("src/*.cpp")

然后 xmake 构建、xmake run 运行。这个骨架对任何平台都一样,嵌入式无非是多配一个交叉工具链。

二、target 的常用配置#

对照官方 configure-targets 文档,平时用得最多的几个:

接口作用生成的参数
set_kind("binary"/"static"/"shared"/...)目标类型
add_files("src/*.c", "src/*.asm")添加源文件
add_files("src/*.cpp", {excludes = "test.cpp"})排除部分文件
add_defines("DEBUG")宏定义-DDEBUG
add_includedirs("/tmp")头文件目录-I/tmp
add_linkdirs("/tmp")链接库目录-L/tmp
add_links("foo")链接库-lfoo
add_cflags("...") / add_cxflags / add_cxxflags原始编译选项直接透传

一个混合 C/汇编的 target 示例:

target("demo")
set_kind("binary")
add_files("src/*.c", "src/*.asm", "src/*.cpp")
add_defines("DEBUG", "STM32F407xx")
add_includedirs("lib", "Drivers/CMSIS/Include")
add_links("myhal")
add_linkdirs("build")

三、创建工程的语言与模板#

xmake create 的语言参数是 -l,模板参数是 -t(文档原文如此,别记反了):

Terminal window
xmake create -l c hello # 指定语言
xmake create -t static test # 指定模板

文档列出模板有 console、static、shared、module.binary、module.shared、qt.、tbox.、wxwidgets 等,最常用的就是 console、static、shared 这三个。

模板列表里没有 stm32/arm 这类。-P 可以指定工程父目录,这条文档里没细讲,xmake create --help 里有。

四、STM32 HAL 工程怎么搭#

官方没有 STM32 专页,但交叉编译文档里写了内置的 gnu-rm 工具链,原话是”gnu-rm 就是内置的 GNU Arm Embedded Toolchain”:

Terminal window
$ xmake f -p cross --toolchain=gnu-rm --sdk=/xxx/cc-arm-none-eabi-9-2019-q4-major
$ xmake

结合前面的 target 配置,一个 HAL 工程的 xmake.lua 大概是这么拼的:

add_rules("mode.debug", "mode.release")
target("firmware")
set_kind("binary")
-- HAL 库源码与芯片外设代码(路径按你 CubeMX 生成的工程填)
add_files("Core/Src/*.c")
add_files("Drivers/STM32F4xx_HAL_Driver/Src/*.c")
-- 头文件搜索路径
add_includedirs("Core/Inc", "Drivers/STM32F4xx_HAL_Driver/Inc",
"Drivers/CMSIS/Include", "Drivers/CMSIS/Device/ST/STM32F4xx/Include")
-- 芯片型号与 HAL 开关宏
add_defines("STM32F407xx", "USE_HAL_DRIVER")
-- 启动文件(汇编)
add_files("startup_stm32f407xx.s")
-- 链接脚本与数学库
add_ldflags("-Tstm32f407xx_flash.ld", "--specs=nano.specs")

命令行切工具链:

Terminal window
xmake f -p cross --toolchain=gnu-rm --sdk=/opt/gcc-arm-none-eabi
xmake

几个文档没细讲的点#

下面这几个点文档里没有专门展开,是我按平时的嵌入式习惯补的,只当参考:

  • -T链接脚本--specs=nano.specs 怎么传<上面用> add_ldflags 是常见做法,官方文档没给 HAL 的完整示范,自己试出来的

  • HAL 库的目录结构<那是> STM32 生态(比如 CubeMX 生成)的约定,不是 xmake 的约定,按你实际工程填就行

  • 启动汇编、链接脚本本身<由芯片工具链侧定义>,不归 xmake 管

五、自定义其他 C 构建链#

命令行方式#

官方 cross-compilation 页面给了一串配置:

Terminal window
# 设置编译器
$ xmake f -p cross --sdk=/user/toolsdk --cc=armv7-linux-clang --cxx=armv7-linux-clang++
# 设置链接器/归档器
$ xmake f -p cross --sdk=/user/toolsdk --ld=armv7-linux-clang++ --sh=armv7-linux-clang++ --ar=armv7-linux-ar
# 设置前缀与 bin 目录
$ xmake f -p cross --cross=armv7-linux- --bin=/opt/bin

设了 --sdk 之后,xmake 会自动加 -I{sdk}/include-L{sdk}/lib,官方说不需要手动配,实测也是。

在 xmake.lua 里声明自定义工具链#

官方 custom-toolchain 页面,最简单的 standalone 工具链只要指定 SDK 目录:

toolchain("my_toolchain")
set_kind("standalone")
set_sdkdir("/tmp/arm-linux-musleabi-cross")
toolchain_end()
target("hello")
set_kind("binary")
add_files("apps/hello/*.c")

切换方式有两种。命令行:xmake f --toolchain=my_toolchain;或者直接在 target 里绑定——官方原话是”这对于嵌入式开发来讲尤其有用,因为嵌入式平台的交叉编译工具链非常多”:

target("hello")
set_toolchains("my_toolchain")

其他常用的工具链 API:set_toolset("cc", "clang")(可配 cc/cxx/ld/sh/ar/ex/strip/mm/mxx/as)、set_bindir("/tmp/sdkdir/bin")、在 on_load 里加编译参数 toolchain:add("cxflags", "-march=armv7-a", {force = true})、手动加系统库 toolchain:add("syslinks", "gcc", "c")

六、用自定义规则扩展构建流程#

构建完总得干点别的,比如 elf 转 hex/bin、bin2c、生成校验,这些都能用 rule() 挂进构建流程(custom-rule 页面):

rule("rulename")
-- 关联的文件扩展名
set_extensions(".ext1", ".ext2")
-- 构建阶段回调
on_build_file(function(target, sourcefile, opt)
...
end)
rule_end()

应用到 target 有两种方式:

add_rules("markdown") -- 全局应用
add_files("src/*.md", {rule = "markdown"}) -- 按文件应用(优先级更高)

可用的生命周期阶段:on_load / on_config / before_build / on_build / after_build / on_clean / on_package / on_install

在规则里调用外部命令的写法(官方示例,用 pandoc 举例):

on_build_file(function(target, sourcefile, opt)
os.vrunv("pandoc", {"-s", "-o", targetfile, sourcefile})
import("core.project.depend")
depend.on_changed(function() ... end, {files = sourcefile})
end)

内置规则也有现成的,比如 add_rules("mode.debug", "mode.release")add_rules("qt.widgetapp")

七、总结#

  • 没有 STM32 模板的情况下,「gnu-rm 工具链 + -p cross + target API」拼一拼就够搭 HAL 工程;链接脚本、--specs 这类细节要对着手上的芯片工具链确认
  • 自定义构建链两条路<命令行> --sdk/--cc/--ld/--cross 快速起步;或者用 toolchain() 固化进工程,多工具链切换也方便
  • 更复杂的构建流程用 rule() + 生命周期回调扩展
  • 遇到文档没写清楚的,先 xmake f --help 或翻一下项目的 issues,比自己瞎猜快

参考:

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

用 xmake 搭建 STM32 HAL 工程与自定义 C 构建链
https://blog.yungong.online/posts/xmake-stm32-build/
作者
云宫
发布于
2026-09-03
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
云宫
Hi, I'm 云宫
公告
欢迎来到 CODE云宫,一座磁带里的知识库。于过去寻找未来,于复古寻找现代。
分类
标签
站点统计
文章
3
分类
2
标签
12
总字数
3,688
运行时长
0
最后活动
0 天前