Files
STM32F4-Base/docs/环境与部署/本地工具路径环境变量方案.md
T
wandering1 4a4ad6bc5f chore(全仓): @build/@test 旧文档别名清退为技能调用名
现状口径:/keil-build 与 /serial-boot-test 是 DSH 会话的技能调用名,
不是 shell 命令;「名 + 命令行参数」的命令形态改为可执行体
run_boot_test.py 的真实调用。

- AGENTS.md:别名说明重写为「技能调用名不是 shell 命令」,两条目改
  「编译(/keil-build)」「串口回归(/serial-boot-test)」
- keil-build / serial-boot-test 两 skill 调用名与示例同步;task-worktree
  方案文档去掉 @build/@test 惯例从句;@task 保留(不在点名范围)
- 123 文件现状陈述全改;台架捕获、变更记录/时间线、rename 映射输入
  等 41 行历史证据保留旧名
- gen_memory_svg.py 6 处措辞随改,3 张 SVG 产物同批重跑
- 顺手补并行方案同行漏网计数 51→52 钩子

验证:提交期快钩子对 123 文件实跑全 Passed;check_doc_links --all
rc=0(3038 处、无法判定 0);check_mermaid --all rc=0;YAML 解析 52
钩子不变;skill-size rc=0;py_compile 全过;字节卫生零漂移。
2026-10-30 13:03:12 +08:00

192 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 本地工具路径环境变量方案
> 本文档描述项目的本机工具路径环境变量机制:变量清单、解析与失败语义、各级配置方法、验收判据
> (2026-10-02 实施并生效;实施过程与后续变更见文末变更记录)。
> **约束(现行)**:只用进程/用户/CI 服务环境变量配置本机差异;不提交本机路径,不引入 `.env`/`python-dotenv`,
> 不把个人工具路径写入共享 workflow;仓库内部路径继续相对脚本/仓库根解析。
## 1. 变量清单
| 变量 | 必需性 | 值的形态 | 使用者 | 默认/回退 |
|---|---|---|---|---|
| `DTU_KEIL_UV4` | MCU 构建机必需 | UV4.exe 完整路径,例如 `D:\Tools\Keil\UV4\UV4.exe` | `keil_build.py`(`/keil-build`) | 不设即报错(exit 2);不从 C 盘旧路径猜测 |
| `DTU_STLINK_CLI` | 复位/烧录/回读机必需 | `ST-LINK_CLI.exe` 完整路径,例如 `C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe` | `stlink_flash.py` | 未设时回退 PATH(`where ST-LINK_CLI.exe` 首个命中);已设但无效 = 硬报错 |
| `DTU_PRECOMMIT_PYTHON` | 可选(覆盖用) | 含 `pre_commit` 模块的 `python.exe` 完整路径 | `ci_local.py` 静态门禁、CI `static-gates` | 未设时按 §1.1 探测(当前解释器 → `.venv` → PATH);已设但无效 = 硬报错 |
| `DTU_GRAPHVIZ_DOT` | 可选(覆盖用) | `dot.exe` 完整路径 | `gen_refgraph.py` | 未设时只查 PATH;无 Graphviz 时降级为"生成 .dot/.json、跳过渲染" |
| `DTU_MSVC_CL` | 可选(覆盖用) | x64 `cl.exe` 完整路径(`bin\Hostx64\x64` 下) | `unit_test_harness.py` 主机侧纯逻辑单测、CI `host-unit-tests` | 未设时按 VS 安装根自动探测(2019/2022/2026 各 edition);已设但不符 `bin\Hostx64\x64\cl.exe` = 硬报错 |
| `DTU_WINDOWS_KITS_ROOT` | 可选(覆盖用) | `Windows Kits\10` 根目录(须含 `Include`/`Lib`) | `unit_test_harness.py` 主机侧纯逻辑单测、CI `host-unit-tests` | 未设时从 `%ProgramFiles*%` 推导根自动探测;已设但无 `Include`/`Lib` = 硬报错 |
| `DTU_VSWHERE` | 可选(覆盖用) | `vswhere.exe` 完整路径 | `build_sim.ps1` | 未设时用 `%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe` 推导;已设但无效 = 硬报错 |
| `DTU_CPPCHECK` | 可选(覆盖用) | `cppcheck.exe` 完整路径 | CI `static-gates` cppcheck 步骤 | 未设时用 PATH(`Get-Command`);已设但无效 = 硬报错。本地 `ci_local.py` 静态门禁不读该变量:cppcheck 钩子按 pre-commit `entry: cppcheck` 从 PATH 解析 |
> 变量值只存路径本身(不加引号);可执行文件变量存 `.exe` 完整路径,目录变量(Kits 根)存目录。
> 不设任何变量时全部走自动发现(PATH / 系统目录推导 / `.venv` / `vswhere`);变量只用于覆盖非标准安装位置。
> 字体系统目录(`simsun.ttc`)不设 DTU 变量:由 `%WINDIR%\Fonts\` 推导,`make_font.py` 的 `--font` 参数仍最高优先。
### 1.1 Python 优先级特别说明(`ci_local.py` / CI 静态门禁)
`pre-commit` 是门禁的**执行环境**而非"工具地址",优先级与其余工具不同:
1. 显式 `DTU_PRECOMMIT_PYTHON`(若设置,必须可执行且能 `import pre_commit`,否则报错);
2. 当前解释器(`sys.executable`,即实际运行 `ci_local.py` 的 Python);
3. 仓库 `.venv\Scripts\python.exe`(若存在且装了 pre-commit);
4. PATH 中的 `python`。
CI 侧同理:`DTU_PRECOMMIT_PYTHON` → runner PATH → workspace `.venv`。
## 2. 解析与失败语义(所有调用端统一)
1. **显式值校验**:变量已设置时,先校验其指向的文件/目录真实存在且符合形态(如 `cl.exe` 必须位于 `bin\Hostx64\x64\` 下);无效则**立即报错**,错误信息必须包含变量名与所给值,**不得静默回退**到自动发现。
2. **未设置才自动发现**:PATH / 系统目录推导 / `.venv` / `vswhere` 等;自动发现失败按各工具既有降级或报错语义处理。
3. **BAT 实现约束**:`.bat` 中读取环境变量用 `%DTU_...%`;判空用 `if defined`;错误分支 `exit /b` 非零。BAT 内解析一律平铺 `goto` 标签风格,不用括号块(`echo )` 会提前闭合块)。
4. **PowerShell 实现约束**:`$env:DTU_...`;`build_sim.ps1` 的 CMake 配置不直接读环境变量(保持生成器无关)。
5. **workflow run 块**:`ci.yml` 的 run 块内用 `${env:DTU_...}`(未设置时为空串)与 PowerShell `$env:DTU_...` 判空,**不得**在 workflow 文件里写死任何本机绝对路径。
6. **Windows 命令行引号规则**:值含空格(如 `C:\Program Files (x86)\...`)时,调用端必须整体加引号(`"%DTU_KEIL_UV4%"` / `"& $env:DTU_..."`);变量值本身**不要**带引号。
7. **系统变量推导**:`%WINDIR%`、`%ProgramFiles%`、`%ProgramFiles(x86)%` 仅用于推导(如 `make_font.py` 的 `simsun.ttc`、`build_sim.ps1` 的 vswhere 路径),不得作为"工具安装目录"的硬编码兜底。
## 3. 本机配置方法
### 3.1 当前 PowerShell 会话(立即生效,适合试配置)
```powershell
# 仅当前会话有效;换终端/重启即失效
$env:DTU_KEIL_UV4 = 'D:\Tools\Keil\UV4\UV4.exe'
$env:DTU_STLINK_CLI = 'D:\Tools\ST-LINK Utility\ST-LINK_CLI.exe'
# 验证:Test-Path $env:DTU_KEIL_UV4 → True
```
### 3.2 用户级持久配置(日常开发机,推荐)
```powershell
# 当前用户、全部新进程可见;无需管理员
[Environment]::SetEnvironmentVariable('DTU_KEIL_UV4', 'D:\Tools\Keil\UV4\UV4.exe', 'User')
[Environment]::SetEnvironmentVariable('DTU_STLINK_CLI', 'D:\Tools\ST-LINK Utility\ST-LINK_CLI.exe', 'User')
# 已存在同名值时直接覆盖;删除用 [Environment]::SetEnvironmentVariable('DTU_KEIL_UV4', $null, 'User')
# 设置后需重开终端/IDE 才对新进程生效
```
### 3.3 Gitea Windows runner(SYSTEM 服务)
```powershell
# 必须管理员;写入机器级(Machine)环境,供 Gitea runner 服务(SYSTEM 账户)读取
[Environment]::SetEnvironmentVariable('DTU_PRECOMMIT_PYTHON', 'C:\ProgramData\anaconda3\python.exe', 'Machine')
[Environment]::SetEnvironmentVariable('DTU_CPPCHECK', 'C:\Program Files\Cppcheck\cppcheck.exe', 'Machine')
# 写入后需重启 Gitea runner 服务/任务才能带上新变量(服务启动时读取环境变量快照)
```
> 注意:runner 以 SYSTEM 运行,**用户级变量对 runner 不可见**;反之机器级变量对交互用户可见但不应依赖。开发机日常配置用 User 级,runner 专用覆盖用 Machine 级。
> 值示例中的 `C:\ProgramData\anaconda3\...` 仅演示"显式覆盖"形态;若 runner 的 PATH/`.venv` 可自动发现,则不必设置该变量。
## 4. 验收判据
- 新电脑只配置本机 `DTU_*` 环境变量(§3),clone 仓库后可直接运行各开发命令,**不修改任何脚本/工作流中的本机路径**。
- 显式变量指向无效路径时,命令以非零退出码失败且错误信息指明变量名,不静默使用其他工具。
- 仓库内不出现提交的本机绝对工具路径(文档中的示例路径除外)。
- 跨机验证操作清单见 `项目部署环境要求.md` §2.12;runner 侧机器级变量设置见 `docs/CI/远程CI完整指南.md` §4.1.3。
---
## 5. 三个解释器各能跑什么(2026-10-27 实测,道G task-33)
> 起因:有队友在 `.venv` 里 `import identify.tags` 失败,又用 `pip` 查不到 `pre-commit`,据此判定
> 「`.venv` 里的 pre-commit 安装是残缺的」。**复测结论:环境不残缺,两条观测都成立但推错了因**——
> 前者是版本本身没有那个模块(下表第三行),后者是查错了对象(下表第二行)。
> 取证方法固定:同一个探针脚本(`sys.executable` + 逐个 `import` + `importlib.metadata.version`)
> 分别喂给三个解释器;脚本放仓外临时目录,不入库、不改任何环境。
| 解释器 | 身份 | 门禁相关模块 | 第三方包 | 结论 |
|---|---|---|---|---|
| `.venv\Scripts\python.exe` | 3.12.4(**基底是 Anaconda**,非干净 CPython) | `identify` 可导入、`pre_commit` 可导入;`identify.tags` **无此模块** | fontTools 4.51.0 / pillow 10.3.0 / pyserial 3.5 / pyyaml 6.0.3 / cfgv 3.5.0 全在,`pre-commit` 与 `identify` 的 dist-info 齐全(`pip show` 可查) | **就是钩子的执行环境**:`.git/hooks/pre-commit` 里 `INSTALL_PYTHON` 写死指向它 |
| `C:\Python314\python.exe` | 3.14.7,PATH 首位 | 三个全缺 | **一个都没装**(`pip` 元数据全 `PackageNotFoundError`) | 「查不到 pre-commit」的现场就是它;`language: system` 的 42 条 entry 的裸 `python` 落在这里 |
| `C:\Users\...\Python311\python.exe` | 3.11.9,PATH 次位 | 同上全缺 | 同上全缺 | 与门禁无关,列出来只为排除「装了但找不到」的猜测 |
**为什么"缺 `identify.tags`"不是故障**:`identify-2.6.19.dist-info/RECORD` 一共 24 行,列出的模块只有
`__init__.py` / `cli.py` / `extensions.py` / `identify.py` / `interpreters.py` / `vendor/licenses.py`——
**根本没有 `identify/tags.py` 这一条**,而磁盘上的文件与 RECORD 逐项一致。即"元数据完好、文件齐全、
只是这个版本没有那个模块"。标签常量在这个版本里位于 `identify/identify.py`(`TEXT` / `BINARY` /
`EXECUTABLE` / `ALL_TAGS`),pre-commit 4.6.2 自己也是从那里取的(`clientlib.py` 里
`from identify.identify import ALL_TAGS`),**全仓没有任何脚本 import `identify.tags`**(实测 grep 零命中)。
⇒ 需要复算文件类型标签时,正确入口是 `identify.identify`;旧写法 `identify.tags` 在这个版本对上必然失败。
### 5.1 新增钩子 entry 的硬规则(今天没炸的真正原因)
`language: system` 的 entry 不继承 `.venv`:pre-commit 不改 `PATH`,所以裸 `python` 命中 PATH 首位
(本机 = 3.14.7,**零第三方包**)。实测本仓 45 条 system 钩子里 **43 条 entry 以裸 `python` 开头**,
今天能全绿的原因是(**2026-10-27 二次修正,改以机械口径为准**):
1. 这些条目**没有任何一条在模块级 import 第三方包**(抽测 bom-drift / layer-deps / doc-links 与一套
带 harness 的主机单测,在 3.14.7 下 exit 0);
2. 真正会碰第三方的是**下游脚本里的惰性导入**——典型是字体链 `tools/font_gen/make_font.py` 在函数体内
`from fontTools.ttLib import TTCollection`。它会不会被走到静态判不了,所以
`scripts/ci_local.py` 的钩子解释器预检把这类只列成**候选**(实测列出 `font-charset` / `generated-fresh`
两条经下游引入 fontTools),摊开给人看、不作判决;判决只留给「模块级 import + 裸 python +
该解释器确实没装 + 脚本不自带解释器解析」四事齐备那种必然崩。
> ⚠ 本节 2026-10-27 的早先版本写作「42 条里唯一需要第三方包的那条自带解释器解析」。那是我拿一条宽松
> 正则(连注释与字符串里的包名都算命中)审计出的**保守过头的结论**,条目数也因 `nested-comment` 钩子
> 落地从 42 变 43。现在这条口径由钩子解释器预检每次跑门禁前重算,人不再需要记这个数。
⇒ 写新钩子时二选一,别开第三条路:要么脚本只用标准库,要么在脚本内部按
「显式变量 > 当前解释器 > 仓库 `.venv` > PATH」自行解析并**探针校验**(先例与理由见
`docs/门禁说明/generated-fresh.md` §4)。**不要**把 entry 写死成某台机器的绝对路径。
### 5.2 动环境的失效顺序与回滚(含本笔机械化)
**先把"谁依赖谁"钉住,才知道动一下会红在哪一步**(下表每行都是本机实测或代码事实,不是推测):
| 被动什么 | 第一现场 | 症状 | 还能动什么 |
|---|---|---|---|
| 删 / 重建 `.venv` | `.git/hooks/pre-commit` 里的 `INSTALL_PYTHON` 指它 | `git commit` **当场起不来**:钩子脚本先判 `if [ -x "$INSTALL_PYTHON" ]`,不成立才回落到 PATH 上的 `pre-commit`——本机 `where.exe pre-commit` 报找不到,于是回落分支也是死路 | 重建 `.venv` 后必须 `pip install -r requirements.txt`(含 pre-commit),否则回落分支永远还是死路 |
| 只换 `.venv` 里的包(不删目录) | pre-commit 本体与 `language: python` 钩子各自独立的缓存环境(`~/.cache/pre-commit/repo*/py_env*/`)互不相干 | 只影响 pre-commit 本体;改写型钩子跑在缓存环境里,**看不见** `.venv` 的变动(实测那份缓存环境里连 `identify` 都没装) | 缓存环境坏了要 `pre-commit clean`——它会连别人正在跑的钩子环境一起重建,必须先要到静默窗口 |
| 换 PATH 首位解释器 | 那 43 条裸 python 条目 | 模块级第三方 import 一条都没有 ⇒ 普通情况下无感;但 3.12 → 3.14 这种版本跨度会改变标准库行为,是"靠巧合不炸"的敞口 | 设 `DTU_PRECOMMIT_PYTHON` 只钉得住 pre-commit 本体,**钉不住**裸 python 条目的落点——那只能靠脚本自解析 |
| 改 `requirements.txt` 的版本约束 | 别人机器上的一次 `pip install -r` | 本机无感,别人下次重建环境时才炸 | 这不属于"修本机环境",要改先报属主,别夹在诊断笔里 |
**回滚按现场分条,别混用**:
- `.venv` 被删 / 建坏:`python -m venv .venv` → `pip install -r requirements.txt` →
`& '.venv\Scripts\python.exe' -m pre_commit --version` 通 → `ci_local.py --preflight-only` 通 → 再跑完整门禁。
- 单包装坏:按修复前那次 `pip freeze`(放仓外,不入库)反向 `pip install <包>==<原版本>`;
**不要** `-U` 顺手把别人的依赖一起动。
- 缓存环境坏:`pre-commit clean` 后跑一次 `ci_local.py` 让它重建;重建期间别提交(几十秒内会拿到半装好的环境)。
- 只有全坏透才删 `.venv` 重来;删前记下 `pip freeze`,并记住本仓 `.venv` 基底是 Anaconda
(换机复制不出来,见上面 §5.2 依赖表与 §5.3 第 5 条)。
**本笔把上面这些机械化了一半**:`scripts/ci_local.py` 新增 **钩子解释器预检**(`--preflight-only`
可单跑,也是 `ci_local.py` 每次的第一段),报清"钩子跑在谁身上 / 裸 python 落到谁 / 那个解释器缺什么 /
哪些只是候选",四事齐备即 exit 2 并指名到钩子。红-绿在临时假仓库上验过(同一份配置里 bad-hook 判 FAIL、
good-hook 判 OK,整体 `rc = 2`)。**它不改环境、不装包、不写仓库**,也不替代上面的修复死顺序——
它只保证一件事:这条链下次断掉时报错发生在第一秒,并且带着钩子的名字。
### 5.3 什么情况下才需要动环境,以及动之前要走死顺序
默认动作是**不动**(本节存在即结论:没有需要重装的东西)。只有出现下列**具体现象**才执行修复,
且必须先要到静默窗口——`pre-commit` 与 `.venv` 是全队共享运行面,中途换包会把别人的一次钩子跑打断:
1. 停表:确认没有人在跑提交/门禁/台架(build 与 bench 两类锁都空闲,见 `task-worktree`);
2. 备份指针:记下 `& '.venv\Scripts\python.exe' -m pip freeze > 仓外文件`(不入库);
3. 只补不重建:优先 `pip install --force-reinstall --no-deps <包>==<requirements.txt 里的版本>`,
**不要**顺手 `-U`(那会连带动别人的依赖);确实要整体重建才 `pip install -r requirements.txt`,
且该文件必须保持纯 ASCII(Windows 下 pip 按代码页解码);
4. 自证(缺一不算修完):`& '.venv\Scripts\python.exe' -m pip show pre-commit` 有版本 →
`-m pre_commit --version` 通 → `scripts/check_generated_fresh.py` 与字体字符集钩子在 `.venv`
与 PATH 两种解释器下都 exit 0 → 最后跑一次 `scripts/ci_local.py`;
5. 回滚:新装/升级出问题时按第 2 步的 freeze 反向 `pip install <包>==<原版本>`;**别删 `.venv` 重来**,
删了就把「基底是 Anaconda」这条不可复制性也一起删掉(换机复现不了,见本文 §3 与 `docs/环境与部署/项目部署环境要求.md`)。
### 5.4 仍开着的账(不在本次范围,登记给对应属主)
- `DTU_PRECOMMIT_PYTHON` 本机当前**未设**,靠 §1.1 的优先级自动落到 `.venv`;如果哪天 PATH 首位换了
解释器,静态门禁档就会跟着换——把它显式设成 `.venv` 是一条零成本的加固(改的是本机环境,不动仓库)。
- 42 条裸 `python` entry 与两个解释器的版本差(3.14 vs 3.12):今天没有可观测的行为差,但这是
「靠巧合不炸」。要不要把 entry 统一改成显式解释器解析,属门禁属主的决定(同一族的先例见 §5.1)。
- 本机的 `.venv` 基底是 Anaconda 发行版,`python -m venv` 在别的机器上给出的不是同一个东西;
这条差异目前无人记录在 `docs/环境与部署/项目部署环境要求.md` 里。
## 变更记录
| 日期 | 变更 |
|---|---|
| 2026-10-27 | **新增 §5.2 动环境的失效顺序与回滚(原插成 §5.4,本笔按依赖表→死顺序→遗留账重排)+ §5.1 二次修正(道G task-33 修复分支)**:四种现场(删/换 `.venv`、只换包、换 PATH 首位、改 requirements 约束)逐行钉死"第一现场 / 症状 / 还能动什么",回滚按现场分条不混用;`scripts/ci_local.py` 同批加 **钩子解释器预检**(`--preflight-only` 单跑,也是每次门禁的第一段:报"钩子跑在谁身上 / 裸 python 落到谁 / 缺哪些包 / 哪些是惰性候选",四事齐备 exit 2 指名到钩子,红-绿在临时假仓库验过)。§5.1 那条「42 条里唯一需要第三方包的那条自带解释器解析」被更严的口径推翻:按**模块级 import** 判是 0 条,条目数也因 `nested-comment` 落地变 43;fontTools 属下游**惰性**导入,预检只列候选不判决。 | 2026-10-27 | **新增 §5 解释器实测矩阵(道G task-33,只读诊断,未动任何环境)**:三个解释器(仓库 `.venv` / PATH 首位 / PATH 次位)逐个探针实测,钉住三条事实——① `.venv` **不是残缺**:`pre-commit` 与 `identify` 的 dist-info 齐全(`pip show` 可查),`identify-2.6.19` 的 RECORD 里本就没有 `tags.py`,标签常量在该版本的 `identify.identify` 里,pre-commit 自己也是从那里取(旧写法 `identify.tags` 在这个版本对上必失败,全仓零引用);② 钩子执行环境被 `.git/hooks/pre-commit` 的 `INSTALL_PYTHON` 钉死为 `.venv`,而 `language: system` 的 42 条 entry 用裸 `python` → 落到 PATH 首位那个**零第三方包**的解释器,今天没炸是「42 条全只用标准库 + 唯一需要第三方包的那条自带解释器解析」两件事同时成立,据此写下新增 entry 的硬规则(§5.1);③ 「查不到 pre-commit」的现场是查了 PATH 上的解释器。另附 §5.2「默认不动环境;确需修复时的死顺序与回滚(只补不重建、freeze 备份放仓外、按 freeze 反向回滚、禁止删 `.venv` 重来)」与 §5.3 三条待属主的账。| 2026-10-02 | **文档改造**:删除规划阶段内容(设计结论、路径耦合盘点、代码改造映射、分阶段推广与验收、风险与边界、后续任务拆分),保留并重组为现行机制说明——§1 变量清单(含 Python 优先级特别说明)、§2 解析与失败语义、§3 本机配置方法(会话/用户/runner 三级)、§4 验收判据、变更记录;章节重编号,外部引用同步(`gen_refgraph.py` §3→§1、`ci_local.py` §3.1→§1.1、`Gitea_Runner部署指南.md` §5.3→§3.3) |
| 2026-10-02 | **实施完成**:阶段 A~D 落地。① 10 处调用点全部改为"`DTU_*` 变量优先 + 自动发现回退"(显式值无效 = 硬报错、不静默回退):`build/download/reset.bat`(goto 标签式解析,纯 ASCII)、`ci_local.py`(`DTU_PRECOMMIT_PYTHON` 严格校验)、`ci.yml`(`DTU_PRECOMMIT_PYTHON`/`DTU_CPPCHECK`/`DTU_MSVC_CL`/`DTU_WINDOWS_KITS_ROOT`,run 块纯 ASCII)、`gen_refgraph.py`(`DTU_GRAPHVIZ_DOT`→PATH,保留无渲染降级)、`unit_test_harness.py`(`DTU_MSVC_CL`/`DTU_WINDOWS_KITS_ROOT` + `%ProgramFiles*%` 推导取代静态盘符列表)、`build_sim.ps1`(`DTU_VSWHERE`→`%ProgramFiles(x86)%` 推导,去字面 C 盘回退)、`make_font.py`(`%WINDIR%` 推导);`_build.cmd` 确认零调用后删除。② 本机按 §3.2 配置用户级 `DTU_KEIL_UV4`/`DTU_STLINK_CLI`(其余工具本机均可自动发现,未设变量),验证:`@build` BUILD_OK 0/0、`ci_local.py` 静态门禁 15 钩子 + 主机侧纯逻辑单测 278/278 断言全绿、refgraph 重生成(含修复 `引用关系图.json` 末尾换行缺失导致的 end-of-file-fixer 抖动,生成器补 `f.write("\n")`)、`build_sim.ps1` vswhere 推导命中 VS2026(当时模拟器 CMake 配置期暴露**既有**问题:`App/cfg_file.c` 已移入 `App/cfg/` 但 `simulator/CMakeLists.txt` 未同步——与环境变量改造无关;2026-10-02 已修复:CMakeLists 同步 `App/cfg/` + `test/board/` 引用,模拟器全量构建通过)、`reset.bat list` 识别探针。③ 文档收口:`AGENTS.md`/`MDK-ARM/README.md`/`项目部署环境要求.md`(新增 §2.1.1)/`Gitea_Runner部署指南.md`(新增 §5.1.3 机器级变量)/`CI配置指南.md`/`pre-commit使用说明.md`/字体/测试流程/引用图说明/ST-LINK 说明/实机规划/`scripts/README.md` 共 12 篇同步为变量口径。④ `requirements.txt` 增 `pre-commit==4.6.2`(重建 `.venv` 即可跑静态门禁)。⑤ 全量 `pre-commit --all-files` + `ci_local.py` 通过。待办:新 workflow 推送远程后跑一次 CI 两 job 闭环验证;第二台不同安装路径机器的交叉验证(操作清单已固化入 `项目部署环境要求.md` §2.12) |
| 2026-10-02 | 初版规划:盘点 BAT/Python/PowerShell/Gitea workflow 中机器相关工具路径;定义 `DTU_*` 变量清单、优先级、用户级与 SYSTEM runner 配置边界;规划 4 阶段迁移及离线/实机验收范围。未改工具调用代码 |