本地工具路径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
@@ -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` 过渡命令 |