- 项目架构总览 v1.1:§1.1 去重复⑥行、硬件行 UART4/TIM3/ADC1;§2.1 任务表 6→9 行且栈值按 freertos.c 校准;§3 补采集算法链与 TIM3 节拍; §5 补 net_events/net_listener/net_pending 与 iec104_serv,单客户端 恢复窗更正为实测 p50 208ms;§7 目录树、§9 索引、§10 变更记录同步 - 项目启动顺序管理:任务表 5→10 行;启动轨迹表 8→14 行(fw build、 ADC input layer、phasor/freq/protection、SD2506 明细、TIM3 启动) - 存储架构说明:§1 初始化顺序块重写(gd5f 归位 app_main_init 内、 rs485Task 未创建、补 TIM3 与 L1~L3 链) - 引用关系图说明 §7 统计与产物重跑刷新;就绪屏障 SVG 补 iec104Task 消费者后重生成(1400x912) - README:外设引脚纠错(RS485=UART4/PC10/PC11/PA15、TPAFE 控制脚 PC8/PC9/PC7)、启动流程补 sys_clock/adc_input/TIM3、任务表重生成 (9 任务)、目录树与 NET 小节同步、ftp_speed_test→regression/ integrity、文档表补四条专项索引 - 工具:gen_task_table.py 补 iec104Task/protectTask 职责; gen_barrier_svg.py 补 iec104Task 消费者与 bit0 计数
6.1 KiB
项目文件引用关系图(tools/refgraph)
生成并维护 STM32F4-Base 的文件级引用关系图(
#include引用)。 工具:tools/refgraph/gen_refgraph.py(纯标准库)+ 成熟渲染引擎 Graphviz。 产物:docs/images/引用关系图.*(本目录图 +.dot+.json)。
1. 为什么自写工具(调研结论)
| 成熟工具 | 能力 | 对本需求的差距 |
|---|---|---|
| Doxygen(开源,C 文档标准工具) | 每文件的 include 依赖图、每函数的调用图、类协作图 | 输出按文件/函数分散,无单一整工程文件引用图;需配置解析全量源码 |
Graphviz(开源,图布局渲染引擎 dot) |
渲染任意 DOT 图(分层布局) | 只做布局渲染、不解析源码 —— 本工具用它出图 |
| cflow(binutils) | 函数级调用图 | 粒度是函数不是文件;依赖汇编/编译产物 |
| SciTools Understand(商业) | 依赖图/调用树/引用映射 | 重量级付费 IDE,不可脚本化、不入构建流程 |
结论:没有现成成熟工具能直接输出"单一、整工程、可重跑更新"的文件引用关系图,
故按"没有则自写"原则自写解析/建模工具;布局渲染这一难点交给成熟引擎 Graphviz。
本机已通过 winget 安装 Graphviz 16.1.0(安装后 dot 可从 PATH 找到;非标准安装位置用 DTU_GRAPHVIZ_DOT 指向 dot.exe,见 docs/环境与部署/本地工具路径环境变量方案.md)。
2. 生成 / 更新(一条命令)
# 方式一:bat(任意位置可运行)
& 'tools\refgraph\gen_refgraph.bat'
# 方式二:python 直跑(等效)
& '.venv\Scripts\python.exe' tools/refgraph/gen_refgraph.py
项目文件有增删改后,重跑上式即可:产物全量重新生成并覆盖
docs/images/引用关系图.*,对照 引用关系图.json 的文本 diff 即可看出引用面变化,
然后按仓库惯例把(工具 + 产物)一并提交。
可选参数:
| 参数 | 默认 | 说明 |
|---|---|---|
--views full,module |
两者 | 只出文件级 / 只出模块级 |
--edge-scope project|all |
project |
project=仅第一方代码发起的引用边(清晰);all=含第三方内部引用(完整但密集) |
--no-render |
关 | 只出 .dot/.json,不调 Graphviz |
--quiet |
关 | 精简控制台输出 |
3. 产物与图例
| 文件 | 说明 | 是否提交 |
|---|---|---|
引用关系图.svg / .dot |
文件级引用图(项目代码视图) | 是 |
引用关系图_模块.svg / .dot |
模块级概览图(目录/库聚合,边上 ×n=引用条数) | 是 |
引用关系图.json |
结构化数据:全部节点/边/未解析 include 明细 | 是 |
引用关系图.png |
文件级图位图预览(大,~5 MB) | 否(本地预览,可随时重出) |
图例(文件级):
- 节点:蓝=第一方(App/、Inc/、Src/、test/、simulator/〔除 SDL2、build〕、 Drivers/BSP/〔除 NET/lftpd〕);灰=第三方(Lib/、Middlewares/、 Drivers/CMSIS、HAL、lftpd、SDL2);橙=外部/系统头文件聚合节点。
- 边:
蓝实线第一方→第一方;灰实线第一方→第三方;橙虚线→外部/系统头文件(stdio.h 等编译器提供);all模式下另有淡点线=第三方内部引用。
模块级图把第一方按目录模块聚合(App、App/task、BSP/UI、Src/Inc (CubeMX)…)、 第三方按库聚合(LVGL、FreeRTOS、CMSIS、HAL、FatFs、dhara、lftpd、SDL2)。
4. 解析原理(与编译器行为对齐)
- 扫描仓库全部
.c/.h(跳过.git/.venv/MDK-ARM/docs/simulator/build); - 提取每条
#include(处理行尾反斜杠续行;编码按 UTF-8→GBK→Latin-1 兜底); - 解析顺序与编译器一致:所在文件目录 → Keil 工程包含路径(解析自
MDK-ARM/STM32F407-Demo.uvprojx,自动跟随)→ 模拟器 CMake 包含路径 (simulator/CMakeLists.txt,脚本内SIM_INCLUDE_DIRS需手动同步); - 解析到仓库内文件 → 成边;解析不到 → 归"外部/系统头文件"(明细在 JSON
unresolved),与编译器查系统目录的行为一致。 - 刻意不做"基名全库兜底":仓库内存在同名系统头(rapidjson 自带
msinttypes/stdint.h),兜底会把各处<stdint.h>误连到库内部文件产生假边 (曾产生 100+ 条假边,已验证并移除)。
5. 语义与已知限制
- 文本层引用:
#if 0内、MCU/模拟器平台条件下的引用均计入(完整呈现项目引用面); 不评估#if条件 —— 未激活条件内的引用(如LV_USE_DRAW_VG_LITE=0时的vg_lite.h)会显示为"未解析→外部",属预期。 - 仅文件级
#include引用;不含函数级调用关系(如需,可另行用 Doxygen/cflow 补充)。 - 双端(Keil MCU / CMake 模拟器)包含路径合并解析,个别引用是"另一端视角" (如 LVGL 的 SDL2 后端引用),属项目级引用面的如实呈现。
- 第一方/第三方划分规则见脚本头部
classify();lftpd 为移植的第三方组件 (与 AGENTS.md pre-commit 排除名单一致)。
6. 维护
- 新增/移动第一方目录 → 改脚本
classify()、FP_MODULES; 新增第三方库 → 改TP_LIBS(模块级聚合用)。 - Keil 工程包含路径变化:自动跟随(每次运行解析 uvprojx)。
- 模拟器包含路径变化:同步脚本
SIM_INCLUDE_DIRS常量。 - 换机:
winget install Graphviz.Graphviz(渲染依赖;缺失时工具自动跳过渲染, 仍产出.dot)。
7. 当前数据(2026-10-14 刷新)
索引 1495 个 .c/.h;解析 include 5972 条(解析成功 4821,外部/系统 1151,351 种);
第一方文件 215 个;节点 = 第一方 215 + 第三方 1266 + 外部聚合 1;去重边 5176 条。
被引用最多的第一方文件:Drivers/BSP/dbg_log.h(48)、Inc/main.h(33)、
Drivers/BSP/NET/net_socket.h(18)……(完整 Top10 见运行报告)。