本地工具路径DTU_*环境变量改造落地:10处调用点去硬编码+变量优先解析,本机全链路验证通过,文档同步收口,requirements补pre-commit

This commit is contained in:
2026-10-02 22:14:49 +08:00
parent b96d649e62
commit 33a4aa4945
30 changed files with 4074 additions and 2917 deletions
+122 -45
View File
@@ -49,6 +49,11 @@
# Python 3.x、cppcheck、pre-commit、MSVC(VS2019/2022 的 C++ 工具链 + Windows SDK)
# - 缺 MSVC 时 L0.5 步骤会**降级为提示并跳过**(不硬失败),但会打印醒目 WARNING
#
# 🔧 runner 机器级环境变量(可选项覆盖;runner 以 SYSTEM 服务运行,用户级变量不可见):
# DTU_PRECOMMIT_PYTHON / DTU_CPPCHECK / DTU_MSVC_CL —— 未设置时按 PATH / 标准 VS 布局自动发现。
# 变量显式设置但值无效时 job 直接报变量名并失败(不静默回退)。配置方法见
# docs/环境与部署/本地工具路径环境变量方案.md §5.3。
#
# 本地等价命令(与 CI 同一套判定,见 scripts/ci_local.py):
# & '.venv\Scripts\python.exe' scripts/ci_local.py
@@ -96,9 +101,10 @@ jobs:
# --- pick a Python that actually has pre-commit -------------------
# The runner runs as SYSTEM, whose PATH is NOT the dev user's PATH.
# On this box SYSTEM's `python` is C:\msys64\...\python.exe (3.14.5,
# no pre-commit). Probe the same order as scripts/ci_local.py:
# PATH python -> .venv -> anaconda3
# Probe order per the DTU_* env var plan (kept in sync with
# scripts/ci_local.py):
# DTU_PRECOMMIT_PYTHON (explicit; invalid value = hard error)
# -> PATH python -> repo .venv
#
# CAUTION 1: a failing native command writes to stderr; with
# $ErrorActionPreference='Stop' that would abort the whole script
@@ -110,27 +116,46 @@ jobs:
# see at all -- no python.exe path can help then. Probe with `-s`
# (no user-site) so we only accept an interpreter that works for
# SYSTEM, and say so clearly when none is found.
$candidates = @(
(Get-Command python -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source),
(Join-Path $repoRoot '.venv\Scripts\python.exe'),
'C:\ProgramData\anaconda3\python.exe'
)
$py = $null
$saved = $ErrorActionPreference
foreach ($c in $candidates) {
if (-not $c) { continue }
if (-not (Test-Path $c)) { continue }
$envPy = $env:DTU_PRECOMMIT_PYTHON
if ($envPy) {
if (-not (Test-Path $envPy)) {
$ErrorActionPreference = 'Stop'
Write-Host "::error::DTU_PRECOMMIT_PYTHON is set but does not exist: $envPy"
Write-Host "::error::fix the variable (full path to a python.exe with pre-commit), or unset it to use auto-discovery"
exit 1
}
$ErrorActionPreference = 'Continue'
& $c -s -m pre_commit --version 2>&1 | Out-Null
& $envPy -s -m pre_commit --version 2>&1 | Out-Null
$rc = $LASTEXITCODE
$ErrorActionPreference = $saved
if ($rc -eq 0) { $py = $c; break }
if ($rc -ne 0) {
$ErrorActionPreference = 'Stop'
Write-Host "::error::DTU_PRECOMMIT_PYTHON does not have a SYSTEM-visible pre-commit: $envPy"
exit 1
}
$py = $envPy
} else {
$candidates = @(
(Get-Command python -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source),
(Join-Path $repoRoot '.venv\Scripts\python.exe')
)
foreach ($c in $candidates) {
if (-not $c) { continue }
if (-not (Test-Path $c)) { continue }
$ErrorActionPreference = 'Continue'
& $c -s -m pre_commit --version 2>&1 | Out-Null
$rc = $LASTEXITCODE
$ErrorActionPreference = $saved
if ($rc -eq 0) { $py = $c; break }
}
}
$ErrorActionPreference = 'Stop'
if (-not $py) {
Write-Host "::error::no Python with a SYSTEM-visible pre-commit. Tried: $($candidates -join ' | ')"
Write-Host "::error::no Python with a SYSTEM-visible pre-commit (DTU_PRECOMMIT_PYTHON not set; tried PATH python and repo .venv)"
Write-Host "::error::pre-commit is probably installed only in a USER site (invisible to SYSTEM)."
Write-Host "::error::fix (elevated): powershell -ExecutionPolicy Bypass -File D:\Docker\act_runner\install_precommit_global.ps1"
Write-Host "::error::fix: set a MACHINE-level DTU_PRECOMMIT_PYTHON for the runner service and restart it, or install pre-commit globally for the SYSTEM account (see the Gitea runner deployment guide in docs/)"
exit 1
}
Write-Host "using python: $py"
@@ -139,21 +164,31 @@ jobs:
"PYTHON=$py" | Out-File -FilePath $env:GITHUB_ENV -Append
# --- cppcheck -----------------------------------------------------
# cppcheck is often installed with a USER-scope PATH entry, which
# SYSTEM cannot see. Fall back to its default install dir.
$cpp = Get-Command cppcheck -ErrorAction SilentlyContinue
if ($cpp) {
Write-Host "found cppcheck: $($cpp.Source)"
} elseif (Test-Path 'C:\Program Files\Cppcheck\cppcheck.exe') {
$dir = 'C:\Program Files\Cppcheck'
# Order per the DTU_* plan: DTU_CPPCHECK (explicit; invalid = hard
# error, no fallback) -> PATH (Get-Command cppcheck). No fixed
# install-dir guess: a USER-scope PATH entry is invisible to SYSTEM,
# so on the runner set a MACHINE-level DTU_CPPCHECK if cppcheck is
# not on SYSTEM's PATH.
$envCpp = $env:DTU_CPPCHECK
if ($envCpp) {
if (-not (Test-Path $envCpp)) {
Write-Host "::error::DTU_CPPCHECK is set but does not exist: $envCpp"
exit 1
}
$dir = Split-Path -Parent $envCpp
$env:Path = "$env:Path;$dir"
$dir | Out-File -FilePath $env:GITHUB_PATH -Append
Write-Host "cppcheck not on PATH; added $dir (User-scope PATH is invisible to SYSTEM)"
Write-Host "using cppcheck from DTU_CPPCHECK: $envCpp"
& $envCpp --version
} else {
Write-Host "::error::runner missing cppcheck -- install it, then re-run"
exit 1
$cpp = Get-Command cppcheck -ErrorAction SilentlyContinue
if (-not $cpp) {
Write-Host "::error::runner missing cppcheck (not on SYSTEM PATH) -- set a machine-level DTU_CPPCHECK, or add its directory to the machine PATH, then re-run"
exit 1
}
Write-Host "found cppcheck: $($cpp.Source)"
cppcheck --version
}
cppcheck --version
Write-Host "runner environment check passed"
@@ -257,19 +292,50 @@ jobs:
id: msvc
shell: powershell
run: |
# Keep in sync with VS_ROOTS in test/host/common/unit_test_harness.py
$roots = @(
'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools',
'C:\Program Files\Microsoft Visual Studio\2022\BuildTools',
'C:\Program Files\Microsoft Visual Studio\2022\Community',
'C:\Program Files\Microsoft Visual Studio\2022\Professional'
)
# MSVC discovery per the DTU_* plan, kept in sync with
# test/host/common/unit_test_harness.py:
# DTU_MSVC_CL (explicit x64 cl.exe; invalid = hard error)
# -> auto-probe standard VS roots derived from %ProgramFiles%
# / %ProgramFiles(x86)% (2019 / 2022 / 2026, all editions)
$found = $false
foreach ($r in $roots) {
if (Test-Path $r) {
$cl = Get-ChildItem -Path $r -Recurse -Filter 'cl.exe' -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -like '*Hostx64\x64*' } | Select-Object -First 1
if ($cl) { $found = $true; Write-Host "found cl.exe: $($cl.FullName)"; break }
$envCl = $env:DTU_MSVC_CL
if ($envCl) {
if (-not (Test-Path $envCl)) {
Write-Host "::error::DTU_MSVC_CL is set but does not exist: $envCl"
exit 1
}
if ($envCl -notlike '*bin\Hostx64\x64\cl.exe') {
Write-Host "::error::DTU_MSVC_CL must be the x64 Host compiler (path ending bin\Hostx64\x64\cl.exe): $envCl"
exit 1
}
$found = $true
Write-Host "using cl.exe from DTU_MSVC_CL: $envCl"
} else {
$pf = ${env:ProgramFiles}
$pf86 = ${env:ProgramFiles(x86)}
if (-not $pf) { $pf = 'C:\Program Files' }
if (-not $pf86) { $pf86 = 'C:\Program Files (x86)' }
$roots = @(
(Join-Path $pf86 'Microsoft Visual Studio\2019\BuildTools'),
(Join-Path $pf86 'Microsoft Visual Studio\2019\Community'),
(Join-Path $pf86 'Microsoft Visual Studio\2019\Professional'),
(Join-Path $pf 'Microsoft Visual Studio\2022\BuildTools'),
(Join-Path $pf 'Microsoft Visual Studio\2022\Community'),
(Join-Path $pf 'Microsoft Visual Studio\2022\Professional'),
(Join-Path $pf 'Microsoft Visual Studio\2022\Enterprise'),
(Join-Path $pf 'Microsoft Visual Studio\2026\BuildTools'),
(Join-Path $pf 'Microsoft Visual Studio\2026\Community'),
(Join-Path $pf 'Microsoft Visual Studio\18\BuildTools'),
(Join-Path $pf 'Microsoft Visual Studio\18\Community'),
(Join-Path $pf 'Microsoft Visual Studio\18\Professional'),
(Join-Path $pf 'Microsoft Visual Studio\18\Enterprise')
)
foreach ($r in $roots) {
if (Test-Path $r) {
$cl = Get-ChildItem -Path $r -Recurse -Filter 'cl.exe' -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -like '*Hostx64\x64*' } | Select-Object -First 1
if ($cl) { $found = $true; Write-Host "found cl.exe: $($cl.FullName)"; break }
}
}
}
if ($found) {
@@ -285,16 +351,27 @@ jobs:
shell: powershell
run: |
# Resolve a working Python first (SYSTEM's PATH python may be unusable).
# Order per the DTU_* plan: DTU_PRECOMMIT_PYTHON (explicit; invalid =
# hard error) -> PATH python -> repo .venv.
$repoRoot = (Get-Location).Path
$py = $null
foreach ($c in @(
(Get-Command python -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source),
(Join-Path $repoRoot '.venv\Scripts\python.exe'),
'C:\ProgramData\anaconda3\python.exe'
)) {
if ($c -and (Test-Path $c)) { $py = $c; break }
$envPy = $env:DTU_PRECOMMIT_PYTHON
if ($envPy) {
if (-not (Test-Path $envPy)) {
Write-Host "::error::DTU_PRECOMMIT_PYTHON is set but does not exist: $envPy"
exit 1
}
$py = $envPy
}
if (-not $py) { Write-Host "::error::no python found"; exit 1 }
if (-not $py) {
foreach ($c in @(
(Get-Command python -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source),
(Join-Path $repoRoot '.venv\Scripts\python.exe')
)) {
if ($c -and (Test-Path $c)) { $py = $c; break }
}
}
if (-not $py) { Write-Host "::error::no python found (set DTU_PRECOMMIT_PYTHON or fix the runner PATH)"; exit 1 }
Write-Host "using python: $py"
New-Item -ItemType Directory -Force -Path 'ci-artifacts' | Out-Null
+1 -1
View File
@@ -39,7 +39,7 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
## 关联注意
- `.venv` 缺失/换机:`& 'C:\ProgramData\anaconda3\python.exe' -m venv .venv; & '.venv\Scripts\python.exe' -m pip install -r requirements.txt`
- `.venv` 缺失/换机:`& <本机任一 python ≥3.10> -m venv .venv; & '.venv\Scripts\python.exe' -m pip install -r requirements.txt`(`requirements.txt` 已含 `pre-commit`,重建后 L0 门禁直接可跑)
- 新增 UI `.c` 文件先走 `new-source-file` skill 双端注册,否则一端静默缺文件
- 字体重生成后全页大面积像素差异属预期:确认字形正确后 `--update` 刷参考
- 涉及新界面/大改时本 skill 是 P3 门禁,完整管线(P0~P5)见 `docs/UI设计/UI_界面制作流程.md`
+3 -3
View File
@@ -14,17 +14,17 @@ STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v
## 构建与验证
- `@build` = `& "MDK-ARM\build.bat"`(仓库根目录用**相对路径**);退出码 0 = 0 错误 0 警告,1 = 有警告或错误(查 `MDK-ARM/build_log.txt`);`build.bat` 硬编码本机 Keil 路径 `C:\Keil_v5\UV4\UV4.exe`(换机需改)
- `@build` = `& "MDK-ARM\build.bat"`(仓库根目录用**相对路径**);退出码 0 = 0 错误 0 警告,1 = 有警告或错误(查 `MDK-ARM/build_log.txt`),2 = `DTU_KEIL_UV4` 未设/无效(换机必设,见 `docs/环境与部署/本地工具路径环境变量方案.md`);UV4 路径经 `DTU_KEIL_UV4` 环境变量解析(**不再硬编码**;显式设置但无效会立即报错、不静默回退)
- `@test` / `test/host/run_boot_test.py` 一键闭环(2026-09-20 起为纯 Python 标准库实现,替代 PowerShell 版;`& '.venv\Scripts\python.exe' test/host/run_boot_test.py`):开串口+清日志 → 烧录(`MDK-ARM/download.bat`,下载后 Reset&Run)→ wait-idle(等 RX 静默 8s,超时 30s)→ `test/host/verify_log.py` 标记校验;退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法/预检错误
- 默认校验标记:Required `App init OK` / `Network Init` / `net init: OK`;Forbidden `FAIL` / `ERROR` / `HardFault` / `[ERR]`(**四个 Fault 的崩溃日志都以 `[ERR]` 开头 → 一律判 FAIL**,这是刻意的:出现 Fault 即本次运行不通过);按模块定制标记(网络/存储/RTC/ADC/RS485/UI)见 `docs/测试说明/自动化测试流程.md`
- ⚠️ 旧绝对路径 `D:\Code\DTU 程序\...` 出现即失效(仓库已搬迁),一律改用仓库相对路径
- **下载/烧录铁律(2026-09-20 实测)**:走 `& "MDK-ARM\reset.bat" flash [文件]`(= `ST-LINK_CLI -c SWD -P <文件> -Rst -Run`),烧后 `-Rst -Run` **不可省略**——裸 `-P` 会报 `Programming Complete`,但目标核处于死循环/异常状态时写入并不落地(芯片内容不变;这就是 09/19~09/20 "反复重下载、芯片一直是旧镜像、二分法失效" 的根因);`.hex`/`.bin` 均可直烧(1MB ≈ 6.5s,快于 UV4 路径);只重启不烧录用 `reset.bat` 无参(= `-c SWD -Rst -Run`,本机 3 线接线唯一复位手段:nRST 未接、`-HardRst`/`RM=` 不可用)
- **烧录后必须回读校验**:`ST-LINK_CLI -c SWD -CmpFile <文件> 0x08000000`(全片逐字节比对,`No difference found` 才算真正写入);CLI = `C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe`(v3.5.0.0,探针 SN `0B250D12A218303030303032`)→ 完整用法/复位语义/故障排查 `docs/测试说明/ST-LINK_CLI_复位使用说明.md`
- **烧录后必须回读校验**:`ST-LINK_CLI -c SWD -CmpFile <文件> 0x08000000`(全片逐字节比对,`No difference found` 才算真正写入);CLI 经 `DTU_STLINK_CLI` 环境变量解析(未设时回退 PATH;本机已入 PATH,未设也能工作)(v3.5.0.0,探针 SN `0B250D12A218303030303032`)→ 完整用法/复位语义/故障排查 `docs/测试说明/ST-LINK_CLI_复位使用说明.md`
## Python 环境
- 统一入口 `& '.venv\Scripts\python.exe'`(3.12,fontTools/Pillow 已装);PATH 默认 `python` 是 msys64 的,**不要用它**跑依赖第三方库的脚本;纯标准库脚本任意 python3 均可
- 重建/换机:`& 'C:\ProgramData\anaconda3\python.exe' -m venv .venv` + `pip install -r requirements.txt`(`.venv/` 已 gitignore)
- 重建/换机:`& <本机任一 python ≥3.10> -m venv .venv` + `pip install -r requirements.txt`(含 `pre-commit`,重建后 L0 门禁直接可跑;`DTU_PRECOMMIT_PYTHON` 可指向装了 pre-commit 的其他解释器)(`.venv/` 已 gitignore)
- `requirements.txt` 必须**纯 ASCII**(Windows 下 pip 按 GBK 代码页解码,中文注释会 UnicodeDecodeError)
## 提交门禁(pre-commit)
+1 -1
View File
@@ -58,7 +58,7 @@
## ⚠️ 注意
- `build.bat` **硬编码本机 Keil 路径** `C:\Keil_v5\UV4\UV4.exe`(换机需改)
- 工具路径经 `DTU_*` 环境变量解析(`DTU_KEIL_UV4` = UV4.exe 完整路径,`DTU_STLINK_CLI` = ST-LINK_CLI.exe 完整路径;换机设变量即可,**无需改脚本**;契约见 `docs/环境与部署/本地工具路径环境变量方案.md`)
- 本目录被 pre-commit 门禁**排除**
- 启动文件的 `Heap_Size = 512B` 是**自研代码禁用 `malloc` 的根因**(见 `AGENTS.md`)
-1
View File
@@ -1 +0,0 @@
@echo off && cd /d "%~dp0" && C:\Keil_v5\UV4\UV4.exe -r "STM32F407-Demo.uvprojx" -t STM32F407-Demo -j0
+21 -1
View File
@@ -1,11 +1,31 @@
@echo off
setlocal
set UV4=C:\Keil_v5\UV4\UV4.exe
set PROJ=%~dp0STM32F407-Demo.uvprojx
set LOG=%~dp0build_log.txt
set TARGET=STM32F407-Demo
:: UV4 location: env var DTU_KEIL_UV4 = full path of UV4.exe.
:: Required on any MCU build machine; there is NO machine-default fallback
:: (no C:\Keil_v5 guess). Set it once per machine, user scope (no admin):
:: [Environment]::SetEnvironmentVariable('DTU_KEIL_UV4', 'D:\Tools\Keil\UV4\UV4.exe', 'User')
:: then reopen the terminal. Full contract: the DTU_* env var plan document
:: in docs/ (local tool path env vars plan).
if defined DTU_KEIL_UV4 goto uv4_set
echo BUILD_FAIL: environment variable DTU_KEIL_UV4 is not set
echo Set it to the full path of UV4.exe, e.g.:
echo [Environment]::SetEnvironmentVariable('DTU_KEIL_UV4', 'D:\Tools\Keil\UV4\UV4.exe', 'User')
exit /b 2
:uv4_set
if exist "%DTU_KEIL_UV4%" goto uv4_ok
echo ENV_ERROR: DTU_KEIL_UV4 is set but does not exist: "%DTU_KEIL_UV4%"
echo Fix the variable value. No fallback to another UV4 install is attempted.
exit /b 2
:uv4_ok
set UV4=%DTU_KEIL_UV4%
:: UV4 is single-instance: if an IDE process is alive, this -b call may be
:: forwarded to it (exit code is lost, GUI may open). Warn only; never kill.
tasklist /fi "imagename eq UV4.exe" /nh | find /i "UV4.exe" >nul
+17 -1
View File
@@ -1,11 +1,27 @@
@echo off
setlocal
set UV4=C:\Keil_v5\UV4\UV4.exe
set PROJ=%~dp0STM32F407-Demo.uvprojx
set LOG=%~dp0download_log.txt
set TARGET=STM32F407-Demo
:: UV4 location: env var DTU_KEIL_UV4 = full path of UV4.exe (same contract
:: as build.bat; required, no machine-default fallback).
if defined DTU_KEIL_UV4 goto uv4_set
echo DOWNLOAD_FAIL: environment variable DTU_KEIL_UV4 is not set
echo Set it to the full path of UV4.exe, e.g.:
echo [Environment]::SetEnvironmentVariable('DTU_KEIL_UV4', 'D:\Tools\Keil\UV4\UV4.exe', 'User')
exit /b 2
:uv4_set
if exist "%DTU_KEIL_UV4%" goto uv4_ok
echo ENV_ERROR: DTU_KEIL_UV4 is set but does not exist: "%DTU_KEIL_UV4%"
echo Fix the variable value. No fallback to another UV4 install is attempted.
exit /b 2
:uv4_ok
set UV4=%DTU_KEIL_UV4%
"%UV4%" -f "%PROJ%" -t%TARGET% -j0 -o "%LOG%"
findstr /C:"Application running" "%LOG%" >nul
+31 -4
View File
@@ -1,11 +1,38 @@
@echo off
setlocal
set STLINK=C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe
if not exist "%STLINK%" (
echo RESET_FAIL: ST-LINK_CLI not found at "%STLINK%"
exit /b 2
:: ST-LINK CLI location: env var DTU_STLINK_CLI = full path of ST-LINK_CLI.exe.
:: Explicit value is used as-is (invalid value = hard error, no silent fallback);
:: when unset, fall back to PATH (where ST-LINK_CLI.exe).
set "STLINK="
if defined DTU_STLINK_CLI goto stlink_check
where ST-LINK_CLI.exe >nul 2>&1
if errorlevel 1 goto stlink_missing
for /f "delims=" %%i in ('where ST-LINK_CLI.exe 2^>nul') do (
if not defined STLINK set "STLINK=%%i"
)
if not defined STLINK goto stlink_missing
goto stlink_done
:stlink_check
if exist "%DTU_STLINK_CLI%" goto stlink_done
echo ENV_ERROR: DTU_STLINK_CLI is set but does not exist: "%DTU_STLINK_CLI%"
echo Fix the variable value. No fallback to PATH or other installs is attempted.
exit /b 2
:stlink_missing
echo ENV_ERROR: ST-LINK_CLI.exe not found (DTU_STLINK_CLI unset and not on PATH)
echo Set it to the full path of ST-LINK_CLI.exe, e.g.:
echo [Environment]::SetEnvironmentVariable('DTU_STLINK_CLI', 'C:\Tools\STLink\ST-LINK_CLI.exe', 'User')
exit /b 2
:stlink_done
if not defined STLINK set "STLINK=%DTU_STLINK_CLI%"
if exist "%STLINK%" goto stlink_ready
echo RESET_FAIL: ST-LINK_CLI not found at "%STLINK%"
exit /b 2
:stlink_ready
if "%~1"=="" goto :reset_run
if /i "%~1"=="hard" goto :hard
@@ -33,7 +33,7 @@
> & '.venv\Scripts\python.exe' tools/font_gen/make_font.py
> ```
>
> PATH 默认 `python` 是 msys64 的(无 fonttools),直接跑会失败。`.venv` 缺失/换机时重建:`& 'C:\ProgramData\anaconda3\python.exe' -m venv .venv; & '.venv\Scripts\python.exe' -m pip install -r requirements.txt`。
> PATH 默认 `python` 是 msys64 的(无 fonttools),直接跑会失败。`.venv` 缺失/换机时重建:`& <本机任一 python ≥3.10> -m venv .venv; & '.venv\Scripts\python.exe' -m pip install -r requirements.txt`(`requirements.txt` 已含 `pre-commit`,重建后 L0 门禁直接可跑)。
> `extract_cn.py` 纯标准库,任意 python3 均可。
---
+44
View File
@@ -10,6 +10,8 @@ digraph refgraph_full {
"App/cfg/cfg_file.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/cfg/cfg_file_store.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/cfg/cfg_file_store_mcu.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/fs/vol_lock.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/fs/vol_lock.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/log/console_log.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/log/console_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/log/sys_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
@@ -161,6 +163,13 @@ digraph refgraph_full {
"test/board/test_common.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/board/test_config.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/board/test_config.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/cfg_file/cfg_file_test.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/cfg_file/stub/dbg_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/sys_clock/stub/FreeRTOS.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/sys_clock/stub/dbg_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/sys_clock/stub/main.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/sys_clock/stub/task.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/sys_clock/sys_clock_test.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/watchdog/stub/dbg_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/watchdog/stub/iwdg.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/host/watchdog/stub/main.h" [fillcolor="#dbeafe", color="#1d4ed8"];
@@ -170,6 +179,7 @@ digraph refgraph_full {
"App/app/app_main.c" -> "App/app/app_main.h" [color="#2563eb", penwidth=1.0];
"App/app/app_main.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/app/app_main.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"App/app/app_main.c" -> "App/util/task_watchdog.h" [color="#2563eb", penwidth=1.0];
"App/app/app_main.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"App/app/app_main.c" -> "Drivers/BSP/RS485/rs485.h" [color="#2563eb", penwidth=1.0];
"App/app/app_main.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
@@ -188,11 +198,16 @@ digraph refgraph_full {
"App/cfg/cfg_file.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/cfg/cfg_file_store.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/cfg/cfg_file_store_mcu.c" -> "App/cfg/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
"App/cfg/cfg_file_store_mcu.c" -> "App/fs/vol_lock.h" [color="#2563eb", penwidth=1.0];
"App/cfg/cfg_file_store_mcu.c" -> "Lib/FatFs/ff.h" [color="#94a3b8", penwidth=0.7];
"App/cfg/cfg_file_store_mcu.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"App/cfg/cfg_file_store_mcu.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/fs/vol_lock.c" -> "App/fs/vol_lock.h" [color="#2563eb", penwidth=1.0];
"App/fs/vol_lock.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/fs/vol_lock.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/log/console_log.c" -> "App/app/sys_events.h" [color="#2563eb", penwidth=1.0];
"App/log/console_log.c" -> "App/log/console_log.h" [color="#2563eb", penwidth=1.0];
"App/log/console_log.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/log/console_log.c" -> "Inc/usart.h" [color="#2563eb", penwidth=1.0];
"App/log/console_log.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/log/console_log.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
@@ -200,6 +215,7 @@ digraph refgraph_full {
"App/log/console_log.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/log/console_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/log/sys_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/log/sys_log_mcu.c" -> "App/fs/vol_lock.h" [color="#2563eb", penwidth=1.0];
"App/log/sys_log_mcu.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/log/sys_log_mcu.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"App/log/sys_log_mcu.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
@@ -220,6 +236,7 @@ digraph refgraph_full {
"App/task/adc_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/task/default_task.c" -> "App/app/sys_events.h" [color="#2563eb", penwidth=1.0];
"App/task/default_task.c" -> "App/cfg/cfg_file.h" [color="#2563eb", penwidth=1.0];
"App/task/default_task.c" -> "App/fs/vol_lock.h" [color="#2563eb", penwidth=1.0];
"App/task/default_task.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/task/default_task.c" -> "App/task/default_task.h" [color="#2563eb", penwidth=1.0];
"App/task/default_task.c" -> "App/util/task_watchdog.h" [color="#2563eb", penwidth=1.0];
@@ -269,10 +286,16 @@ digraph refgraph_full {
"App/util/sys_clock.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/util/sys_clock.h" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"App/util/sys_clock.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/util/task_watchdog.c" -> "App/log/console_log.h" [color="#2563eb", penwidth=1.0];
"App/util/task_watchdog.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/util/task_watchdog.c" -> "App/util/task_watchdog.h" [color="#2563eb", penwidth=1.0];
"App/util/task_watchdog.c" -> "Drivers/BSP/NET/lftpd/lftpd.h" [color="#94a3b8", penwidth=0.7];
"App/util/task_watchdog.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/util/task_watchdog.c" -> "Inc/iwdg.h" [color="#2563eb", penwidth=1.0];
"App/util/task_watchdog.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"App/util/task_watchdog.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"App/util/task_watchdog.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
"App/util/task_watchdog.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/util/task_watchdog.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/CH395F/ch395f.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/CH395F/ch395f.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
@@ -333,6 +356,7 @@ digraph refgraph_full {
"Drivers/BSP/RS485/rs485.c" -> "Drivers/BSP/RS485/rs485.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/RS485/rs485.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/SD2506/sd2506.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/SD2506/sd2506.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/SD2506/sd2506.c" -> "Inc/i2c.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/SD2506/sd2506.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/SD2506/sd2506.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
@@ -457,6 +481,7 @@ digraph refgraph_full {
"Src/freertos.c" -> "App/sync/time_sync.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/task/default_task.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/task/net_task.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/util/task_watchdog.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Drivers/BSP/NET/lftpd/lftpd.h" [color="#94a3b8", penwidth=0.7];
"Src/freertos.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
@@ -474,6 +499,7 @@ digraph refgraph_full {
"Src/iwdg.c" -> "Inc/iwdg.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "App/app/app_main.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "App/util/task_watchdog.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/NET/net_select.h" [color="#2563eb", penwidth=1.0];
@@ -605,6 +631,24 @@ digraph refgraph_full {
"test/board/test_config.h" -> "test/board/sd2506_test.h" [color="#2563eb", penwidth=1.0];
"test/board/test_config.h" -> "test/board/storage_test.h" [color="#2563eb", penwidth=1.0];
"test/board/test_config.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/cfg_file/cfg_file_test.c" -> "App/cfg/cfg_file.c" [color="#2563eb", penwidth=1.0];
"test/host/cfg_file/cfg_file_test.c" -> "App/cfg/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
"test/host/cfg_file/cfg_file_test.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"test/host/cfg_file/cfg_file_test.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/host/cfg_file/cfg_file_test.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/cfg_file/stub/dbg_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/sys_clock/stub/FreeRTOS.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/sys_clock/stub/dbg_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/sys_clock/stub/main.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/sys_clock/stub/task.h" -> "test/host/sys_clock/stub/FreeRTOS.h" [color="#2563eb", penwidth=1.0];
"test/host/sys_clock/sys_clock_test.c" -> "App/util/sys_clock.c" [color="#2563eb", penwidth=1.0];
"test/host/sys_clock/sys_clock_test.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"test/host/sys_clock/sys_clock_test.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"test/host/sys_clock/sys_clock_test.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/host/sys_clock/sys_clock_test.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"test/host/sys_clock/sys_clock_test.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"test/host/sys_clock/sys_clock_test.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
"test/host/sys_clock/sys_clock_test.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/watchdog/stub/dbg_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/watchdog/stub/iwdg.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/host/watchdog/stub/main.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
+323 -5
View File
@@ -33,6 +33,14 @@
"path": "App/cfg/cfg_file_store_mcu.c",
"class": "fp"
},
{
"path": "App/fs/vol_lock.c",
"class": "fp"
},
{
"path": "App/fs/vol_lock.h",
"class": "fp"
},
{
"path": "App/log/console_log.c",
"class": "fp"
@@ -5573,6 +5581,34 @@
"path": "test/board/test_config.h",
"class": "fp"
},
{
"path": "test/host/cfg_file/cfg_file_test.c",
"class": "fp"
},
{
"path": "test/host/cfg_file/stub/dbg_log.h",
"class": "fp"
},
{
"path": "test/host/sys_clock/stub/FreeRTOS.h",
"class": "fp"
},
{
"path": "test/host/sys_clock/stub/dbg_log.h",
"class": "fp"
},
{
"path": "test/host/sys_clock/stub/main.h",
"class": "fp"
},
{
"path": "test/host/sys_clock/stub/task.h",
"class": "fp"
},
{
"path": "test/host/sys_clock/sys_clock_test.c",
"class": "fp"
},
{
"path": "test/host/watchdog/stub/dbg_log.h",
"class": "fp"
@@ -5661,6 +5697,12 @@
"kind": "fp-fp",
"include": "sys_log.h"
},
{
"from": "App/app/app_main.c",
"to": "App/util/task_watchdog.h",
"kind": "fp-fp",
"include": "task_watchdog.h"
},
{
"from": "App/app/app_main.c",
"to": "Drivers/BSP/dbg_log.h",
@@ -5775,6 +5817,30 @@
"kind": "fp-tp",
"include": "ff.h"
},
{
"from": "App/cfg/cfg_file_store_mcu.c",
"to": "App/fs/vol_lock.h",
"kind": "fp-fp",
"include": "vol_lock.h"
},
{
"from": "App/fs/vol_lock.c",
"to": "App/fs/vol_lock.h",
"kind": "fp-fp",
"include": "vol_lock.h"
},
{
"from": "App/fs/vol_lock.c",
"to": "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h",
"kind": "fp-tp",
"include": "cmsis_os.h"
},
{
"from": "App/fs/vol_lock.h",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdint.h"
},
{
"from": "App/log/console_log.c",
"to": "App/log/console_log.h",
@@ -5817,6 +5883,12 @@
"kind": "fp-fp",
"include": "sys_events.h"
},
{
"from": "App/log/console_log.c",
"to": "App/log/sys_log.h",
"kind": "fp-fp",
"include": "sys_log.h"
},
{
"from": "App/log/console_log.h",
"to": "外部/系统头文件",
@@ -5883,6 +5955,12 @@
"kind": "fp-fp",
"include": "sys_clock.h"
},
{
"from": "App/log/sys_log_mcu.c",
"to": "App/fs/vol_lock.h",
"kind": "fp-fp",
"include": "vol_lock.h"
},
{
"from": "App/sync/time_sync.c",
"to": "外部/系统头文件",
@@ -6039,6 +6117,12 @@
"kind": "fp-fp",
"include": "task_watchdog.h"
},
{
"from": "App/task/default_task.c",
"to": "App/fs/vol_lock.h",
"kind": "fp-fp",
"include": "vol_lock.h"
},
{
"from": "App/task/net_task.c",
"to": "外部/系统头文件",
@@ -6285,6 +6369,42 @@
"kind": "fp-fp",
"include": "iwdg.h"
},
{
"from": "App/util/task_watchdog.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "string.h"
},
{
"from": "App/util/task_watchdog.c",
"to": "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h",
"kind": "fp-tp",
"include": "FreeRTOS.h"
},
{
"from": "App/util/task_watchdog.c",
"to": "Middlewares/Third_Party/FreeRTOS/Source/include/task.h",
"kind": "fp-tp",
"include": "task.h"
},
{
"from": "App/util/task_watchdog.c",
"to": "Drivers/BSP/NET/lftpd/lftpd.h",
"kind": "fp-tp",
"include": "lftpd.h"
},
{
"from": "App/util/task_watchdog.c",
"to": "App/log/sys_log.h",
"kind": "fp-fp",
"include": "sys_log.h"
},
{
"from": "App/util/task_watchdog.c",
"to": "App/log/console_log.h",
"kind": "fp-fp",
"include": "console_log.h"
},
{
"from": "App/util/task_watchdog.c",
"to": "Drivers/BSP/dbg_log.h",
@@ -6795,6 +6915,18 @@
"kind": "tp-tp",
"include": "private/lftpd_io.h"
},
{
"from": "Drivers/BSP/NET/lftpd/lftpd_io.c",
"to": "Drivers/BSP/NET/lftpd/lftpd.h",
"kind": "tp-tp",
"include": "lftpd.h"
},
{
"from": "Drivers/BSP/NET/lftpd/lftpd_io.c",
"to": "App/fs/vol_lock.h",
"kind": "tp-tp",
"include": "vol_lock.h"
},
{
"from": "Drivers/BSP/NET/lftpd/lftpd_io.c",
"to": "Drivers/BSP/dbg_log.h",
@@ -6999,6 +7131,12 @@
"kind": "fp-fp",
"include": "i2c.h"
},
{
"from": "Drivers/BSP/SD2506/sd2506.c",
"to": "Drivers/BSP/dbg_log.h",
"kind": "fp-fp",
"include": "dbg_log.h"
},
{
"from": "Drivers/BSP/SD2506/sd2506.h",
"to": "Inc/main.h",
@@ -38787,6 +38925,12 @@
"kind": "fp-tp",
"include": "lftpd.h"
},
{
"from": "Src/freertos.c",
"to": "App/util/task_watchdog.h",
"kind": "fp-fp",
"include": "task_watchdog.h"
},
{
"from": "Src/freertos.c",
"to": "test/board/ch395f_test_task.h",
@@ -38949,6 +39093,12 @@
"kind": "fp-fp",
"include": "sys_clock.h"
},
{
"from": "Src/main.c",
"to": "App/util/task_watchdog.h",
"kind": "fp-fp",
"include": "task_watchdog.h"
},
{
"from": "Src/main.c",
"to": "Drivers/BSP/dbg_log.h",
@@ -39489,6 +39639,144 @@
"kind": "fp-fp",
"include": "sd2506_test.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdint.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdio.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "string.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdlib.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "Drivers/BSP/dbg_log.h",
"kind": "fp-fp",
"include": "dbg_log.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "App/cfg/cfg_file_store.h",
"kind": "fp-fp",
"include": "cfg_file_store.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "App/log/sys_log.h",
"kind": "fp-fp",
"include": "sys_log.h"
},
{
"from": "test/host/cfg_file/cfg_file_test.c",
"to": "App/cfg/cfg_file.c",
"kind": "fp-fp",
"include": "cfg_file.c"
},
{
"from": "test/host/cfg_file/stub/dbg_log.h",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdio.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdint.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdio.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "string.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "Inc/main.h",
"kind": "fp-fp",
"include": "main.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h",
"kind": "fp-tp",
"include": "FreeRTOS.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "Middlewares/Third_Party/FreeRTOS/Source/include/task.h",
"kind": "fp-tp",
"include": "task.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "Drivers/BSP/dbg_log.h",
"kind": "fp-fp",
"include": "dbg_log.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "Drivers/BSP/SD2506/sd2506.h",
"kind": "fp-fp",
"include": "sd2506.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "App/util/sys_clock.h",
"kind": "fp-fp",
"include": "sys_clock.h"
},
{
"from": "test/host/sys_clock/sys_clock_test.c",
"to": "App/util/sys_clock.c",
"kind": "fp-fp",
"include": "sys_clock.c"
},
{
"from": "test/host/sys_clock/stub/FreeRTOS.h",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdint.h"
},
{
"from": "test/host/sys_clock/stub/dbg_log.h",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdio.h"
},
{
"from": "test/host/sys_clock/stub/main.h",
"to": "外部/系统头文件",
"kind": "fp-ext",
"include": "stdint.h"
},
{
"from": "test/host/sys_clock/stub/task.h",
"to": "test/host/sys_clock/stub/FreeRTOS.h",
"kind": "fp-fp",
"include": "FreeRTOS.h"
},
{
"from": "test/host/watchdog/watchdog_test.c",
"to": "外部/系统头文件",
@@ -39565,6 +39853,9 @@
"App/cfg/cfg_file_store_mcu.c": [
"string.h"
],
"App/fs/vol_lock.h": [
"stdint.h"
],
"App/log/console_log.c": [
"stdio.h"
],
@@ -39599,6 +39890,9 @@
"App/util/sys_clock.h": [
"stdint.h"
],
"App/util/task_watchdog.c": [
"string.h"
],
"App/util/task_watchdog.h": [
"stdint.h"
],
@@ -41268,6 +41562,29 @@
"test/board/test_config.h": [
"stdint.h"
],
"test/host/cfg_file/cfg_file_test.c": [
"stdint.h",
"stdio.h",
"stdlib.h",
"string.h"
],
"test/host/cfg_file/stub/dbg_log.h": [
"stdio.h"
],
"test/host/sys_clock/stub/FreeRTOS.h": [
"stdint.h"
],
"test/host/sys_clock/stub/dbg_log.h": [
"stdio.h"
],
"test/host/sys_clock/stub/main.h": [
"stdint.h"
],
"test/host/sys_clock/sys_clock_test.c": [
"stdint.h",
"stdio.h",
"string.h"
],
"test/host/watchdog/stub/dbg_log.h": [
"stdio.h"
],
@@ -41283,11 +41600,11 @@
]
},
"stats": {
"files_indexed": 1411,
"includes_parsed": 5658,
"resolved": 4601,
"unresolved": 1057,
"nodes_fp": 138,
"files_indexed": 1420,
"includes_parsed": 5700,
"resolved": 4630,
"unresolved": 1070,
"nodes_fp": 147,
"nodes_tp": 1259,
"ext_names": 352
},
@@ -41309,6 +41626,7 @@
"App",
"App/app",
"App/cfg",
"App/fs",
"App/log",
"App/sync",
"App/task",
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 328 KiB

After

Width:  |  Height:  |  Size: 358 KiB

+20 -15
View File
@@ -29,7 +29,7 @@ digraph refgraph_module {
"其他(第三方)" [fillcolor="#f3f4f6", color="#9ca3af"];
"外部/系统头文件" [shape=ellipse, fillcolor="#fef3c7", color="#d97706"];
"App" -> "App/log" [color="#2563eb", penwidth=1.2, label="×2"];
"App" -> "App/util" [color="#2563eb", penwidth=1.2, label="×3"];
"App" -> "App/util" [color="#2563eb", penwidth=1.2, label="×4"];
"App" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×3"];
"App" -> "BSP/GD5F2GQ5UE" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×1"];
@@ -37,17 +37,17 @@ digraph refgraph_module {
"App" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "BSP/TPAFE5160" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×2"];
"App" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×3"];
"App" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×3"];
"App" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×7"];
"App/log" -> "App" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×8"];
"App/log" -> "App" [color="#2563eb", penwidth=1.2, label="×2"];
"App/log" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×4"];
"App/log" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×4"];
"App/task" -> "App" [color="#2563eb", penwidth=1.2, label="×4"];
"App/task" -> "App" [color="#2563eb", penwidth=1.2, label="×5"];
"App/task" -> "App/log" [color="#2563eb", penwidth=1.2, label="×2"];
"App/task" -> "App/util" [color="#2563eb", penwidth=1.2, label="×4"];
"App/task" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×5"];
@@ -63,11 +63,13 @@ digraph refgraph_module {
"App/task" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "test" [color="#2563eb", penwidth=1.2, label="×4"];
"App/task" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×2"];
"App/util" -> "App/log" [color="#2563eb", penwidth=1.2, label="×2"];
"App/util" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×2"];
"App/util" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×1"];
"App/util" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×2"];
"App/util" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×4"];
"App/util" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×3"];
"App/util" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×3"];
"App/util" -> "lftpd" [color="#2563eb", penwidth=1.2, label="×1"];
"App/util" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×4"];
"BSP(公共)" -> "App/log" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP(公共)" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP(公共)" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
@@ -89,6 +91,7 @@ digraph refgraph_module {
"BSP/NETCFG" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/NETCFG" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×3"];
"BSP/RS485" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/SD2506" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/SD2506" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/SD2506" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
"BSP/TPAFE5160" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
@@ -120,7 +123,7 @@ digraph refgraph_module {
"SDL2" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×36"];
"Src/Inc (CubeMX)" -> "App" [color="#2563eb", penwidth=1.2, label="×3"];
"Src/Inc (CubeMX)" -> "App/task" [color="#2563eb", penwidth=1.2, label="×2"];
"Src/Inc (CubeMX)" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "App/util" [color="#2563eb", penwidth=1.2, label="×3"];
"Src/Inc (CubeMX)" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×2"];
"Src/Inc (CubeMX)" -> "BSP/CH395F" [color="#2563eb", penwidth=1.2, label="×2"];
"Src/Inc (CubeMX)" -> "BSP/GD5F2GQ5UE" [color="#2563eb", penwidth=1.2, label="×1"];
@@ -135,6 +138,7 @@ digraph refgraph_module {
"Src/Inc (CubeMX)" -> "test" [color="#2563eb", penwidth=1.2, label="×3"];
"Src/Inc (CubeMX)" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×4"];
"dhara" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×5"];
"lftpd" -> "App" [color="#94a3b8", penwidth=0.7, label="×1"];
"lftpd" -> "BSP(公共)" [color="#94a3b8", penwidth=0.7, label="×4"];
"lftpd" -> "BSP/NET" [color="#94a3b8", penwidth=0.7, label="×3"];
"lftpd" -> "FatFs" [color="#94a3b8", penwidth=0.7, label="×2"];
@@ -149,16 +153,17 @@ digraph refgraph_module {
"simulator" -> "SDL2" [color="#2563eb", penwidth=1.2, label="×2"];
"simulator" -> "test" [color="#2563eb", penwidth=1.2, label="×1"];
"simulator" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×6"];
"test" -> "App" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "App" [color="#2563eb", penwidth=1.2, label="×3"];
"test" -> "App/log" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "App/task" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×8"];
"test" -> "App/util" [color="#2563eb", penwidth=1.2, label="×3"];
"test" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×10"];
"test" -> "BSP/CH395F" [color="#2563eb", penwidth=1.2, label="×2"];
"test" -> "BSP/GD5F2GQ5UE" [color="#2563eb", penwidth=1.2, label="×4"];
"test" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×5"];
"test" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×2"];
"test" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×3"];
"test" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×5"];
"test" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×4"];
"test" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×17"];
"test" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×7"];
"test" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×5"];
"test" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×23"];
}
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 101 KiB

+1 -1
View File
@@ -48,7 +48,7 @@ git commit
| scripts/check_cubemx_survival.py | 随仓库提交 | CubeMX 重生成存活审计(纯 Python,无依赖) |
| scripts/check_test_suite.py | 随仓库提交 | 测试套件开关门禁(纯 Python,无依赖) |
> **PATH 要求**:cppcheck 安装后需在系统 PATH 中(`C:\Program Files\Cppcheck`)。winget 自动写入 User PATH,但当前终端不会立即生效,需**重开终端**。
> **PATH 要求**:cppcheck 安装后需在 PATH 中可找到(winget 自动写入 User PATH,但当前终端不会立即生效,需**重开终端**);装在非 PATH 位置时可用 `DTU_CPPCHECK` 环境变量指向 `cppcheck.exe` 完整路径(显式设置但无效 → 硬报错,不静默回退)。
---
+1 -1
View File
@@ -15,7 +15,7 @@
结论:**没有现成成熟工具能直接输出"单一、整工程、可重跑更新"的文件引用关系图**,
故按"没有则自写"原则自写解析/建模工具;布局渲染这一难点交给成熟引擎 Graphviz。
本机已通过 winget 安装 Graphviz 16.1.0(`C:\Program Files\Graphviz`)。
本机已通过 winget 安装 Graphviz 16.1.0(安装后 `dot` 可从 **PATH** 找到;非标准安装位置用 `DTU_GRAPHVIZ_DOT` 指向 `dot.exe`,见 `docs/环境与部署/本地工具路径环境变量方案.md`)。
## 2. 生成 / 更新(一条命令)
@@ -1,7 +1,7 @@
# ST-LINK_CLI 复位使用说明(v3.5.0.0 本机实测版)
> 依据:本机 ST-LINK Utility 4.5.0.0 自带 `ST-LINK_CLI.exe`(CLI 版本 v3.5.0.0,`-h` 全文已实测核对)+ ST 官方文档语义。
> 探针路径:`C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe`
> 探针路径:经 `DTU_STLINK_CLI` 环境变量解析(本机设为标准安装位 `C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe`;未设时回退 PATH,`reset.bat` 均可用)
> 2026-09-19 已上板实测(ST-LINK/V2,FW V2J37S7,SN `0B250D12A218303030303032`;STM32F407ZGTx 目标,SWD)。
> 2026-09-20 复测(V0.1 板):烧写静默失败根因闭环、完整启动闭环(详见 §10)。
> ⚠️ **本机接线:3 根线(SWDIO / SWCLK / GND),nRST 未接** → 能力边界见 §0,实测记录见 §9。
+4 -4
View File
@@ -456,7 +456,7 @@ journal 整体回退到回绕之前 → **回绕之后写的一切(日志、
| A3 | 构建产物为**产品态** | 检查 `test/board/test_config.h` L30-33 | 四个 `TEST_SUITE_*` **全部注释** |
| A4 | `.map` 非测试态 | 看 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map` 的 `ER_IROM1` | 产品态基线**随已接受的修复增长**:2026-10-02 台架窗口实测 `0x000402B4` = **262,836 B**(初版基线 262,100 B + round 1~6 修复增量);明显阶跃到 ≈**266,540 B** = 停在套件态 → 重跑 A2 |
| A5 | 全量静态门禁 | `pre-commit run --all-files` | **16/16 Passed** |
| A6 | ST-LINK 探针可见 | `"C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe" -c SWD -List` | 列出探针 SN `0B250D12A218303030303032` |
| A6 | ST-LINK 探针可见 | `& "MDK-ARM\reset.bat" list`(CLI 经 `DTU_STLINK_CLI` / PATH 解析) | 列出探针 SN `0B250D12A218303030303032` |
| A7 | 串口端口正确 | 检查 `.opencode/serial_config.json` 的 `portName` | 与设备管理器一致(默认 COM7) |
| A8 | 串口助手 daemon 可用 | `& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py status` | 返回 JSON,`open: true/false` 可读 |
@@ -572,9 +572,9 @@ journal 整体回退到回绕之前 → **回绕之后写的一切(日志、
& "MDK-ARM\reset.bat" flash MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex
# 3) 抓串口日志,确认 [ERR] WATCHDOG task stall + 复位原因
# 4) 回读校验复位后镜像
"C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe" \
-c SWD -CmpFile MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex 0x08000000
# 4) 回读校验复位后镜像(ST-LINK_CLI 经 DTU_STLINK_CLI 解析,未设时回退 PATH,不写死路径)
$cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-LINK_CLI.exe).Source }
& $cli -c SWD -CmpFile MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex 0x08000000
# 判据:No difference found
# 5) 撤销注入,@build 回产品态,再跑一轮 @test 确认正常
@@ -556,7 +556,7 @@ CI 只在 push / PR 时跑,且需 runner 就绪。**提交前自查、或 runn
& '.venv\Scripts\python.exe' scripts/ci_local.py --l05-only # 只跑 L0.5
```
- **自动选用装了 pre-commit 的解释器**(本机 `pre-commit` 只装在 anaconda3,`.venv` 没有);
- **自动选用装了 pre-commit 的解释器**(优先级:`DTU_PRECOMMIT_PYTHON` 显式指定 → 当前解释器(重建 `.venv` 已自带 pre-commit)→ 仓库 `.venv` → PATH 的 `python`;显式值无效 → 硬报错并指明变量名,不静默回退);
仍不可用时退出码 2 并给出修复提示。
- **`.map` 自适应与 CI 完全一致**:本地有 `.map` 就照常跑 `mem-numbers`,没有就跳过。
- 退出码:`0` 通过 / `1` 门禁或单测失败 / `2` 环境错误。
+14 -13
View File
@@ -202,21 +202,22 @@ python -m pre_commit --version
### 3.2 MSVC 的路径要求(探测逻辑)
`l05-host-unit-tests` 的 MSVC 探测会去这些**固定根目录**找
`VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe`(与
`test/host/common/unit_test_harness.py` 的 `VS_ROOTS` 保持一致):
`l05-host-unit-tests` 的 MSVC 探测优先读机器级 `DTU_MSVC_CL`(x64 `cl.exe` 完整路径;
值无效 → 硬失败、不静默回退);未设置时按**标准布局自动探测**(根目录由
`%ProgramFiles` / `%ProgramFiles(x86)` 推导,不写死盘符;与
`test/host/common/unit_test_harness.py` 的 `_default_vs_roots()` 保持一致):
2019 → `Program Files (x86)`;2022 / 2026(实际目录名 `18`)→ `Program Files`,
各取 BuildTools/Community/Professional/Enterprise 子目录,找
`VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe`。
```
C:\Program Files (x86)\Microsoft Visual Studio\2019\{BuildTools,Community,Professional}
C:\Program Files\Microsoft Visual Studio\2022\{BuildTools,Community,Professional,Enterprise}
C:\Program Files\Microsoft Visual Studio\2026\{BuildTools,Community}
```
> ⚠️ **装在完全非标准位置(如 D 盘自定义目录)会探测不到** → 被当成"没装 MSVC"跳过 L0.5(仅告警)。
> 处置(二选一):设机器级 `DTU_MSVC_CL` 指向 `cl.exe`(推荐;值无效会硬报错),
> 或把 VS 装回标准位置(探测按 `%ProgramFiles*` 推导,换盘符的标准布局仍命中)。
>
> Windows SDK 同理:默认 `<ProgramFiles(x86)>\Windows Kits\10\`;非标准位置用 `DTU_WINDOWS_KITS_ROOT` 指定。
> ⚠️ **装在非默认路径(如 D 盘)会探测不到** → 被当成"没装 MSVC"直接跳过 L0.5。
> 要么用默认路径,要么同步改 `unit_test_harness.py` 的 `VS_ROOTS` **和** workflow
> 里的 `$roots`(两处必须一致,否则本地能跑、CI 跳过)。
Windows SDK 同理,默认在 `C:\Program Files (x86)\Windows Kits\10\`。
> 📌 2026-10-02:workflow 与本地 harness 同步改为"变量优先 + 标准布局推导"
> (`本地工具路径环境变量方案.md`)——旧写法要求"同步改两处",现已不需要。
---
@@ -447,6 +447,10 @@ Start-ScheduledTask -TaskName GiteaActionsRunner
C:\ProgramData\anaconda3\python.exe
```
> 📌 上为 2026-10-02 的历史报错原文。workflow 现已改为
> **`DTU_PRECOMMIT_PYTHON`(机器级)→ PATH 的 `python` → 工作区 `.venv`** 顺序(§5.1.3),
> 且报错行会指明是变量无效还是自动发现落空。
**根因(两层)**:
1. **用户态 site-packages 对 SYSTEM 不可见**。
@@ -540,23 +544,47 @@ mv tools/serial_tool/state.bak_ci tools/serial_tool/state
> 更一般的教训:**任何校验"文件是否存在/数字是否一致"的钩子,都要在
> "无本地产物"的干净克隆里验一次**,别只在开发机上跑。
### 5.2 ⚠️ 关键坑:MSVC 的路径必须"标准"
CI 的 MSVC 探测(`l05` job)会去这几个**固定根目录**找
`VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe`:
### 5.1.3 机器级 `DTU_*` 环境变量(runner 的正式覆盖通道,2026-10-02 起)
workflow 已改为统一消费 `DTU_*` 接口(见 `本地工具路径环境变量方案.md` §5.3):
**显式变量优先 → 自动发现回退**,三个 job 步骤相关的变量:
| 变量 | 作用 | 未设置时的回退 |
|---|---|---|
| `DTU_PRECOMMIT_PYTHON` | 指向装有 pre-commit 的 python.exe(L0/L0.5 用) | PATH 的 `python` → 工作区 `.venv`(干净克隆里通常没有) |
| `DTU_CPPCHECK` | 指向 cppcheck.exe(L0 钩子用) | SYSTEM 的 PATH(用户级 PATH 不可见) |
| `DTU_MSVC_CL` | 指向 x64 `cl.exe`(L0.5 用) | `%ProgramFiles%`/`%ProgramFiles(x86)%` 推导的 VS 标准根自动探测 |
设置(**必须管理员**;scope 用 `Machine` 才能被 SYSTEM 任务看到):
```powershell
[Environment]::SetEnvironmentVariable('DTU_PRECOMMIT_PYTHON', 'C:\ProgramData\anaconda3\python.exe', 'Machine') # 示例:本机 runner
[Environment]::SetEnvironmentVariable('DTU_CPPCHECK', 'C:\Program Files\Cppcheck\cppcheck.exe', 'Machine')
[Environment]::SetEnvironmentVariable('DTU_MSVC_CL', 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe', 'Machine')
# ★ 设完必须重启 runner 任务(环境块是任务启动时快照的)
Stop-ScheduledTask -TaskName GiteaActionsRunner
Start-ScheduledTask -TaskName GiteaActionsRunner
```
C:\Program Files (x86)\Microsoft Visual Studio\2019\{BuildTools,Community,Professional}
C:\Program Files\Microsoft Visual Studio\2022\{BuildTools,Community,Professional,Enterprise}
C:\Program Files\Microsoft Visual Studio\2026\{BuildTools,Community}
```
> 与 §5.1.1 的关系:机器级 `DTU_PRECOMMIT_PYTHON` 是**正式通道**(指向哪个解释器由你说了算,
> 值无效时 job 直接报变量名、不猜);"把 pre-commit 装进全局 site-packages"仍是**兜底**
> (变量未设 + 全局 site 可见也能过)。两条路并存不冲突:变量设了就用变量,没设走探测。
> 显式变量值无效(文件不存在 / 无 pre-commit 模块)→ job **硬失败**并指明变量名——**不会**
> 静默回退到别的解释器,避免 runner 悄悄换了 Python 导致钩子行为漂移。
### 5.2 ⚠️ 关键坑:MSVC 的路径必须"标准"(或显式给变量)
CI 的 MSVC 探测(`l05` job)优先读机器级 `DTU_MSVC_CL`(§5.1.3);
未设置时按**标准布局自动探测**(根目录由 `%ProgramFiles` / `%ProgramFiles(x86)` 推导,
不再写死盘符):2019 → `Program Files (x86)`;2022 / 2026(实际目录名 `18`)→ `Program Files`,
各取 BuildTools/Community/Professional/Enterprise 子目录,找
`VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe`。本地 `unit_test_harness.py` 用同一套推导(已同步)。
**你本机实测命中第 1 条**:
`C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe` ✅
> ⚠️ 若将来 MSVC 装到 **D 盘或非上述路径** → 探测不到 → **L0.5 被静默跳过**(只告警)。
> 修法要**同步改两处**(否则本地能跑、CI 跳过):
> - `test/host/common/unit_test_harness.py` 的 `VS_ROOTS`
> - `.gitea/workflows/ci.yml` 里 `探测 MSVC` 步骤的 `$roots`
> ⚠️ 若将来 MSVC 装到 **D 盘或完全非标准路径** → 自动探测不到 → 两种处置(二选一):
> - 设机器级 `DTU_MSVC_CL` 指向 `cl.exe`(**推荐**,不动任何代码;值无效会硬报错、不静默跳过)
> - 或把 VS 装回标准根(探测逻辑按 `%ProgramFiles*` 推导,换盘符的标准布局仍命中)
### 5.3 验证运行器能找到工具链(注册前先跑一遍)
@@ -633,7 +661,7 @@ date +%s # 对比 last_online
| 🔴 `l0-gates` 报 `no Python with a SYSTEM-visible pre-commit` | `pre-commit` 只装在**用户态** site-packages(SYSTEM 不可见);或 pip 因 user-site 已满足而**静默跳过**全局安装 | 提权装到**全局**(§5.1.1),务必用 `-s` 复验 |
| `l0-gates` 报 `TerminatorExpectedAtEndOfString` / 缺少右引号 | `run:` 块含**中文**,被 WinPS 5.1 按 GBK 解码撞坏引号 | `run:` 块改**纯 ASCII**(中文只留 `name:`/注释) |
| `l0-gates` 报 `Cannot find: pwsh in PATH` | `shell: pwsh` = PS7,本机只有 WinPS 5.1 | 改 `shell: powershell` |
| `l0-gates` 报 `runner missing: cppcheck` | cppcheck 仅在用户级 PATH | workflow 内回落到 `C:\Program Files\Cppcheck` |
| `l0-gates` 报 `runner missing: cppcheck` | cppcheck 仅在用户级 PATH(SYSTEM 不可见) | 设机器级 `DTU_CPPCHECK`(§5.1.3,**workflow 不再回落固定目录**),或把 cppcheck 目录加入系统 PATH 后重启任务 |
| 🔴 `doc-links` 钩子本地过、CI 挂 | 引用了 **gitignore 的运行时文件**(如 `tools/serial_tool/state/*.json`),本地存在、干净克隆里没有 | 该行加状态词「未创建/不存在」等(§5.1.2) |
| `l05` 日志 `::warning::runner has no MSVC` 但仍 **PASS** | 缺 MSVC 时 L0.5 **降级跳过**(不硬失败) | 装 VS BuildTools(§5.2),否则该层无覆盖 |
| 任务跑满 72 小时被杀 | 计划任务默认 `ExecutionTimeLimit` | 设为 `0`(不限时长),见 §4.3 警示 |
@@ -769,28 +797,41 @@ $pc = (python -m pre_commit --version 2>&1)
if ($LASTEXITCODE -eq 0) { Write-Host " OK $pc" -ForegroundColor Green }
else { Write-Host " FAIL 缺 pre-commit" -ForegroundColor Red }
Write-Host "=== MSVC cl.exe ===" -ForegroundColor Cyan
$roots = @(
'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools',
'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community',
'C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional',
'C:\Program Files\Microsoft Visual Studio\2022\BuildTools',
'C:\Program Files\Microsoft Visual Studio\2022\Community',
'C:\Program Files\Microsoft Visual Studio\2022\Professional',
'C:\Program Files\Microsoft Visual Studio\2022\Enterprise',
'C:\Program Files\Microsoft Visual Studio\2026\BuildTools',
'C:\Program Files\Microsoft Visual Studio\2026\Community'
)
$hit = $null
foreach ($r in $roots) {
if (Test-Path $r) {
$hit = Get-ChildItem -Path $r -Recurse -Filter 'cl.exe' -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -like '*Hostx64\x64*' } | Select-Object -First 1
if ($hit) { break }
Write-Host "=== DTU_* 机器级变量(§5.1.3)===" -ForegroundColor Cyan
foreach ($n in @("DTU_PRECOMMIT_PYTHON", "DTU_CPPCHECK", "DTU_MSVC_CL")) {
$v = [Environment]::GetEnvironmentVariable($n, "Machine")
if ($v) { Write-Host " OK $n = $v" -ForegroundColor Green }
else { Write-Host " -- $n(未设置:workflow 将走自动发现)" -ForegroundColor Yellow }
}
Write-Host "=== MSVC cl.exe(DTU_MSVC_CL 优先,否则标准布局推导)===" -ForegroundColor Cyan
if ($env:DTU_MSVC_CL -and (Test-Path $env:DTU_MSVC_CL)) {
Write-Host " OK $($env:DTU_MSVC_CL)(来自 DTU_MSVC_CL)" -ForegroundColor Green
} else {
$pf = ${env:ProgramFiles}
$pf86 = ${env:ProgramFiles(x86)}
$roots = @(
(Join-Path $pf86 'Microsoft Visual Studio\2019\BuildTools'),
(Join-Path $pf86 'Microsoft Visual Studio\2019\Community'),
(Join-Path $pf86 'Microsoft Visual Studio\2019\Professional'),
(Join-Path $pf 'Microsoft Visual Studio\2022\BuildTools'),
(Join-Path $pf 'Microsoft Visual Studio\2022\Community'),
(Join-Path $pf 'Microsoft Visual Studio\2022\Professional'),
(Join-Path $pf 'Microsoft Visual Studio\2022\Enterprise'),
(Join-Path $pf 'Microsoft Visual Studio\18\BuildTools'),
(Join-Path $pf 'Microsoft Visual Studio\18\Community')
)
$hit = $null
foreach ($r in $roots) {
if (Test-Path $r) {
$hit = Get-ChildItem -Path $r -Recurse -Filter 'cl.exe' -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -like '*Hostx64\x64*' } | Select-Object -First 1
if ($hit) { break }
}
}
if ($hit) { Write-Host " OK $($hit.FullName)" -ForegroundColor Green }
else { Write-Host " FAIL 未找到 MSVC (Hostx64\x64\cl.exe);可设机器级 DTU_MSVC_CL" -ForegroundColor Red }
}
if ($hit) { Write-Host " OK $($hit.FullName)" -ForegroundColor Green }
else { Write-Host " FAIL 未找到 MSVC (Hostx64\x64\cl.exe)" -ForegroundColor Red }
```
---
@@ -830,6 +871,13 @@ powershell -ExecutionPolicy Bypass -File "D:\Docker\act_runner\install_precommit
# 若有包报"安装成功"但 import 失败(pip 静默跳过):
powershell -ExecutionPolicy Bypass -File "D:\Docker\act_runner\fix_cfgv_global.ps1"
# 5b) 2026-10-02 起推荐:改设机器级 DTU_* 变量(§5.1.3,显式覆盖、报错直指变量名);
# 全局 site-packages 安装保留为未设变量时的兜底。设完同样要重启 runner 任务。
# (管理员 PowerShell;值按本机实际路径改)
# [Environment]::SetEnvironmentVariable('DTU_PRECOMMIT_PYTHON', 'C:\ProgramData\anaconda3\python.exe', 'Machine')
# [Environment]::SetEnvironmentVariable('DTU_CPPCHECK', 'C:\Program Files\Cppcheck\cppcheck.exe', 'Machine')
# [Environment]::SetEnvironmentVariable('DTU_MSVC_CL', '<本机 x64 cl.exe 完整路径>', 'Machine')
# 6) 复验(-s = 模拟 SYSTEM 视角,必须过)
& 'C:\ProgramData\anaconda3\python.exe' -s -m pre_commit --version # pre-commit 4.6.2
@@ -861,6 +909,7 @@ powershell -ExecutionPolicy Bypass -File "D:\Docker\act_runner\fix_cfgv_global.p
| 日期 | 变更 |
|---|---|
| 2026-10-02 | **workflow 接入 `DTU_*` 机器级变量**(`本地工具路径环境变量方案.md` 实施):`l0-gates` 的 Python 探测改为 `DTU_PRECOMMIT_PYTHON`(显式,无效即硬失败)→ PATH → `.venv`(删除 `C:\ProgramData\anaconda3` 固定候选);cppcheck 改为 `DTU_CPPCHECK` 优先 → PATH(**移除 `C:\Program Files\Cppcheck` 固定回退**);`l05` 的 MSVC 探测改为 `DTU_MSVC_CL` 优先 → `%ProgramFiles*` 推导的标准根(与 `unit_test_harness.py` 同步,不再写死盘符);新增 §5.1.3 机器级变量设置方法(`Machine` scope + 重启任务)、§5.2 与 check_env 样例、排障表 cppcheck 行、TL;DR 5b 步骤。§5.1.1 的报错原文标注为历史记录 |
| 2026-10-02 | ✅ **首次 CI 全绿(run#8:L0 + L0.5 双 job Success)**。定位并修复最后两个拦路虎:① **§5.1.1 用户态 site-packages 陷阱**——`pre-commit` 只装在 `%APPDATA%\Roaming\Python\...`(SYSTEM 不可见);且提权 `pip install --no-user` 会因 pip 扫**整个 `sys.path`**、见 user-site 已满足而**静默跳过**全局安装(9 依赖中唯 `cfgv` 因版本相同被跳过→`-s` 下 `ModuleNotFoundError`)。修法:提权 + `--force-reinstall --no-deps` 强制落全局,并以 `-s` 复验。② **§5.1.2 doc-links 假阳性**——文档引用了 gitignore 的运行时文件 `tools/serial_tool/state/meta.json`,本地存在、干净克隆无 → 按《文档规范》§3.3 加同状态词「运行时未创建」。排障表补 6 条(pre-commit 不可见 / GBK 中文 / pwsh / cppcheck / doc-links / MSVC 降级)。新增配套脚本 `install_precommit_global.ps1`、`install_precommit_global2.ps1`、`fix_cfgv_global.ps1` |
| 2026-10-02 | 🔴 **常驻方式重大修正(实测推翻)**:`Start-Service gitea-runner` 必然失败。经二进制逆向确认 `gitea-runner v4.0.1` **无任何服务管理代码**(命令集仅 `bug-report/cache-server/config/daemon/exec/register`,无 `service.go`;`OpenSCManagerW` 等符号来自 Docker SDK,非服务安装代码),`daemon` 是纯控制台程序、不向 SCM 回报 `SERVICE_RUNNING`。**§4 全节重写为「任务计划程序」方案**(新增 §4.0 根因分析、§4.2 `deploy_runner_task.ps1`、§4.3 手动命令 + 72h 超时警示、§4.5 清理遗留服务、§4.6 提权);删除失效的 `deploy_runner.ps1`/`install_service.ps1`;排障表补「错误 1053」「LastTaskResult 非 0」「72 小时被杀」3 条;拓扑图/§5.1/§7 日志/§10 TL;DR 同步更新。另修 `config.yaml` 的 `fetch_timeout` 5m→1m(超出 RPC 1m 会被截断并告警) |
| 2026-10-02 | **修 `.ps1` 编码坑(实测)**:无 BOM 的 UTF-8 脚本被 WinPS 5.1 按 GBK 解读 → 中文乱码(`鐒跺悗鎵ц`)并撞坏引号配对,报 `源文本中包含无法识别的标记`/`字符串缺少终止符`。**新增 §7.1「给含中文的 `.ps1` 加 UTF-8 BOM」**(两种修法 + 解析器校验命令);排障表补该条目;配套脚本已统一加 BOM |
@@ -0,0 +1,182 @@
# 本地工具路径环境变量方案
> **状态**:**已实施**(2026-10-02,见文末变更记录)。仓库脚本已全部改为 `DTU_*` 变量解析,
> 本机已按 §5 配置并全链路验证(`@build` 0/0、`ci_local.py` L0+L0.5 全绿、refgraph 重生成、
> ST-LINK 探针识别);文档示例已同步改为变量口径。
> **目标**:同一份仓库代码可在不同 Windows 用户、磁盘和工具安装目录下工作,不再要求把 Keil、ST-LINK、Python、Visual Studio、Windows SDK、Graphviz、Cppcheck 安装到某台机器的固定绝对路径。
> **约束**:只用进程/用户/CI 服务环境变量配置本机差异;不提交本机路径,不引入 `.env`/`python-dotenv`,不把个人工具路径写入共享 workflow;仓库内部路径继续相对脚本/仓库根解析。
---
## 1. 设计结论
采用统一的 `DTU_` 前缀和**可执行文件/工具根目录的绝对路径变量**。调用端遵循:
```text
调用参数(如果已有)
  → 对应 DTU_* 环境变量(显式配置时严格使用;路径无效则报错)
  → PATH / Windows 安装发现(仅适合支持自动发现的工具)
  → 给出包含变量名与设置方式的清晰错误
```
关键决策:
1. **路径因机器而异的工具**才配置变量;Windows 自带目录优先由 `%WINDIR%`、`%ProgramFiles%` 等系统变量推导。
2. **显式变量有最高优先级**。变量已设置但文件不存在时应报错,不可悄悄回退到另一版本/另一安装路径,否则容易构建或运行错工具。
3. Keil 与 ST-LINK 属必需工具,最终要求通过变量显式指定;不保留 `C:\Keil_v5` 或 `C:\Program Files (x86)\...` 这类机器默认值作为永久兜底。
4. 可从 PATH 或官方探测器可靠发现的工具(如 `cppcheck`、`dot`、Visual Studio)允许自动发现;变量用于覆盖非标准安装位置。
5. 本地开发者变量与 Gitea runner 服务变量分开管理。runner 当前以 **SYSTEM** 运行,普通开发者的用户级变量不会自动传给它。
6. 该方案仅配置“工具地址”,不改变工具版本、Keil 工程、下载参数、串口端口或产品代码。
---
## 2. 当前路径耦合盘点
下表区分**脚本运行时实际硬编码**和仅存在于说明/注释里的机器示例。实施时先处理运行时路径,文档示例随后同步。
| 工具/路径 | 当前耦合点 | 影响 | 目标变量/策略 |
|---|---|---|---|
| Keil UV4 | `MDK-ARM/build.bat`、`MDK-ARM/download.bat` 写死 `C:\Keil_v5\UV4\UV4.exe`;`MDK-ARM/_build.cmd` 也有同一路径 | 更换盘符/Keil 安装目录后构建、下载失败 | `DTU_KEIL_UV4`:UV4.exe 完整路径;显式配置,无永久 C 盘兜底 |
| ST-LINK CLI | `MDK-ARM/reset.bat` 写死 ST-LINK Utility 下的 CLI 完整路径 | 不同 Utility 版本/安装目录下复位、烧录、回读命令失败 | `DTU_STLINK_CLI`:`ST-LINK_CLI.exe` 完整路径 |
| Python(pre-commit 环境) | `scripts/ci_local.py`、`.gitea/workflows/ci.yml` 在候选列表中写死 `C:\ProgramData\anaconda3\python.exe` | Python 发行版、用户目录、CI 运行账户改变后路径失效 | `DTU_PRECOMMIT_PYTHON`:含 `pre_commit` 模块的 Python 完整路径;其余优先尝试当前解释器、仓库 `.venv`、PATH |
| Graphviz | `tools/refgraph/gen_refgraph.py` 在 PATH 检查后枚举两个 `C:\Program Files...\dot.exe` | 非默认安装目录无法渲染图 | `DTU_GRAPHVIZ_DOT`:`dot.exe` 完整路径;未设时只从 PATH 查找,允许按当前工具语义跳过渲染 |
| MSVC `cl.exe` | `test/host/common/unit_test_harness.py` 和 CI workflow 分别维护 VS2019/2022/2026 安装根列表 | 自定义 VS 目录/只安装特定 edition 时主机单测漏检工具链 | `DTU_MSVC_CL`:x64 `cl.exe` 完整路径;保留版本 glob/自动探测作未配置时回退 |
| Windows SDK | `unit_test_harness.py` 写死 `C:\Program Files (x86)\Windows Kits\10` | Windows 安装目录不在默认盘时找不到 include/lib | `DTU_WINDOWS_KITS_ROOT`:`Windows Kits\10` 根目录;未设置则从系统注册信息/已知 SDK 位置自动发现 |
| Visual Studio 定位器 | `simulator/build_sim.ps1` 已读 `%ProgramFiles(x86)%`,但仍有 `C:\Program Files (x86)` 字面回退,并据此拼 `vswhere.exe` | 非默认 Program Files 目录或自定义 installer 布局下 VS 探测失败 | `DTU_VSWHERE`:`vswhere.exe` 完整路径;未设时由 `%ProgramFiles(x86)%` 推导并清晰失败,不保留固定 C 盘值 |
| Cppcheck(CI) | `.gitea/workflows/ci.yml` 有 PATH 探测,但回退到 `C:\Program Files\Cppcheck\cppcheck.exe` | runner 安装位置不同会导致 L0 job 失败 | `DTU_CPPCHECK`:`cppcheck.exe` 完整路径;优先变量,未设时 `Get-Command`/PATH |
| 字体系统目录 | `tools/font_gen/make_font.py` 默认字体写死 `C:\Windows\Fonts\simsun.ttc` | Windows 非 C 盘系统目录时默认字体定位失败 | 不另设 DTU 变量:改由 `%WINDIR%\Fonts\simsun.ttc` 推导;现有 `--font` 参数仍优先 |
| 工程/构建产物 | `.bat` 中 `%~dp0`、Python 中 `Path(__file__)` 解析的 `.uvprojx`、HEX、日志、仓库文件路径 | 不是本机工具安装路径 | **保持原样**,不可错误改成 DTU 变量 |
> `MDK-ARM/_build.cmd` 已在实施时确认**全库无调用者**(仅本文档提及),按"优先删除/退役"执行:2026-10-02 已删除。
### 2.1 不纳入首轮的项目
- `cmake`、`node`、`npm`、`lv_font_conv`、`pre-commit` 命令本身已有 PATH/项目环境解析;除非后续发现非标准安装确实需要路径覆盖,不再各造一组变量。
- `simulator/build_sim.ps1` 的生成器和版本选择已通过 `vswhere` 探测,不应改成固定某个 VS 版本目录。
- `.gitea/workflows/ci.yml` 内 Windows PowerShell 的系统路径/runner workspace 路径属于运行平台接口或 workflow 工作目录,不是开发机工具安装目录。
- `C:\ProgramData\anaconda3` 的 README/文档示例、Keil/ST-LINK 文档示例及 `AGENTS.md` 中路径说明,不是脚本解析逻辑,但实施完成后必须逐项改成环境变量示例,避免读者继续复制硬编码路径。
---
## 3. 建议变量清单与语义
| 变量 | 必需性 | 值的形态 | 使用者 | 默认/回退 |
|---|---|---|---|---|
| `DTU_KEIL_UV4` | MCU 构建/Keil 下载机必需 | UV4.exe 完整路径,例如 `D:\Tools\Keil\UV4\UV4.exe` | `build.bat`、`download.bat`、`_build.cmd`(若保留) | 不设即报错;不从 C 盘旧路径猜测 |
| `DTU_STLINK_CLI` | 使用 ST-LINK CLI 的机器必需 | `ST-LINK_CLI.exe` 完整路径 | `reset.bat` 及回读/烧录调用入口 | 未设可尝试 `where ST-LINK_CLI.exe`;找不到即报错 |
| `DTU_PRECOMMIT_PYTHON` | 有多个 Python 且 pre-commit 不在当前解释器时建议设置;CI runner 建议必设 | `python.exe` 完整路径,且必须能成功执行 `-m pre_commit --version` | `scripts/ci_local.py`、CI L0/L0.5 Python 选择 | 当前解释器 → 仓库 `.venv` → PATH `python`;删除 Anaconda 固定路径 |
| `DTU_GRAPHVIZ_DOT` | 可选 | `dot.exe` 完整路径 | `tools/refgraph/gen_refgraph.py` | PATH `dot`;找不到时保持现有“只生成 .dot、不渲染”的可降级语义 |
| `DTU_MSVC_CL` | 可选;本地 L0.5/CI L0.5 要运行时需可发现 | x64 `cl.exe` 完整路径 | `test/host/common/unit_test_harness.py`、CI 环境预检 | 未设时使用 VS 自动探测;不能把 x86 `cl.exe` 误作目标 |
| `DTU_WINDOWS_KITS_ROOT` | 可选;主机侧 C 单测依赖 Windows SDK 时需发现 | `Windows Kits\10` 根目录(不是某一版本 Include 子目录) | `unit_test_harness.py`、CI 探测 | 未设时从系统变量/注册表或 `%ProgramFiles(x86)%` 推导默认安装根 |
| `DTU_VSWHERE` | 可选 | `vswhere.exe` 完整路径 | `simulator/build_sim.ps1`、如需则 CI | 未设时按 `%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe` 查找 |
| `DTU_CPPCHECK` | 可选;无 PATH 的 CI runner 建议设置 | `cppcheck.exe` 完整路径 | `.gitea/workflows/ci.yml` 预检;若需供 pre-commit 直接调用则同时把其目录加入 PATH | 未设时 `Get-Command cppcheck` / PATH;找不到即失败 |
**变量值只存路径本身**,不要在环境变量值外层包含引号。例如变量值是 `D:\Tools\Keil MDK\UV4\UV4.exe`,调用方负责在命令行中加引号。
### 3.1 Python 优先级特别说明
`DTU_PRECOMMIT_PYTHON` 表示“装有 pre-commit 的解释器”,不是项目默认 Python,也不替代仓库 `.venv`:
1. 若显式设置该变量,先检查文件存在并验证 `-m pre_commit --version`;**无效就报配置错误**,不静默使用别的解释器。
2. 未设置时依次探测调用脚本的 `sys.executable`、仓库 `.venv\Scripts\python.exe`、PATH 中 Python。
3. 不再写死 Anaconda 路径;需要使用 Anaconda 的机器通过变量显式指定它。
4. 字体等依赖项目 requirements 的脚本仍使用 `.venv\Scripts\python.exe`;不要让机器级变量覆盖该项目环境。
---
## 4. 解析与失败语义
所有调用端按同一原则实现,减少 BAT、Python、PowerShell 三种逻辑相互不一致:
### 4.1 显式值校验
- 环境变量不存在/空白:走该工具允许的 PATH 或系统发现逻辑。
- 环境变量非空:去除外围空格后按**字面路径**读取;先检查文件/目录类型是否正确。
- 显式路径不存在、不是预期工具或执行版本检查失败:输出 `ENV_ERROR`,指出变量名、收到的路径和示例设置方式,返回非零;**不得悄悄回退**。
- 可选工具 Graphviz 例外:变量未设且 PATH 未命中时,可按现状降级“不渲染”;但变量显式设置错误仍应报错,避免用户以为覆盖配置已生效。
### 4.2 Windows 命令行要求
- BAT 用 `set "NAME=value"` 设置局部变量、用 `"%NAME%"` 调用带空格路径的 exe。
- PowerShell 通过 `$env:DTU_...` 读取;调用 exe 用 `& $exePath ...`。
- Python 通过 `os.environ.get("DTU_...")` 读取,命令参数保持 list 传给 `subprocess.run`,不要拼 shell 字符串。
- 环境变量中不包引号;对空值、前后空格、相对路径的处理要统一。建议要求工具路径使用**绝对路径**,减少当前工作目录依赖。
- 变量名大小写按 `DTU_UPPER_SNAKE_CASE`;Windows 对环境变量名大小写不敏感。
---
## 5. 本机如何配置
### 5.1 当前 PowerShell 会话(即时生效,适合试配)
```powershell
$env:DTU_KEIL_UV4 = 'D:\Tools\Keil\UV4\UV4.exe'
$env:DTU_STLINK_CLI = 'D:\Tools\STLink\ST-LINK_CLI.exe'
$env:DTU_PRECOMMIT_PYTHON = 'D:\Python\python.exe'
$env:DTU_GRAPHVIZ_DOT = 'D:\Tools\Graphviz\bin\dot.exe'
$env:DTU_MSVC_CL = 'D:\VS\VC\Tools\MSVC\<版本>\bin\Hostx64\x64\cl.exe'
$env:DTU_WINDOWS_KITS_ROOT = 'D:\Windows Kits\10'
$env:DTU_VSWHERE = 'D:\VS Installer\vswhere.exe'
$env:DTU_CPPCHECK = 'D:\Tools\Cppcheck\cppcheck.exe'
```
设置后仅影响**当前 PowerShell 及其子进程**。批处理、Python、CI job 都继承该环境(但已启动的进程不会自动刷新)。
### 5.2 用户级永久配置(开发者日常机)
建议先在当前会话试跑验证,再写用户级变量:
```powershell
[Environment]::SetEnvironmentVariable('DTU_KEIL_UV4', 'D:\Tools\Keil\UV4\UV4.exe', 'User')
[Environment]::SetEnvironmentVariable('DTU_STLINK_CLI', 'D:\Tools\STLink\ST-LINK_CLI.exe', 'User')
[Environment]::SetEnvironmentVariable('DTU_PRECOMMIT_PYTHON', 'D:\Python\python.exe', 'User')
```
其他可选变量按实际使用补充。写入用户级变量后,**关闭并重新打开终端/IDE**再验证;无需管理员权限,也不建议把开发工具路径写进系统级 PATH。
验证例:
```powershell
$env:DTU_KEIL_UV4
Test-Path -LiteralPath $env:DTU_KEIL_UV4
& $env:DTU_KEIL_UV4 -?
```
如 `DTU_PRECOMMIT_PYTHON` 已配置,再验证:
```powershell
& $env:DTU_PRECOMMIT_PYTHON -m pre_commit --version
```
### 5.3 Gitea Windows runner(SYSTEM 服务)
当前 workflow 的 runner 以 **SYSTEM** 身份运行。开发者的用户级变量对该服务不可见;不能只在登录账号里执行 `setx` 后就假定 CI 会读取。
建议顺序:
1. 在 runner 主机用**管理员权限**设置机器级环境变量,或在服务启动配置中注入变量;只为 CI 所需工具配置 `DTU_PRECOMMIT_PYTHON`、`DTU_CPPCHECK`、`DTU_MSVC_CL`、`DTU_WINDOWS_KITS_ROOT`。
2. 重启 runner 服务,使服务进程继承新环境;不把个人开发机的 Keil/ST-LINK 路径放入共享 workflow。
3. workflow 的 PowerShell 环境自检打印变量是否设置、目标文件是否存在、工具版本;**避免打印整份环境变量**。
4. CI runner 路径不同于开发机是预期情况;workflow 只消费 `DTU_*` 接口及 PATH,不写任何特定用户目录或固定盘符。
> 安全:这些变量是路径而不是凭据。不得在变量中存放 token、密码或私钥;CI 日志只打印工具路径和版本,不输出无关环境变量。
---
## 6. 代码改造映射(2026-10-02 已实施完毕)
| 顺序 | 文件 | 计划改造 | 验证方式 |
|---|---|---|---|
| 1 | `MDK-ARM/build.bat` | 用 `DTU_KEIL_UV4` 替换绝对路径;缺失/无效时给设置提示;UV4 单实例警告和 build log 判据保持不变 | 未设置变量时明确失败;有效路径下 `@build` 0/0;路径含空格测试 |
| 2 | `MDK-ARM/download.bat` | 同一变量调用 UV4;保留项目/日志目录的 `%~dp0` 相对定位 | 不烧录的预检可单测;有 MCU 后才允许验证下载功能 |
| 3 | `MDK-ARM/reset.bat` | `DTU_STLINK_CLI` 替代写死地址;保留 `-Rst -Run` 等已验证参数与现有命令行为 | `list`/帮助命令和缺路径负测;烧录/复位须在用户明确要求且有实机后测 |
| 4 | `MDK-ARM/_build.cmd` | 确认是否仍使用;保留则改用 `DTU_KEIL_UV4` 或转调 `build.bat`,否则退役 | 全库搜索确认无其他调用者 → **已确认零调用,文件已删除** |
| 5 | `scripts/ci_local.py` | `_resolve_python()` 接受 `DTU_PRECOMMIT_PYTHON`;删除 Anaconda 硬编码候选及过时提示;验证显式值可用 | 设置有效/无效/未设置变量三组测试;`ci_local.py --l0-only` |
| 6 | `.gitea/workflows/ci.yml` | Python 和 cppcheck 使用 runner 环境变量优先 + PATH 发现;删除 Anaconda/Cppcheck 固定目录;L0.5 与 Python 探测顺序同步 | CI runner SYSTEM 环境预检;L0、L0.5 job 全绿 |
| 7 | `tools/refgraph/gen_refgraph.py` | `DTU_GRAPHVIZ_DOT` 优先,其次 `shutil.which("dot")`;移除两条固定 Graphviz 路径 | 临时变量有效/无效/不设置三态;无 dot 时 `.dot` 仍产出 |
| 8 | `test/host/common/unit_test_harness.py` | 优先采用 `DTU_MSVC_CL` 和 `DTU_WINDOWS_KITS_ROOT`;未设置时由 VS/SDK 发现逻辑取代静态盘符列表 | 当前 MSVC、定制安装路径、缺工具三类环境测试;现有 L0.5 全部通过 |
| 9 | `simulator/build_sim.ps1` | 允许 `DTU_VSWHERE` 覆盖;默认用 `%ProgramFiles(x86)%` 推导,不写死 `C:\Program Files (x86)` | 定制路径与标准安装路径探测;模拟器构建通过 |
| 10 | `tools/font_gen/make_font.py` | 默认字体根改成 `WINDIR` 环境值;保留 `--font` 显式覆写 | Windows 系统盘非 C 盘模拟/路径不存在提示;字体生成回归 |
| 11 | `AGENTS.md`、`MDK-ARM/README.md`、环境部署/工具说明 | 把实际路径示例改成变量名和配置步骤;注明改造已完成/仍待完成,避免旧说明与行为冲突 | `doc-links`、机器路径扫描、全量 pre-commit |
> 工作流中的运行块要求纯 ASCII(Windows PowerShell 5.1 编码约束);改 `.gitea/workflows/ci.yml` 时保持该约束。
---
## 7. 分阶段落地与验收
### 阶段 A:只读盘点与变量契约冻结
- 确认 `MDK-ARM/_build.cmd` 的调用关系;全库搜索绝对工具路径和对应的文档说明。
- 冻结 §3 变量名、值格式、必选/可选语义;确认 runner SYSTEM 账户能读到所需变量。
- 输出仅变更文件清单,不改工具行为前先做 review。
**出口**:工具路径没有遗漏;变量不与系统/其他项目冲突;明确每个变量由开发者、系统管理员或 runner 管理员配置。
### 阶段 B:调用端解析器与本地验证
- 先改 BAT/Python/PowerShell 的路径读取,显式错误路径要 fail-fast。
- 增加/扩充可离线自动化检查:变量未设置、合法路径含空格、显式路径错误、PATH 回退、可选工具缺失。
- 把旧绝对路径回退仅作为**短期迁移兼容**(如确需保留,必须打印 deprecated warning 和移除日期);完成机器配置后在同一改造周期删掉,不能长期留作第二套真相。
**出口**:路径解析单测/负测通过;主机侧单测、静态门禁、模拟器构建未回归;所有脚本错误信息可执行。
### 阶段 C:逐机器配置与构建验证
1. 在开发机设置当前会话变量并做 `@build`、本地主机单测、refgraph、模拟器的离线验证。
2. 设置用户级永久变量,重开终端复验;不配置的可选工具仍能通过 PATH 或降级策略工作。
3. 配置 Gitea runner SYSTEM 服务环境并重启服务,跑 CI 的 L0 和 L0.5 两个 job。
4. 对 `DTU_STLINK_CLI` 只验证 `-List`/读取版本等无破坏性探测;**烧录/复位验证不属于本次环境变量改造的必需项**,没有实机时不执行。
**出口**:至少两台不同安装路径的 Windows 环境验证通过;CI job 成功;源码及 workflow 不再含活跃的特定用户路径/工具安装路径。
### 阶段 D:清理旧约束
- 更新 `docs/环境与部署/项目部署环境要求.md`、`MDK-ARM/README.md`、`AGENTS.md`、ST-LINK/串口/CI 相关工具说明。
- 删除已确认无调用者的旧入口或机器路径 fallback。
- `pre-commit run --all-files`、`scripts/ci_local.py`、`@build` 通过;CI 两 job 全绿。
- `git grep` 检查剩余绝对路径:允许 Windows 系统变量推导、示例路径(明确标注示例)、第三方/硬件/测试数据;不允许活跃工具调用继续依赖开发者机器盘符。
**最终验收**:新电脑仅需按 §5 配置本机环境变量(加装版本要求的工具),clone 仓库后不修改 `.bat/.py/.ps1/.yml` 中的本机路径即可运行对应开发命令。
---
## 8. 风险与边界
| 风险 | 缓解措施 |
|---|---|
| 显式变量拼错,脚本仍自动挑到别的工具版本 | 显式配置无效时立即报错,不做静默回退;预检输出最终解析路径与版本 |
| 环境变量已更新但 IDE/runner 仍持有旧快照 | 说明设置后需重启终端/IDE/runner 服务;CI 加启动时自检 |
| Keil 与 ST-LINK 路径含空格 | BAT 调用始终完整双引号包裹;加入路径含空格测试 |
| Gitea runner 作为 SYSTEM 导致用户变量不可见 | 通过机器级或服务级变量注入,并重启 runner;workflow 报告变量缺失,不猜个人目录 |
| MSVC/SDK 版本布局差异 | 显式 `DTU_MSVC_CL` + SDK 根目录可覆盖;自动发现作为 fallback;检查 x64 Host 编译器与 SDK include/lib 均齐全 |
| 文档已改但代码还没实现,用户误以为路径已经可配置 | 文档开头标明“规划稿、未实施”;阶段完成后更新状态,不提前改写当前事实为完成 |
| 过度配置造成环境变量泛滥 | 只为实际机器路径变量化;项目相对路径、PATH 可发现工具、OS 系统目录不重复配置 |
---
## 9. 后续任务拆分(实现阶段)
1. **统一变量接口与解析行为**(`DTU_` 前缀、必选/可选、fail-fast 规则)。
2. **改造 MCU 工具入口**(Keil UV4 / ST-LINK CLI / 遗留 `_build.cmd`)。
3. **改造 Python/主机工具发现**(pre-commit Python / MSVC / Windows SDK / Graphviz / 字体目录)。
4. **改造 CI runner 环境解析**(移除 Anaconda/Cppcheck/VS 的具体安装路径,SYSTEM 服务注入变量)。
5. **本地与第二台机器验证并清理旧路径**(代码、workflow、`AGENTS.md`、部署与工具文档一起收口)。
> 本文冻结方案并已实施(2026-10-02):上述代码改造全部完成并通过本机全链路验证;
> runner 侧 CI 全绿待新 workflow 推送远程后触发(见变更记录)。实施期遵守项目安全限制:没有 MCU 时不运行下载/烧录/复位动作。
---
## 变更记录
| 日期 | 变更 |
|---|---|
| 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` 确认零调用后删除。② 本机按 §5.2 配置用户级 `DTU_KEIL_UV4`/`DTU_STLINK_CLI`(其余工具本机均可自动发现,未设变量),验证:`@build` BUILD_OK 0/0、`ci_local.py` L0 15 钩子 + L0.5 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` 仍指旧路径——与本改造无关,留待配置引擎重构方处理)、`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` 即可跑 L0)。⑤ 全量 `pre-commit --all-files` + `ci_local.py` 通过。待办:新 workflow 推送远程后跑一次 CI 两 job 闭环验证;第二台不同安装路径机器的交叉验证 |
| 2026-10-02 | 初版规划:盘点 BAT/Python/PowerShell/Gitea workflow 中机器相关工具路径;定义 `DTU_*` 变量清单、优先级、用户级与 SYSTEM runner 配置边界;规划 4 阶段迁移及离线/实机验收范围。未改工具调用代码 |
@@ -57,12 +57,41 @@ flowchart LR
| 版本控制 | git | 提交受 pre-commit 钩子门禁(§2.7) |
| 磁盘 | ≥10 GB 空闲 | Keil 工程 + VS 模拟器 `build/` + 工具链 |
### 2.1.1 本地工具路径环境变量(`DTU_*` 系列,新机器必配项见下表)
仓库脚本**不含本机绝对工具路径**:Keil / ST-LINK / pre-commit Python / MSVC / Windows SDK /
Graphviz / Cppcheck 的安装位置差异一律用 `DTU_*` 环境变量表达(完整契约与解析语义见
`docs/环境与部署/本地工具路径环境变量方案.md`)。新机器装完工具后按表配置:
| 变量 | 必需性 | 值的形态 | 使用方 |
|---|---|---|---|
| `DTU_KEIL_UV4` | **必需**(MCU 构建/Keil 下载机) | UV4.exe 完整路径 | `MDK-ARM/build.bat`、`download.bat` |
| `DTU_STLINK_CLI` | **必需**(用 ST-LINK CLI 的机器;已在 PATH 可不设) | ST-LINK_CLI.exe 完整路径 | `MDK-ARM/reset.bat`(烧录/复位/回读) |
| `DTU_PRECOMMIT_PYTHON` | 可选(pre-commit 不在 `.venv`/当前解释器时设;CI runner 建议必设) | 装有 pre-commit 的 python.exe 完整路径 | `scripts/ci_local.py`、CI L0/L0.5 |
| `DTU_CPPCHECK` | 可选(开发机入 PATH 即可;无 PATH 的 CI runner 建议设) | cppcheck.exe 完整路径 | pre-commit cppcheck 钩子、CI L0 |
| `DTU_MSVC_CL` | 可选(VS 标准位置时自动探测) | x64 `cl.exe` 完整路径 | 主机侧单测、CI L0.5 |
| `DTU_WINDOWS_KITS_ROOT` | 可选(SDK 标准位置时自动探测) | `Windows Kits\10` 根目录 | 主机侧单测 |
| `DTU_VSWHERE` | 可选(VS 标准位置时由 `%ProgramFiles(x86)%` 自动推导) | vswhere.exe 完整路径 | `simulator/build_sim.ps1` |
| `DTU_GRAPHVIZ_DOT` | 可选(PATH 可发现时不设) | dot.exe 完整路径 | `tools/refgraph` 渲染 |
```powershell
# 用户级设置(无需管理员;★ 设完必须重开终端/IDE 才生效)
[Environment]::SetEnvironmentVariable('DTU_KEIL_UV4', 'D:\Tools\Keil\UV4\UV4.exe', 'User') # 示例路径
[Environment]::SetEnvironmentVariable('DTU_STLINK_CLI', 'D:\Tools\STLink\ST-LINK_CLI.exe', 'User') # 示例路径
# 其余可选项按实际安装位置补充;验证:$env:DTU_KEIL_UV4 后 Test-Path / 跑对应命令
```
> 统一解析语义:变量**显式设置但无效 → 立即报错**(指出变量名与收到的路径),不静默回退到别的安装;
> 未设置 → 按工具走 PATH / 标准布局自动发现(可选工具允许降级,如 Graphviz 缺失只跳渲染)。
> CI runner 以 **SYSTEM 服务**运行,用户级变量对其不可见——runner 用**机器级**变量注入(见
> `Gitea_Runner部署指南.md` 环境变量节)。
### 2.2 MCU 构建工具链(必需)
| 项 | 要求 | 说明 |
|---|---|---|
| Keil MDK-ARM | **v5.x**(须含 ARMCC v5 编译器) | 工程锁定 `uAC6=0`(仅 ARMCC v5,**不支持 armclang**);仅支持此工具链,无其他工具链 |
| 安装路径 | `C:\Keil_v5\` | `MDK-ARM/build.bat`、`download.bat` 硬编码 `C:\Keil_v5\UV4\UV4.exe`;**换机器须装到同路径,或修改两个 bat 的 `UV4=` 行** |
| 安装路径 | **任意目录** | `build.bat` / `download.bat` / `reset.bat` 经 `DTU_*` 环境变量解析工具路径(§2.1.1);新机器装完后设置 `DTU_KEIL_UV4` / `DTU_STLINK_CLI` 即可,**无需修改仓库脚本** |
| 设备支持 | STM32F407ZGTx + CMSIS Flash 算法 | 工程引用 `STM32F4xx_1024.FLM`(1MB 片内 Flash,0x08000000),由 CMSIS STM32F4 设备包提供 |
| STM32CubeMX | **6.17.0**(工程 `STM32F407-Demo.ioc` 记录的版本) | 修改外设/引脚/时钟配置并再生成 CubeMX 文件;固件包须 **STM32Cube FW_F4 V1.28.3** |
| 命令行构建 | `& "MDK-ARM\build.bat"`(即 `@build`) | 退出码 0 = 0 错 0 警;失败看 `MDK-ARM/build_log.txt` |
@@ -77,7 +106,7 @@ flowchart LR
| 项 | 配置方法 | 说明 |
|---|---|---|
| License | 首次启动 UV4 自动生成 **90 天评估 license**;长期使用需购买正式 license | license 绑定机器、不在仓库;`Options for Target → License` 查看/输入 |
| Device Pack | **Pack Installer** 安装 `Keil::CMSIS`、`Keil::STM32F4xx_DFP`(pack 源 https://www.keil.com/pack/ ) | 工程引用的 **Flash 算法 `STM32F4xx_1024.FLM` 就来自此 pack**(.uvoptx 的 `$$Device:STM32F407ZGTx$` 变量解析到 pack 目录 `C:\Keil_v5\PACK\Keil\STM32F4xx_DFP\<ver>\CMSIS\Flash\`);**pack 缺失则下载失败** |
| Device Pack | **Pack Installer** 安装 `Keil::CMSIS`、`Keil::STM32F4xx_DFP`(pack 源 https://www.keil.com/pack/ ) | 工程引用的 **Flash 算法 `STM32F4xx_1024.FLM` 就来自此 pack**(.uvoptx 的 `$$Device:STM32F407ZGTx$` 变量解析到 pack 目录 `<Keil安装目录>\PACK\Keil\STM32F4xx_DFP\<ver>\CMSIS\Flash\`,如 `C:\Keil_v5\...`);**pack 缺失则下载失败** |
| 下载器驱动 | 工程已配 **UL2CM3** 调试驱动 + Flash 算法参数(.uvoptx 自带,调试时钟 10 MHz) | 物理下载器(ST-Link 等)需装 USB 驱动(见第 8 步);现场换其他下载器在 Keil `Options for Target → Debug → Settings` 切换 |
> **项目自带、新机器无需重配**(随仓库同步):编译器与目标选项(`.uvprojx`:ARMCC v5 / 设备 STM32F407ZGTx / Cortex-M4+FPU)、
@@ -124,7 +153,7 @@ flowchart LR
|---|---|---|
| 统一入口 | **仓库 `.venv\Scripts\python.exe`** | 一切依赖第三方库的脚本(字体生成、截图转 PNG、RemoDispBus 回归)都用它 |
| 解释器版本 | Python ≥ 3.10(任意发行版) | 种子解释器仅用于建 venv 一次;本机为 3.12.4 |
| 依赖 | `fonttools==4.51.0`、`pillow==10.3.0`、`pyserial==3.5` | 清单 = 仓库根 `requirements.txt`(**必须保持纯 ASCII**:Windows 下 pip 按 GBK 代码页解码,中文注释会 UnicodeDecodeError) |
| 依赖 | `fonttools==4.51.0`、`pillow==10.3.0`、`pyserial==3.5`、`pre-commit==4.6.2` | 清单 = 仓库根 `requirements.txt`(**必须保持纯 ASCII**:Windows 下 pip 按 GBK 代码页解码,中文注释会 UnicodeDecodeError);`pre-commit` 入 `.venv` 后,重建 venv 即可直接跑 L0 门禁(`scripts/ci_local.py` 自动选用) |
| 入库情况 | `.venv/` 已 gitignore | **换机/首次必须重建** |
```powershell
@@ -181,7 +210,7 @@ python tools/font_gen/extract_cn.py # 任意 python3:
| 项 | 要求 | 说明 |
|---|---|---|
| Graphviz | `winget install Graphviz.Graphviz`(本机实测 16.1.0) | `tools/refgraph` 引用关系图生成器的渲染引擎;`dot` 在 `C:\Program Files\Graphviz\bin\`,工具自动定位,**无需配置 PATH** |
| Graphviz | `winget install Graphviz.Graphviz`(本机实测 16.1.0) | `tools/refgraph` 引用关系图生成器的渲染引擎;`dot` 从 **PATH** 查找(winget 安装自动入 PATH);非标准安装目录用 `DTU_GRAPHVIZ_DOT` 指向 `dot.exe`(§2.1.1) |
| 必需性 | **可选** | 未装时工具自动跳过渲染(仍产出 `.dot`/`.json`,装好后重跑即出图);不影响编译/测试/审查门禁 |
| 产物 | `docs/images/引用关系图.*` | 文件级 + 模块级 `.svg`/`.dot`/`.json`(随工具提交入库);PNG 仅本地预览(`docs/images/*.png` 已 gitignore) |
@@ -208,7 +237,7 @@ winget install Git.Git
**第 2 步:Keil MDK-ARM v5 + STM32CubeMX**(GUI 安装,无命令行方式)
- 下载页:<https://www.keil.com/arm/mdk.htm>(MDK-ARM v5.x;90 天评估 license 可先开发;必须含 **ARMCC v5** 编译器——工程锁 `uAC6=0`,armclang 不行)
- **安装目录设为 `C:\Keil_v5`**(`build.bat` / `download.bat` 的 `UV4=` 行硬编码该路径;装别处就改这两个 bat)
- **安装目录任意**(装完设置 `DTU_KEIL_UV4` = UV4.exe 完整路径,§2.1.1;默认安装位置即可)
- 装完打开 **Pack Installer** → 安装 `Keil::CMSIS` 和 `Keil::STM32F4xx_DFP`(提供 STM32F407ZGTx 设备 + `STM32F4xx_1024.FLM` Flash 算法;pack 源 https://www.keil.com/pack/ ,Pack Installer 自动拉取)——**必装,否则烧录失败**(FLM 从 pack 目录解析,不在仓库)
- **License**:首次启动 UV4 自动生成 90 天评估 license(长期使用需购买正式 license;license 绑定机器、不在仓库)
- **STM32CubeMX 6.17.0**:下载页 https://www.st.com/en/tools/stm32cubemx.html (直链 https://www.st.com/resource/en/software_stm32cubemx/stm32cubemx_setup.exe )
@@ -289,13 +318,13 @@ npm i -g lv_font_conv # 手动:https://www.npmjs.com/package/lv
```powershell
winget install astral-sh.uv
uv tool install pre-commit
winget install cppcheck # 2.21.0 → C:\Program Files\Cppcheck
winget install cppcheck # 2.21.0(安装位置任意;入 PATH 或用 DTU_CPPCHECK 指向)
# ★ 重开终端(PATH 才生效),然后:
pre-commit install
pre-commit run --all-files # 首次全库基线扫描
```
> 手动下载:uv → https://astral.sh/uv/ (一行安装 `powershell -c "irm https://astral.sh/uv/install.ps1 | iex"`)· pre-commit → https://pre-commit.com/ · cppcheck 2.21.0 → https://github.com/CppQA/cppcheck/releases (2.21.0 tag 的 Windows x64 zip,解压至 `C:\Program Files\Cppcheck` 并加入 PATH)
> 手动下载:uv → https://astral.sh/uv/ (一行安装 `powershell -c "irm https://astral.sh/uv/install.ps1 | iex"`)· pre-commit → https://pre-commit.com/ · cppcheck 2.21.0 → https://github.com/CppQA/cppcheck/releases (2.21.0 tag 的 Windows x64 zip,解压至任意目录并加入 PATH,或用 `DTU_CPPCHECK` 指向 `cppcheck.exe`)
**第 7 步:Python 串口助手**(串口调试 / 自动测试,仓库内置)
@@ -320,7 +349,7 @@ pre-commit run --all-files # 首次全库基线扫描
把查到的端口写入 `.opencode\serial_config.json` 的 `portName`(唯一配置源,换口只改这里)。
**第 10 步:冒烟验证**(全过 = 环境就绪)
**第 10 步:冒烟验证**(全过 = 环境就绪;前置:§2.1.1 的 `DTU_*` 变量已设置——未设时构建脚本会明确报出缺哪个变量及设置方法)
```powershell
& "MDK-ARM\build.bat" # → BUILD_OK: 0 errors, 0 warnings
@@ -337,7 +366,7 @@ pre-commit run --all-files
**搭建清单汇总**(随步骤逐项打勾):
- [ ] Windows 10/11 x64 + PowerShell 5.1+
- [ ] Keil MDK-ARM v5.x 装到 `C:\Keil_v5\`(或已同步修改两个 bat)+ CMSIS / STM32F4 DFP 包
- [ ] Keil MDK-ARM v5.x 已装(任意目录,`DTU_KEIL_UV4` 已设 UV4.exe 完整路径,§2.1.1)+ CMSIS / STM32F4 DFP 包
- [ ] STM32CubeMX 6.17.0 已装(与 .ioc 版本一致;含/可装 STM32Cube FW_F4 V1.28.3 固件包)
- [ ] VS2019 / 2022 / 2026 任一(C++ x64 工作负载)+ Windows 10/11 SDK + CMake ≥3.15(模拟器构建脚本自动适配 VS 版本;**同一 VS 提供主机侧单测所需的 `cl.exe`**,见 §2.3 / §2.10)
- [ ] `git clone` 仓库 → `pre-commit install`;cppcheck 入 PATH
@@ -355,7 +384,7 @@ pre-commit run --all-files
| 组件 | 官方下载页 | 版本 / 说明 |
|---|---|---|
| Git for Windows | https://git-scm.com/download/win | 最新稳定版 |
| Keil MDK-ARM | https://www.keil.com/arm/mdk.htm | v5.x,须含 ARMCC v5;安装目录 `C:\Keil_v5` |
| Keil MDK-ARM | https://www.keil.com/arm/mdk.htm | v5.x,须含 ARMCC v5;安装目录任意(`DTU_KEIL_UV4` 设 UV4.exe 完整路径) |
| CMSIS / STM32F4xx DFP | https://www.keil.com/pack/ | 在 Keil Pack Installer 内装 `Keil::CMSIS`、`Keil::STM32F4xx_DFP` |
| STM32CubeMX | https://www.st.com/en/tools/stm32cubemx.html | 6.17.0(与 .ioc 一致);直链 https://www.st.com/resource/en/software_stm32cubemx/stm32cubemx_setup.exe |
| STM32Cube FW_F4(固件包) | https://www.st.com/en/embedded-software/stm32cube-f4.html | V1.28.3(与仓库 HAL 驱动一致) |
@@ -386,7 +415,7 @@ workflow 见 `.gitea/workflows/ci.yml`;覆盖边界与判定细节见 [`../测
| Gitea 版本 | ≥ 1.21(实测远程 **1.25.4**) | workflow 置于 `.gitea/workflows/`,兼容 GitHub Actions 语法 |
| Actions 开关 | 实例 `[actions] ENABLED = true` | site admin 配置;未开启则 push 不触发任何 job |
| runner OS | **Windows**(`runs-on: windows`) | labels 须含 `windows`;与开发机同平台,避免脚本语法分叉 |
| runner 软件 | Python 3.x、cppcheck、pre-commit、**MSVC**(VS C++ 工具链 + Windows SDK) | 前三个缺 → `l0-gates` **硬失败**(`::error::`);MSVC 缺 → `l05-host-unit-tests` **降级跳过并告警**(不硬失败,但等于 L0.5 裸奔) |
| runner 软件 | Python 3.x、cppcheck、pre-commit、**MSVC**(VS C++ 工具链 + Windows SDK) | 前三个缺 → `l0-gates` **硬失败**(`::error::`);MSVC 缺 → `l05-host-unit-tests` **降级跳过并告警**(不硬失败,但等于 L0.5 裸奔)。runner 以 SYSTEM 服务运行,**用户级 PATH/变量不可见**:自动发现失败时用**机器级** `DTU_PRECOMMIT_PYTHON` / `DTU_CPPCHECK` / `DTU_MSVC_CL` 注入(见 `Gitea_Runner部署指南.md` 环境变量节,§2.1.1) |
| Keil | **不需要** | 刻意不跑 `@build`(需授权);`.map` 缺失时 `mem-numbers` 钩子自动跳过 |
| `mem-numbers` | 有 `.map` 就跑,无则 `SKIP` | Keil 构建产物 `.map` 已 gitignore;自建带 Keil 的 runner 会照常跑该钩子 |
@@ -529,7 +558,8 @@ workflow 见 `.gitea/workflows/ci.yml`;覆盖边界与判定细节见 [`../测
| 现象 | 原因 | 处理 |
|---|---|---|
| `build.bat` 找不到 UV4 / 闪退 | Keil 未装在 `C:\Keil_v5\` | 装到该路径,或改 `build.bat` / `download.bat` 的 `UV4=` 行 |
| `build.bat` / `download.bat` 报 `DTU_KEIL_UV4 is not set` / `does not exist` | `DTU_KEIL_UV4` 未设置或指向错误路径(**设完变量须重开终端**) | 设置/修正 `DTU_KEIL_UV4` 为 UV4.exe 完整路径(§2.1.1),重开终端重试 |
| `reset.bat` 报 `ST-LINK_CLI.exe not found` / `ENV_ERROR: DTU_STLINK_CLI` | `DTU_STLINK_CLI` 未设且不在 PATH,或显式值无效 | 设置 `DTU_STLINK_CLI` 为 ST-LINK_CLI.exe 完整路径,或把其目录加入 PATH;显式值无效时**不会**回退,须修值 |
| Keil 编译报编译器不识别 | 新装 MDK 只有 armclang | 工程锁 `uAC6=0`,必须用带 **ARMCC v5** 的 MDK v5.x |
| CubeMX 再生成后出现大量 diff / 新告警 | 用了比工程记录更新的 CubeMX / 固件包版本 | 用 git 还原生成文件,按 **.ioc 记录的 CubeMX 6.17.0 + STM32Cube FW_F4 V1.28.3** 重新生成 |
| CMake 配置失败:找不到生成器 | 本机 VS 大版本与生成器不匹配 | 统一走 `simulator\build_sim.bat`(自动探测 VS 版本选生成器);手动 cmake 时 `-G` 号须与本机 VS 一致(16=2019 / 17=2022 / 18=2026) |
@@ -573,6 +603,7 @@ workflow 见 `.gitea/workflows/ci.yml`;覆盖边界与判定细节见 [`../测
| 日期 | 变更 |
|---|---|
| 2026-10-02 | **本地工具路径环境变量方案落地**(`本地工具路径环境变量方案.md`):仓库脚本不再含本机绝对工具路径——10 处调用点(`build/download/reset.bat`、`_build.cmd` 退役、`ci_local.py`、`ci.yml`、`gen_refgraph.py`、`unit_test_harness.py`、`build_sim.ps1`、`make_font.py`)统一改为"`DTU_*` 变量优先 + 自动发现回退"(显式设置但无效 = 硬报错,不静默回退);新增 §2.1.1 变量清单/设置方法/解析语义;Keil 安装路径、Graphviz、cppcheck、VS/SDK 自动探测、Python 重建示例与速查表同步改为变量口径;`requirements.txt` 增 `pre-commit`(重建 `.venv` 即可直接跑 L0 门禁);本机已按 §2.1.1 配置用户级 `DTU_KEIL_UV4`/`DTU_STLINK_CLI` 并全链路验证(@build 0/0、ci_local L0+L0.5 全绿、refgraph 重生成、reset 探针识别) |
| 2026-10-02 | 新增 **`Gitea_Runner部署指南.md`**:针对**本机 Gitea 原生部署**(`D:\Docker\Gitea\gitea.exe` + Windows 服务 + `127.0.0.1:3001`)定制的 Runner 端全流程——下载 / `register`(**`--instance` 用回环、`--labels "windows:host"` 必须精确匹配 `runs-on`**)/ `config.yaml` / `daemon install` 常驻 / 软件与 PATH 坑 / MSVC 路径约束 / 内网 action 零依赖改法 / 排障表 / `check_env.ps1` 自检脚本;§七相关文档登记 |
| 2026-10-01 | 新增 **`CI配置指南.md`**(Gitea Actions 配置全流程:服务端 `[actions] ENABLED` / Windows runner 注册(`--labels "windows:host"`)/ runner 软件环境与 PATH / workflow 位置与触发 / 内网拉不到 `actions/checkout` 的三种处置 / 端到端验证清单 / 故障排查表 / 日常维护);§七相关文档登记 |
| 2026-10-01 | **新增 §2.11 CI runner 环境(Gitea Actions,T-6)**:Gitea ≥1.21(实测 1.25.4)+ `[actions] ENABLED` + Windows runner(装 Python/cppcheck/pre-commit/MSVC);**不需要 Keil**(刻意不跑 `@build`,无 `.map` 时 `mem-numbers` 自动跳过);补"CI 不能替代本地门禁"与 `scripts/ci_local.py` 过渡命令 |
+1
View File
@@ -4,3 +4,4 @@
fonttools==4.51.0 # tools/font_gen/make_font.py (font generation, verified version)
pillow==10.3.0 # simulator/i1_to_png.py (screenshot to PNG, verified on this machine)
pyserial==3.5 # tools/serial_tool/serial_tool.py (serial assistant daemon + CLI)
pre-commit==4.6.2 # commit gate (scripts/ci_local.py L0; keeps rebuilt .venv self-sufficient)
+3 -2
View File
@@ -32,8 +32,9 @@
## 使用方式
```bash
# 全库跑门禁
& 'C:\ProgramData\anaconda3\python.exe' -m pre_commit run --all-files
# 全库跑门禁(用仓库 .venv 的 python,其 pre-commit 随 requirements.txt 安装;
# 其他装有 pre-commit 的解释器可用 DTU_PRECOMMIT_PYTHON 指定)
& '.venv\Scripts\python.exe' -m pre_commit run --all-files
# 本地跑与 CI 等价的门禁(L0 + L0.5)
& '.venv\Scripts\python.exe' scripts/ci_local.py
+34 -9
View File
@@ -38,6 +38,7 @@
import argparse
import os
import re
import shutil
import subprocess
import sys
from pathlib import Path
@@ -46,18 +47,40 @@ REPO_ROOT = Path(__file__).resolve().parent.parent
def _resolve_python():
"""挑一个真正装了 pre-commit 的解释器。
r"""挑一个真正装了 pre-commit 的解释器。
本机可能有多个 python(.venv / anaconda3 / 系统),而 **pre-commit 只装在其中一个**。
按优先级探测:当前解释器 → `.venv` → anaconda3 → PATH 上的 `pre-commit` 所在环境。
本机可能有多个 python(.venv / 发行版 / 系统),而 **pre-commit 只装在其中一个**。
按优先级探测(见 docs/环境与部署/本地工具路径环境变量方案.md §3.1):
1. DTU_PRECOMMIT_PYTHON(显式配置:文件缺失或无 pre-commit 模块 → 立即报
配置错误,**不静默回退**到别的解释器)
2. 当前解释器(sys.executable)
3. 仓库 `.venv\Scripts\python.exe`
4. PATH 上的 `python`
找到即返回 (python_path, note);都找不到则返回 (当前解释器, None) 交由调用方报错。
"""
candidates = [sys.executable]
venv = REPO_ROOT / ".venv" / "Scripts" / "python.exe"
if venv.is_file():
candidates.append(str(venv))
candidates.append(r"C:\ProgramData\anaconda3\python.exe")
explicit = os.environ.get("DTU_PRECOMMIT_PYTHON", "").strip()
if explicit:
if not os.path.isfile(explicit):
print("[ERROR] DTU_PRECOMMIT_PYTHON 已设置但文件不存在: {}".format(explicit))
print(" 请修正该变量(python.exe 完整路径),或清除该变量改用自动探测。")
sys.exit(2)
try:
cp = subprocess.run([explicit, "-m", "pre_commit", "--version"],
capture_output=True, timeout=60)
except (OSError, subprocess.TimeoutExpired) as e:
print("[ERROR] DTU_PRECOMMIT_PYTHON 指定的解释器无法执行: {}({})".format(explicit, e))
sys.exit(2)
if cp.returncode != 0:
print("[ERROR] DTU_PRECOMMIT_PYTHON 指向的解释器没有 pre-commit 模块: {}".format(explicit))
print(" 请修正该变量(指向装有 pre-commit 的 python),或清除该变量改用自动探测。")
sys.exit(2)
return explicit, "(显式配置 DTU_PRECOMMIT_PYTHON)"
candidates = [
sys.executable,
str(REPO_ROOT / ".venv" / "Scripts" / "python.exe"),
shutil.which("python"),
]
seen = set()
for py in candidates:
if not py or py in seen or not os.path.isfile(py):
@@ -230,7 +253,9 @@ def main(argv=None):
if probe.returncode != 0:
print("[ERROR] 该解释器没有 pre-commit 模块。请任选其一:")
print(" - 用装了 pre-commit 的解释器跑本脚本(如 "
r"& 'C:\ProgramData\anaconda3\python.exe' scripts/ci_local.py)")
"& '.venv\\Scripts\\python.exe' scripts/ci_local.py)")
print(" - 或设置 DTU_PRECOMMIT_PYTHON 指向该解释器")
print(" (见 docs/环境与部署/本地工具路径环境变量方案.md)")
print(" - 或在当前环境安装:pip install pre-commit")
return 2
+12 -6
View File
@@ -45,12 +45,18 @@ if (-not $cmake) {
exit 3
}
# vswhere 随 Visual Studio / BuildTools 自带
$pf86 = ${env:ProgramFiles(x86)}
if (-not $pf86) { $pf86 = 'C:\Program Files (x86)' }
$vswhere = Join-Path $pf86 'Microsoft Visual Studio\Installer\vswhere.exe'
if (-not (Test-Path $vswhere)) {
Write-Host '[build_sim] 预检失败:未找到 vswhere(本机未安装 Visual Studio / BuildTools)' -ForegroundColor Red
# vswhere:DTU_VSWHERE 显式覆盖 > %ProgramFiles(x86)% 推导(不保留固定 C 盘值)
$vswhere = $env:DTU_VSWHERE
if ($vswhere) {
if (-not (Test-Path -LiteralPath $vswhere)) {
Write-Host "[build_sim] 预检失败:DTU_VSWHERE 已设置但文件不存在:$vswhere" -ForegroundColor Red
exit 3
}
} elseif (${env:ProgramFiles(x86)}) {
$vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
}
if (-not $vswhere -or -not (Test-Path -LiteralPath $vswhere)) {
Write-Host '[build_sim] 预检失败:未找到 vswhere(本机未安装 Visual Studio / BuildTools,或布局非标准;可用 DTU_VSWHERE 指向 vswhere.exe 完整路径)' -ForegroundColor Red
exit 3
}
+89 -41
View File
@@ -48,26 +48,49 @@ import tempfile
from dataclasses import dataclass, field
# ----------------------------- 工具链探测位置 -----------------------------
# 顺序 = 优先级;`_first` 取每个根目录下最大的版本子目录(新版本优先)。
VS_ROOTS = [
r"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools",
r"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community",
r"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional",
r"C:\Program Files\Microsoft Visual Studio\2022\BuildTools",
r"C:\Program Files\Microsoft Visual Studio\2022\Community",
r"C:\Program Files\Microsoft Visual Studio\2022\Professional",
r"C:\Program Files\Microsoft Visual Studio\2022\Enterprise",
r"C:\Program Files\Microsoft Visual Studio\2026\BuildTools",
r"C:\Program Files\Microsoft Visual Studio\2026\Community",
# VS2026 的实际安装目录是 "18"(2026-10 台架实测:vswhere → ...\18\Community,
# 显式覆盖(环境变量,见 docs/环境与部署/本地工具路径环境变量方案.md):
# DTU_MSVC_CL x64 Host cl.exe 完整路径(最高优先级;无效直接报错)
# DTU_WINDOWS_KITS_ROOT Windows Kits\10 根目录
# 未设置时用标准布局自动探测:默认安装根由系统变量 %ProgramFiles% /
# %ProgramFiles(x86)% 推导(不写死盘符);`_first` 取每个根目录下最大的版本子目录。
def _default_vs_roots():
"""标准 VS 安装根(2019 -> Program Files (x86);2022/2026 -> Program Files)。"""
pf = os.environ.get("ProgramFiles", r"C:\Program Files")
pf86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
roots = []
for year, base in (("2019", pf86), ("2022", pf), ("2026", pf)):
for edition in ("BuildTools", "Community", "Professional", "Enterprise"):
roots.append(os.path.join(base, "Microsoft Visual Studio", year, edition))
# VS2026 的实际安装目录名是 "18"(2026-10 台架实测:vswhere → ...\18\Community,
# MSVC 14.51 + SDK 10.0.26100 布局与 2022 一致,cl.exe 路径模式不变);
# 上面两条 "2026" 目录名在本机并不存在,保留以防将来布局回改
r"C:\Program Files\Microsoft Visual Studio\18\BuildTools",
r"C:\Program Files\Microsoft Visual Studio\18\Community",
r"C:\Program Files\Microsoft Visual Studio\18\Professional",
r"C:\Program Files\Microsoft Visual Studio\18\Enterprise",
]
SDK_ROOTS = [r"C:\Program Files (x86)\Windows Kits\10"]
# 上面 "2026" 目录名在本机并不存在,保留以防将来布局回改
for edition in ("BuildTools", "Community", "Professional", "Enterprise"):
roots.append(os.path.join(pf, "Microsoft Visual Studio", "18", edition))
return roots
def _default_sdk_roots():
r"""Windows SDK 默认安装根(%ProgramFiles(x86)%\Windows Kits\10)。"""
pf86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
return [os.path.join(pf86, "Windows Kits", "10")]
def _sdk_dirs(sdk):
"""返回某 Windows Kits 根下的 (include 子目录列表, lib 子目录列表)。"""
sdk_inc = _first(os.path.join(sdk, r"Include\*"))
sdk_lib = _first(os.path.join(sdk, r"Lib\*"))
inc = []
if sdk_inc:
inc = [os.path.join(sdk_inc, "ucrt"),
os.path.join(sdk_inc, "shared"),
os.path.join(sdk_inc, "um")]
lib = []
if sdk_lib:
lib = [os.path.join(sdk_lib, "ucrt", "x64"),
os.path.join(sdk_lib, "um", "x64")]
return inc, lib
# 编译开关(各模块共用;模块特有开关见 TestBuild.extra_flags)
_BASE_FLAGS = [
@@ -127,13 +150,32 @@ def decode(b):
def locate_toolchain():
"""返回 (cl.exe, include_dirs, lib_dirs);找不到返回 (None, [], [])。"""
cl = None
for vs in VS_ROOTS:
c = _first(os.path.join(vs, r"VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe"))
if c:
cl = c
break
"""返回 (cl.exe, include_dirs, lib_dirs);找不到返回 (None, [], [])。
优先级(见方案文档):DTU_MSVC_CL / DTU_WINDOWS_KITS_ROOT(显式设置但
无效 → 立即报错,**不静默回退**自动探测)→ 标准布局自动探测
(_default_vs_roots / _default_sdk_roots)。
"""
# ---- cl.exe ----
explicit_cl = os.environ.get("DTU_MSVC_CL", "").strip()
if explicit_cl:
if not os.path.isfile(explicit_cl):
print("[ENV] DTU_MSVC_CL 已设置但不存在: {}(请修正变量值,不做自动探测回退)"
.format(explicit_cl), file=sys.stderr)
return None, [], []
tail = os.path.normpath(explicit_cl).lower()
if not tail.endswith(os.path.join("bin", "hostx64", "x64", "cl.exe")):
print("[ENV] DTU_MSVC_CL 必须是 x64 Host 编译器(路径以 bin\\Hostx64\\x64\\cl.exe 结尾): {}"
.format(explicit_cl), file=sys.stderr)
return None, [], []
cl = explicit_cl
else:
cl = None
for vs in _default_vs_roots():
c = _first(os.path.join(vs, r"VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe"))
if c:
cl = c
break
if not cl:
return None, [], []
@@ -143,20 +185,26 @@ def locate_toolchain():
inc = [os.path.join(msvc_ver_dir, "include")]
lib = [os.path.join(msvc_ver_dir, "lib", "x64")]
for sdk in SDK_ROOTS:
sdk_inc = _first(os.path.join(sdk, r"Include\*"))
sdk_lib = _first(os.path.join(sdk, r"Lib\*"))
if sdk_inc:
inc += [
os.path.join(sdk_inc, "ucrt"),
os.path.join(sdk_inc, "shared"),
os.path.join(sdk_inc, "um"),
]
if sdk_lib:
lib += [
os.path.join(sdk_lib, "ucrt", "x64"),
os.path.join(sdk_lib, "um", "x64"),
]
# ---- Windows SDK ----
explicit_sdk = os.environ.get("DTU_WINDOWS_KITS_ROOT", "").strip()
if explicit_sdk:
if not os.path.isdir(explicit_sdk):
print("[ENV] DTU_WINDOWS_KITS_ROOT 已设置但不存在: {}(请修正变量值,不做自动探测回退)"
.format(explicit_sdk), file=sys.stderr)
return None, [], []
sdk_inc, sdk_lib = _sdk_dirs(explicit_sdk)
if not sdk_inc and not sdk_lib:
print("[ENV] DTU_WINDOWS_KITS_ROOT 下未找到 Include\\<ver> 或 Lib\\<ver>: {}".format(explicit_sdk),
file=sys.stderr)
return None, [], []
else:
sdk_inc, sdk_lib = [], []
for sdk in _default_sdk_roots():
sdk_inc, sdk_lib = _sdk_dirs(sdk)
if sdk_inc or sdk_lib:
break
inc += sdk_inc
lib += sdk_lib
return cl, inc, lib
@@ -168,7 +216,7 @@ def build_and_run(build, out=None):
cl, inc, lib = locate_toolchain()
if not cl:
print("[ENV] 找不到 MSVC cl.exe(需要 VS2019/2022/2026 的 C++ 工具链)", file=err)
print("[ENV] 找不到 MSVC cl.exe(设置 DTU_MSVC_CL,或安装 VS2019/2022/2026 的 C++ 工具链)", file=err)
return 2
tmp = tempfile.gettempdir()
+5 -3
View File
@@ -52,8 +52,10 @@ def resolve_font(path):
if not os.path.exists(path):
sys.exit('ERROR: --font 指定的文件不存在: ' + path)
return path
# 默认字体:Windows 宋体集合 simsun.ttc(lv_font_conv 不支持 .ttc,需先抽取 face0)
ttc = r'C:\Windows\Fonts\simsun.ttc'
# 默认字体:Windows 宋体集合 simsun.ttc,由 WINDIR 环境变量的系统字体目录推导
# (兼容非 C 盘系统盘);lv_font_conv 不支持 .ttc,需先抽取 face0
windir = os.environ.get('WINDIR') or r'C:\Windows'
ttc = os.path.join(windir, 'Fonts', 'simsun.ttc')
if os.path.exists(ttc):
try:
from fontTools.ttLib import TTCollection
@@ -64,7 +66,7 @@ def resolve_font(path):
return tmp
except Exception as e:
sys.exit('ERROR: 抽取 simsun.ttc 失败,请 pip install fonttools,或用 --font 指定 ttf: ' + str(e))
sys.exit('ERROR: 未找到 C:\\Windows\\Fonts\\simsun.ttc,请用 --font 指定字体 ttf/otf 路径')
sys.exit('ERROR: 未找到 %s,请用 --font 指定字体 ttf/otf 路径' % ttc)
# ---------------------------------------------------------------------------
+15 -9
View File
@@ -446,14 +446,18 @@ class Graph:
# ---------------------------------------------------------------------------
def find_dot() -> str | None:
p = shutil.which("dot")
if p:
return p
for c in (r"C:\Program Files\Graphviz\bin\dot.exe",
r"C:\Program Files (x86)\Graphviz\bin\dot.exe"):
if os.path.isfile(c):
return c
return None
"""定位 Graphviz dot:DTU_GRAPHVIZ_DOT(显式)→ PATH。
显式变量已设置则严格使用(无效立即报错,不静默回退);未设置时只查
PATH,未找到返回 None 并降级为"只生成 .dot、不渲染"(保持既有语义)。
见 docs/环境与部署/本地工具路径环境变量方案.md §3。
"""
explicit = os.environ.get("DTU_GRAPHVIZ_DOT", "").strip()
if explicit:
if not os.path.isfile(explicit):
sys.exit("ERROR: DTU_GRAPHVIZ_DOT 已设置但不存在: {}(清除该变量可改用 PATH 查找)".format(explicit))
return explicit
return shutil.which("dot")
def render(dot: str, dotfile: str, outfiles: dict[str, str]) -> bool:
@@ -579,7 +583,8 @@ def main() -> int:
f.write(dm)
written.append(pm)
# JSON 数据
# JSON 数据(末尾补单个换行:与 pre-commit end-of-file-fixer 口径一致,
# 避免每次重生成都触发该钩子的"首次修复"抖动,模式同 make_font.py)
pj = os.path.join(outdir, "引用关系图.json")
payload = {
"title": title,
@@ -592,6 +597,7 @@ def main() -> int:
}
with open(pj, "w", encoding="utf-8", newline="\n") as f:
json.dump(payload, f, ensure_ascii=False, indent=1)
f.write("\n")
written.append(pj)
# 渲染