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 命令:pwdmkdirrmfindcp……

Windows 的 cmd.exePowerShell 完全不认识这些命令,或者行为不一致。

xPack Windows Build Tools 就是一个绿色的 GNU 工具包,它把这些 Linux 命令的 Windows 原生版本(make.exemkdir.exesh.exerm.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
安装路径务必满足"无空格、无中文"。GNU make 对路径里的空格极其敏感,它会把空格两侧当成两个独立的参数,导致各种诡异的报错。推荐路径:C:\ArmToolchainD:\DevTools\ArmGCC

手动配置 PATH 环境变量(5 步操作)

  1. Win + S 搜索"环境变量",点击"编辑系统环境变量"
  2. 点击右下角"环境变量(N)…"按钮
  3. 在"系统变量"中找到 Path,双击
  4. 点击"新建",填入 ARM 工具链 bin 目录的完整路径(例如 C:\ArmToolchain\bin
  5. 一路确定,关闭所有窗口

验证(必须开新终端)

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,其他不用管。

安装步骤

  1. 解压到干净路径(同样无空格无中文),例如:C:\xpack-build-tools
  2. 进入解压后的 bin 目录(里面能看到 make.exemkdir.exesh.exe
  3. 复制这个 bin 目录的完整路径
  4. 重复第一步的"手动配置 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,pwdfind 等命令都能正常执行。

正常编译输出(最后几行)

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:\ProgramFiles\ArmToolchain\bin

正确姿势:路径无空格、无中文,例如 C:\ArmToolchainD:\DevTools\ArmGCC


坑 2:新版 ARM 工具链 MSI 不再自动添加 PATH

现象:安装完工具链,打开 CMD 输入 arm-none-eabi-gcc --version,报"不是内部或外部命令"。

根本原因:ARM 官方在 15.x 版本的 MSI 安装包中取消了末尾的 PATH 复选框,需要手动配置。

正确姿势:安装完成后,手动将工具链 bin 目录加入系统 PATH。具体步骤见第三节。


坑 3:make 不加 SHELL=sh 导致 pwd 失败

现象:直接执行 makemake -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
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐