Windows 下 STM32 裸机编译环境搭建全攻略:从零到make成功的完整避坑指南
Windows 下 STM32 裸机编译环境搭建全攻略:从零到 make 成功的完整避坑指南
目标芯片:STM32(ARM)
工具链:arm-none-eabi-gcc
主机环境:Windows 10/11
一、引言:为什么你的 make 就是跑不起来
嵌入式圈子里有一个沉默的共识:Linux 下编译 STM32 项目几乎没有任何门槛,但一旦换到 Windows,各种莫名其妙的报错就会扑面而来。
你可能遇到过这些:
'arm-none-eabi-gcc' 不是内部或外部命令
process_begin: CreateProcess(NULL, pwd, ...) failed.
file.mk:21: pipe: No such file or directory
标记"&&"不是此版本中的有效语句分隔符。
这三行报错来自同一个项目,按顺序出现,每一条都卡在不同的地方。大多数教程会告诉你"安装 ARM 工具链、把路径加到 PATH 就行了",但实际操作中,光是工具链安装这一步就有至少 3 个隐藏坑等着你。
这篇文章的目标是:把搭建 Windows 裸机编译环境的完整路径,连同每一个坑的根本原因,一次性讲透。
二、核心概念:弄清楚你在装什么
在动手之前,先搞懂几个概念,后面碰到问题才不会懵。
2.1 交叉编译器是什么
你的 Windows 电脑是 x86_64 架构,STM32 是 ARM架构。两者指令集完全不同,你不可能直接用系统自带的 gcc 编译出能在芯片上跑的代码。
交叉编译器就是这个中间人:它运行在你的 x86_64 Windows 机器上,但输出的二进制是能在 ARM 上执行的机器码。
arm-none-eabi-gcc 这个名字本身就是一份完整的"出身证明":
| 字段 | 含义 |
|---|---|
arm |
编译目标是 ARM 架构 |
none |
目标平台没有操作系统(裸机或 FreeRTOS 等轻量 RTOS) |
eabi |
嵌入式应用二进制接口(Embedded ABI),STM32 的标准规范 |
gcc |
GNU C Compiler |
与之对应的 arm-none-linux-gnueabihf 则是目标跑 Linux 的 ARM 交叉编译器(比如 Raspberry Pi 那种)。两者绝对不能混用。
底层原理补充:为什么裸机要用
none而不是linux?因为带linux的工具链会链接 glibc,会预设存在内核系统调用层。裸机上没有内核,这些依赖全部是悬空的,链接时会报一堆undefined reference或者生成的代码直接跑飞。
2.2 为什么 Windows 下还需要 xPack Build Tools
Makefile 本质上是一个Shell 脚本调度器。它内部大量使用了 Linux 的 shell 命令:pwd、mkdir、rm、find、cp……
Windows 的 cmd.exe 和 PowerShell 完全不认识这些命令,或者行为不一致。
xPack Windows Build Tools 就是一个绿色的 GNU 工具包,它把这些 Linux 命令的 Windows 原生版本(make.exe、mkdir.exe、sh.exe、rm.exe 等)打了个包,让你的 Makefile 在 Windows 下也能正常运转。
整体工具链关系如下:
你的 Makefile
│
├── 调用 make(来自 xPack Build Tools)
│ │
│ ├── 调用 sh.exe 执行 $(shell ...) 内联命令(来自 xPack)
│ ├── 调用 arm-none-eabi-gcc 编译 .c 文件(来自 ARM Toolchain)
│ ├── 调用 arm-none-eabi-ld 链接(来自 ARM Toolchain)
│ └── 调用 arm-none-eabi-objcopy 生成 .bin/.hex(来自 ARM Toolchain)
两套工具缺一不可。
三、从零搭建到成功编译
正确的步骤是两步:装编译器 + 装构建工具,缺一不可。
3.1 第一步:安装 ARM GNU Toolchain
下载地址(官方):https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
在下载页面里,你会看到密密麻麻的文件列表。选这个,其他不用看:
Windows (mingw-w64-x86_64) hosted cross toolchains
└── AArch32 bare-metal target (arm-none-eabi)
└── arm-gnu-toolchain-15.2.rel1-mingw-w64-x86_64-arm-none-eabi.msi ← 下这个

| 维度 | 正确选项 | 错误选项 | 原因 |
|---|---|---|---|
| 主机架构 | mingw-w64-x86_64 |
mingw-w64-i686 |
你的 PC 是 64 位系统 |
| 目标架构 | arm-none-eabi |
arm-none-linux-gnueabihf |
STM32 是裸机,不是 Linux |
| 安装包格式 | .msi |
.zip |
MSI 自动安装更省心 |
安装关键细节:
⚠️ 避坑:新版 MSI 已经没有"添加到环境变量"的复选框了
老教程里说的"最后一步勾选 Add path to environment variable",在 15.x 版本的 MSI 包里已经消失。装完之后你需要手动配环境变量。不用慌,下面有详细步骤。
⚠️ 避坑:不要装在 Program Files
安装路径务必满足"无空格、无中文"。GNUmake对路径里的空格极其敏感,它会把空格两侧当成两个独立的参数,导致各种诡异的报错。推荐路径:C:\ArmToolchain或D:\DevTools\ArmGCC。
手动配置 PATH 环境变量(5 步操作):
Win + S搜索"环境变量",点击"编辑系统环境变量"- 点击右下角"环境变量(N)…"按钮
- 在"系统变量"中找到
Path,双击 - 点击"新建",填入 ARM 工具链
bin目录的完整路径(例如C:\ArmToolchain\bin) - 一路确定,关闭所有窗口
验证(必须开新终端):
arm-none-eabi-gcc --version
成功输出:
arm-none-eabi-gcc (Arm GNU Toolchain 15.2.Rel1 (Build arm-15.86)) 15.2.1 20251203
Copyright (C) 2025 Free Software Foundation, Inc.
...
⚠️ 避坑:必须开新终端窗口
环境变量的修改对已经打开的窗口不生效。必须完全关闭当前 CMD/PowerShell/VS Code,重新打开。这是 Windows 的机制,不是 bug。
3.2 第二步:安装 xPack Windows Build Tools
下载地址(官方 GitHub Release):https://github.com/xpack-dev-tools/windows-build-tools-xpack/releases
找到最新版,下载:xpack-windows-build-tools-4.4.1-3-win32-x64.zip

页面上还有
.sha文件(校验用)和Source code(源码包),只下载 zip,其他不用管。
安装步骤:
- 解压到干净路径(同样无空格无中文),例如:
C:\xpack-build-tools - 进入解压后的
bin目录(里面能看到make.exe、mkdir.exe、sh.exe) - 复制这个
bin目录的完整路径 - 重复第一步的"手动配置 PATH"操作,把这个路径也加进去
验证:
make --version
成功输出:
GNU Make 4.4.1
Built for x86_64-w64-mingw32
...
3.3 第三步:实际编译项目
两套工具都就位后,进入项目根目录编译:
# 切换到项目目录(/d 参数支持跨盘符)
cd /d D:\YourProject\ps_app_vcu_gcc
# 首次编译前创建 build 目录(只需要一次)
mkdir build
# 编译!关键:必须指定 SHELL=sh
make SHELL=sh -j
这里有一个关键参数:SHELL=sh。
不加这个参数,make 会默认用 cmd.exe 执行 Makefile 里的 $(shell ...) 命令,而 cmd.exe 不认识 pwd,整个路径解析会崩掉(就是 Version 1.0 看到的那堆报错)。
加上 SHELL=sh 后,make 会调用 xPack 提供的 sh.exe,这是一个完整的 Unix shell,pwd、find 等命令都能正常执行。
正常编译输出(最后几行):
arm-none-eabi-size xxx.elf
text data bss dec hex filename
206512 4832 125152 336496 52270 xxx.elf
arm-none-eabi-objcopy xxx.elf -Obinary xxx.bin
arm-none-eabi-objcopy xxx.elf -Oihex xxx.hex
cp xxx.bin xxx.hex ./fireware/
产物说明:
| 文件 | 用途 |
|---|---|
xxx.elf |
调试用,包含符号信息,可以用 GDB 调试 |
xxx.bin |
烧录用,纯二进制,ST-Link/J-Link 直刷 |
xxx.hex |
烧录用,Intel HEX 格式,STM32CubeProgrammer 等工具常用 |
3.4 核心逻辑拆解:两套工具如何协作
理解这张图,以后遇到任何新的 Makefile 项目都不慌:
Makefile 执行流程(Windows 下)
1. make SHELL=sh -j
│
└─ make 读取 Makefile
│
├─ $(shell pwd) → 调用 sh.exe → 返回当前目录路径(Unix 格式)
├─ find Module → 调用 sh.exe 内的 find → 扫描源文件列表
│
├─ 对每个 .c 文件:
│ arm-none-eabi-gcc [参数] -c src/foo.c -o build/foo.o
│
├─ 链接:
│ arm-none-eabi-gcc [参数] build/*.o -T xxx.ld -o VCU_APP.elf
│
└─ 格式转换:
arm-none-eabi-objcopy VCU_APP.elf -Obinary VCU_APP.bin
arm-none-eabi-objcopy VCU_APP.elf -Oihex VCU_APP.hex
四、避坑指南:经验逐条剖析
坑 1:安装路径带空格
现象:make 执行一半报找不到文件,或者路径被截断成两段。
根本原因:GNU Make 在解析路径时,遇到空格就会认为是参数分隔符。C:\Program Files\ArmToolchain\bin 中的空格会让 Make 误以为你传了两个参数 C:\Program 和 Files\ArmToolchain\bin。
正确姿势:路径无空格、无中文,例如 C:\ArmToolchain、D:\DevTools\ArmGCC。
坑 2:新版 ARM 工具链 MSI 不再自动添加 PATH
现象:安装完工具链,打开 CMD 输入 arm-none-eabi-gcc --version,报"不是内部或外部命令"。
根本原因:ARM 官方在 15.x 版本的 MSI 安装包中取消了末尾的 PATH 复选框,需要手动配置。
正确姿势:安装完成后,手动将工具链 bin 目录加入系统 PATH。具体步骤见第三节。
坑 3:make 不加 SHELL=sh 导致 pwd 失败
现象:直接执行 make 或 make -j,出现:
process_begin: CreateProcess(NULL, pwd, ...) failed.
Makefile:10: pipe: No error
find: /Module: No such file or directory
根本原因:make 在 Windows 下默认用 cmd.exe 执行 $(shell ...) 内的命令,而 cmd.exe 没有 pwd 命令。路径解析失败后,后续所有依赖该路径的规则全部连环崩溃。
正确姿势:
make SHELL=sh -j
如果每次都觉得麻烦,可以在 Makefile 开头加一行:
SHELL := sh这样直接
make -j就行,不用每次手动指定。但要注意,这是对 Makefile 的修改,如果是别人的项目要谨慎。
坑 4:PowerShell 里 && 语法报错
现象:在 PowerShell 里执行 make SHELL=sh clean && make SHELL=sh -j,报:
标记"&&"不是此版本中的有效语句分隔符。
根本原因:&& 是 bash/sh 的链式执行语法,老版本 PowerShell(5.x)不支持。PowerShell 7.x 虽然支持了 &&,但行为细节与 bash 有差异。
正确姿势:在 PowerShell 中分两行执行:
make SHELL=sh clean
make SHELL=sh -j
或者直接切换到 CMD(Win + R → 输入 cmd)再执行。
坑 5:make 输出 “is up to date”
现象:第二次执行 make SHELL=sh -j,输出:
make: 'VCU_APP.elf' is up to date.
然后什么都没发生。
这不是错误,这是 Make 的增量编译机制在正常工作。
Make 会比较源文件的修改时间和目标文件的修改时间,如果源文件没有更新,就不重新编译。这正是 Make 的核心价值——避免每次都从头编译。
如果你想强制全量重新编译,执行:
# PowerShell 分两行
make SHELL=sh clean
make SHELL=sh -j
# CMD 可以一行
make SHELL=sh clean && make SHELL=sh -j
坑 6:编译成功但出现大量 warning
现象:编译完成,但 ld.exe 输出了很多警告:
warning: _close is not implemented and will always fail
warning: _fstat is not implemented and will always fail
warning: _read is not implemented and will always fail
warning: VCU_APP.elf has a LOAD segment with RWX permissions
这些 warning 对裸机项目全部正常,不影响固件运行。
| Warning | 原因 | 是否影响运行 |
|---|---|---|
_close/_fstat/_read is not implemented |
链接了 nosys.specs,这些 POSIX 系统调用在裸机上没有实现,是预期行为 |
不影响,芯片上不会调用这些 |
LOAD segment with RWX permissions |
链接脚本没有严格分离可执行段,是编码风格问题 | 不影响功能,但安全意识高的项目会修复 |
五、复习:一张表带走核心知识点
| 知识点 | 关键结论 |
|---|---|
| 工具选择 | arm-none-eabi 用于 STM32 裸机;arm-none-linux-gnueabihf 用于跑 Linux 的 ARM 板,不可混用 |
| Windows 需要两套工具 | ① ARM GNU Toolchain(编译器)② xPack Build Tools(make/sh/mkdir) |
| PATH 配置原则 | 路径无空格、无中文;安装完必须重开终端才能生效 |
| 新版 MSI 行为变化 | 15.x 版本不再有"Add to PATH"复选框,需手动配 |
| Windows 下跑 Makefile | 必须加 SHELL=sh,否则 $(shell pwd) 等 Unix 命令会报错 |
| PowerShell vs CMD | PowerShell 5.x 不支持 &&,用两行代替;或切到 CMD |
| 增量编译 | “is up to date” 是正常行为,不是错误;强制全量编译用 make clean |
| 裸机链接 warning | _close/_read 等未实现的 warning 是正常的裸机现象,不影响烧录和运行 |
附录:完整编译命令速查
# === 首次配置(只需一次)===
# 验证编译器
arm-none-eabi-gcc --version
# 验证 make
make --version
# 创建 build 目录(项目根目录下)
mkdir build
# === 日常编译 ===
# 正常编译(增量)
make SHELL=sh -j
# 强制全量重新编译(PowerShell 用两行)
make SHELL=sh clean
make SHELL=sh -j
# 强制全量重新编译(CMD 可以一行)
make SHELL=sh clean && make SHELL=sh -j
# === 编译参数说明 ===
# SHELL=sh 告诉 make 用 xPack 的 sh.exe 执行 shell 命令(关键!)
# -j 多核并行编译,速度更快
官方工具下载地址(两个都要)
- ARM GNU Toolchain:
https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads- xPack Windows Build Tools:
https://github.com/xpack-dev-tools/windows-build-tools-xpack/releases
更多推荐
所有评论(0)