# STM32 自动编译修复系统 - 项目需求与技术方案

## 1. 项目概述

### 1.1 背景
我们有一个用 **STM32CubeMX** 创建的嵌入式项目，希望通过 AI Agent 实现：
- 自动修改代码
- 使用开源编译器自动编译
- 根据编译报错自动修复，循环直到编译通过

### 1.2 核心目标
构建一个 **MCP（Model Context Protocol）Build Server**，实现以下闭环：
Agent 修改本地代码 → 调用 MCP 编译 → MCP 返回结构化报错 → Agent 根据报错修复 → 再编译 → 直到成功

text


### 1.3 核心原则
| 原则 | 说明 |
|------|------|
| **MCP 只编译，不改代码** | 源码以只读方式挂载进 Docker 容器 |
| **Agent 只改代码，不直接编译** | 所有编译动作都通过 MCP 工具调用 |
| **结构化错误返回** | MCP 解析 GCC 输出，返回 `file/line/col/message` 结构化数据 |
| **可重复构建环境** | 使用 Docker 容器保证编译环境一致性 |

---

## 2. 系统架构

### 2.1 架构图
┌─────────────────────────────────────────────────────────────────┐ │ 本地工作区 │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ STM32CubeMX 工程 │ │ │ │ ├── Core/Src/ (用户代码，可修改) │ │ │ │ ├── Core/Inc/ (用户头文件，可修改) │ │ │ │ ├── Drivers/ (HAL库，禁止修改) │ │ │ │ ├── Middlewares/ (中间件，禁止修改) │ │ │ │ ├── Makefile (CubeMX生成，谨慎修改) │ │ │ │ └── tools/build.sh (编译入口脚本) │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ │ 只读挂载 (-v workspace:/src:ro) ▼ ┌─────────────────────────────────────────────────────────────────┐ │ MCP Build Server │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ stm32_build_server.py (FastMCP) │ │ │ │ ├── build_firmware() 工具 │ │ │ │ │ ├── 调用 docker run │ │ │ │ │ ├── 收集编译输出 │ │ │ │ │ └── 返回结构化结果 │ │ │ │ └── gcc_parse.py (GCC报错解析器) │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ │ docker run --network=none ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Docker 编译容器 │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ stm32-toolchain:latest │ │ │ │ ├── arm-none-eabi-gcc (Arm GNU Toolchain) │ │ │ │ ├── make │ │ │ │ └── /src (只读) → 拷贝到 /work → 编译 → 输出到 /out │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘

text


### 2.2 组件职责

| 组件 | 职责 | 技术栈 |
|------|------|--------|
| **Agent** | 读取报错、分析原因、修改源码 | OpenAI Agents SDK / 其他 LLM Agent |
| **MCP Build Server** | 接收编译请求、调用 Docker、解析报错、返回结果 | Python + FastMCP (mcp[cli]) |
| **Docker 编译容器** | 提供隔离的、可重复的编译环境 | Ubuntu + arm-none-eabi-gcc + make |
| **build.sh** | 容器内编译入口，执行 make 并收集产物 | Bash |
| **gcc_parse.py** | 解析 GCC/LD 输出，提取结构化错误信息 | Python + 正则表达式 |

---

## 3. 目录结构

在 STM32CubeMX 工程根目录下创建以下结构：
your-cubemx-project/ │ ├── Core/ # CubeMX 生成（用户代码在 USER CODE 区块） ├── Drivers/ # CubeMX 生成（禁止修改） ├── Middlewares/ # CubeMX 生成（禁止修改，如果有） ├── Makefile # CubeMX 生成 ├── *.ioc # CubeMX 工程文件 │ ├── App/ # [新建] 用户自定义模块（推荐放这里，不会被覆盖） │ ├── Inc/ │ └── Src/ │ ├── tools/ │ └── build.sh # [新建] 容器内编译入口脚本 │ ├── mcp_build/ │ ├── init.py # [新建] 空文件 │ ├── stm32_build_server.py # [新建] MCP Server 主程序 │ └── gcc_parse.py # [新建] GCC 报错解析器 │ ├── docker/ │ └── Dockerfile # [新建] 编译环境镜像定义 │ ├── requirements.txt # [新建] Python 依赖 ├── pyproject.toml # [可选] uv/poetry 项目配置 └── README.md

text


---

## 4. 各模块详细需求

### 4.1 Docker 编译镜像

**文件**: `docker/Dockerfile`

**需求**:
- 基于 Ubuntu 24.04 (LTS)
- 安装 `gcc-arm-none-eabi` (Arm GNU Toolchain)
- 安装 `binutils-arm-none-eabi`
- 安装 `make`
- 安装基础工具: `bash`, `coreutils`, `findutils`, `sed`, `grep`, `gawk`, `file`
- 创建工作目录: `/work`, `/out`
- 不需要网络访问（运行时用 `--network=none`）

**镜像名称**: `stm32-toolchain:latest`

**构建命令**:
```bash
docker build -f docker/Dockerfile -t stm32-toolchain:latest .
4.2 编译入口脚本
文件: tools/build.sh

需求:

接收环境变量配置（不是命令行参数，更安全）
把只读的 /src 拷贝到可写的 /work/project
在 /work/project 下执行 make
所有输出写入 /out/build.log
收集编译产物 (.elf, .hex, .bin) 到 /out/artifacts/
支持 make clean
支持指定并行任务数 (-j)
支持指定 Makefile 子目录（如果 Makefile 不在根目录）
环境变量:

变量名	默认值	说明
SRC_DIR	/src	源码只读挂载点
WORK_DIR	/work	容器内可写工作目录
OUT_DIR	/out	输出目录（日志、产物）
PROJECT_SUBDIR	""	Makefile 所在子目录（相对于工程根）
MAKE_TARGET	all	make 目标
JOBS	""	并行数，空则不指定
CLEAN	0	是否先 make clean（1 或 0）
输出:

/out/build.log - 完整编译日志
/out/artifacts/*.elf - 编译产物（如果成功）
/out/artifacts/*.hex
/out/artifacts/*.bin
4.3 GCC 报错解析器
文件: mcp_build/gcc_parse.py

需求:

解析 GCC 编译期错误格式: file:line:col: error/warning: message
解析 GCC 工具链错误: arm-none-eabi-gcc: error: message
解析链接期错误关键词:
undefined reference to
multiple definition of
ld returned
collect2: error:
路径归一化：去掉容器内前缀 /work/project/，返回相对路径
按严重程度排序：error > warning > note
输入: 编译日志文本 (str)

输出: 错误列表 list[dict]

Python

[
    {
        "type": "compiler" | "linker" | "toolchain" | "system",
        "severity": "error" | "warning" | "note",
        "file": "Core/Src/main.c" | None,  # 相对路径
        "line": 123 | None,
        "col": 9 | None,
        "message": "unknown type name 'Foo_t'",
        "raw": "原始行文本"
    },
    ...
]
函数签名:

Python

def parse_gcc_output(
    text: str,
    work_prefixes: tuple[str, ...] = ("/work/project/", "/work/"),
) -> list[dict[str, Any]]:
4.4 MCP Build Server
文件: mcp_build/stm32_build_server.py

需求:

使用官方 MCP Python SDK 的 FastMCP
暴露一个工具: build_firmware
支持 STDIO 传输模式（Agent 作为子进程拉起）
支持通过环境变量配置默认镜像和允许的 workspace 根目录
环境变量:

变量名	默认值	说明
STM32_BUILD_IMAGE	stm32-toolchain:latest	Docker 镜像名
STM32_ALLOWED_ROOT	""	允许的 workspace 根目录（空=不限制）
工具定义: build_firmware

输入参数:

参数	类型	默认值	说明
workspace	str	(必填)	工程根目录绝对路径
project_subdir	str	""	Makefile 子目录
clean	bool	True	是否先 make clean
jobs	int	8	并行任务数
make_target	str	"all"	make 目标
timeout_sec	int	600	超时秒数
max_log_tail_kb	int	96	返回的日志尾部最大 KB
image	str	""	覆盖默认镜像名
输出结构:

Python

{
    "ok": bool,                    # 编译是否成功 (exit_code == 0)
    "exit_code": int,              # make 返回码
    "image": str,                  # 使用的镜像名
    "outdir": str,                 # 临时输出目录路径
    "artifacts": list[str],        # 产物文件路径列表
    "errors": list[dict],          # 结构化错误列表（见 4.3）
    "log_tail": str,               # 编译日志尾部
    "docker_tail": str             # docker run 输出尾部
}
Docker 运行约束:

--rm: 容器退出后自动删除
--network=none: 禁用网络
-v workspace:/src:ro: 源码只读挂载
-v outdir:/out:rw: 输出目录可写
--user UID:GID: Linux 下使用当前用户，避免权限问题
安全校验:

workspace 必须存在且是目录
如果设置了 STM32_ALLOWED_ROOT，workspace 必须在其下
运行入口:

Python

if __name__ == "__main__":
    mcp.run()  # STDIO 模式
4.5 依赖配置
文件: requirements.txt

text

mcp[cli]>=1.26.0,<2
安装:

Bash

pip install -r requirements.txt
5. CubeMX 工程约束（Agent 必须遵守）
5.1 可修改区域
区域	可否修改	说明
/* USER CODE BEGIN xxx */ 区块内	✅ 可以	CubeMX 再生成时会保留
App/ 目录（自建）	✅ 可以	CubeMX 完全不会碰
Core/Src/*.c USER CODE 区块外	⚠️ 谨慎	会被再生成覆盖
Drivers/	❌ 禁止	HAL 库，由 CubeMX 管理
Middlewares/	❌ 禁止	中间件，由 CubeMX 管理
Makefile	⚠️ 谨慎	可改但再生成会覆盖，建议只改编译选项
.ioc 文件	❌ 禁止	CubeMX 工程文件，不要手动编辑
5.2 修复策略优先级
Agent 修复代码时应遵循以下优先级：

优先: 在 App/ 目录下新增/修改文件（永不被覆盖）
其次: 在已有的 USER CODE BEGIN/END 区块内修改
最后: 修改 CubeMX 生成的代码（需要有再生成后重新应用的策略）
5.3 修复循环约束
每轮最多修复 1~3 个最上游的 error
先修 编译错误，再修 链接错误
禁止修改 Drivers/、Middlewares/、startup_*.s、*.ld 除非错误明确指向
最大迭代次数: 20 次
超过迭代上限应停止并输出当前最相关的错误
6. 使用方式
6.1 构建 Docker 镜像
Bash

cd your-cubemx-project
docker build -f docker/Dockerfile -t stm32-toolchain:latest .
6.2 验证镜像
Bash

docker run --rm stm32-toolchain:latest arm-none-eabi-gcc --version
6.3 启动 MCP Server（STDIO 模式）
Bash

cd your-cubemx-project
python -m mcp_build.stm32_build_server
6.4 开发调试（使用 MCP Inspector）
Bash

# 安装 uv（如果没有）
pip install uv

# 启动 Inspector
uv run mcp dev mcp_build/stm32_build_server.py
6.5 Agent 连接示例（OpenAI Agents SDK）
Python

from agents import Agent
from agents.mcp import MCPServerStdio

async def main():
    async with MCPServerStdio(
        command="python",
        args=["-m", "mcp_build.stm32_build_server"],
        cwd="/path/to/your-cubemx-project",
    ) as mcp_server:
        agent = Agent(
            name="STM32 Build Agent",
            instructions="...",
            mcp_servers=[mcp_server],
        )
        # ... agent 循环修复逻辑
7. 验收标准
7.1 Docker 镜像验收
 docker build 成功，镜像大小 < 1GB
 arm-none-eabi-gcc --version 输出正确版本
 make --version 输出正确版本
7.2 build.sh 验收
 在只读 /src 下不会报错（拷贝到 /work 再编译）
 CLEAN=1 时执行 make clean
 编译日志写入 /out/build.log
 编译产物收集到 /out/artifacts/
 编译失败时返回非零退出码
7.3 GCC 解析器验收
 正确解析 file:line:col: error: msg 格式
 正确解析 undefined reference to 'xxx'
 正确解析 multiple definition of 'xxx'
 路径去掉 /work/project/ 前缀
 errors 按 severity 排序
7.4 MCP Server 验收
 build_firmware 工具可被 MCP Inspector 调用
 编译成功时 ok=True, exit_code=0
 编译失败时 ok=False, errors[] 非空
 workspace 不存在时返回错误
 超时时返回 timeout 错误
 源码确实以只读挂载（容器内无法修改 /src）
7.5 端到端验收
 故意在代码中引入一个语法错误
 调用 build_firmware
 返回的 errors[] 包含正确的 file/line/message
 Agent 可根据 errors 定位并修复
 修复后再次调用 build_firmware，ok=True
8. 后续扩展（可选）
功能	说明
ccache 加速	在 Docker 中添加 ccache，挂载持久缓存目录
Filesystem MCP	把"改文件"也纳入 MCP 工具，实现更细粒度的权限控制
源码片段返回	报错时返回相关文件的上下文代码（周边 N 行）
增量编译	clean=False 时跳过 make clean，加速迭代
多目标支持	支持 Debug/Release 等多配置
CMake 支持	支持 CMake 工程（CubeMX 也可生成 CMakeLists.txt）
9. 参考资料
MCP 官方规范
MCP Python SDK
Arm GNU Toolchain
STM32CubeMX 用户手册
10. 文件清单（Agent 需要创建）
text

[ ] docker/Dockerfile
[ ] tools/build.sh (需要 chmod +x)
[ ] mcp_build/__init__.py
[ ] mcp_build/gcc_parse.py
[ ] mcp_build/stm32_build_server.py
[ ] requirements.txt
text


---

这份文档涵盖了：
1. **项目背景与目标** - 让 Agent 理解要做什么
2. **系统架构** - 各组件如何协作
3. **目录结构** - 文件放哪里
4. **各模块详细需求** - 每个文件的完整规格
5. **CubeMX 约束** - 哪些能改哪些不能改
6. **使用方式** - 如何运行和测试
7. **验收标准** - 怎样算做完了
8. **文件清单** - 需要创建哪些文件
