longvo92/codegen-compare-tool
GitHub: longvo92/codegen-compare-tool
针对 AUTOSAR/Simulink 代码生成输出进行智能 Diff 对比的工具,自动过滤时间戳和变量重命名等噪声,仅展示真实的语义变更。
Stars: 0 | Forks: 0
# CodeGen 对比工具
[](https://github.com/longvo92/codegen-compare-tool/actions/workflows/test.yml)
[](https://www.python.org/downloads/)
[](LICENSE)
[](https://github.com/longvo92/codegen-compare-tool/releases/latest)
对两个 AUTOSAR 代码生成输出文件夹(MATLAB/Simulink Embedded Coder)进行 Diff 对比,并仅展示**重要的变更**。
重新生成 Simulink 模型会重写时间戳、UUID、注释横幅和自动生成的变量名,即使行为完全相同也是如此。该工具将每个代码块(hunk)分类为*真实变更*或*可忽略变更*,随后提供两种查看结果的方式:一个独立的 **HTML 报告**,在文本 Diff 之上提供 AUTOSAR 级别的摘要;以及一个带有变更缩略图的**并排桌面查看器**。
在同一个对比核心之上构建的两个前端,因此判定结果绝不会因查看方式而异:
| | 用途 | 运行条件 |
|---|---|---|
| [**Viewer**](#side-by-side-viewer) | 交互式查看:文件夹树、双窗格 Diff、缩略图 | 命令行未指定文件夹(或双击 `.exe` 时) |
| [**CLI**](#command-line) | 流水线和脚本 — 生成报告,使用退出代码拦截构建 | 命令行同时指定两个文件夹 |
**对比过程零依赖** — CLI 和 HTML 报告仅需 Python 3.8+ 标准库:无需 pip install,无需服务器,无需互联网访问。[并排查看器](#side-by-side-viewer) 额外需要 PySide6,仅在打开时才会导入。
## 安装
直接从克隆的仓库运行 — 无需安装:
```
git clone https://github.com/longvo92/codegen-compare-tool.git
cd codegen-compare-tool
python -m compare_tool --help
```
或者将其安装为命令(`compare-tool`):
```
pip install git+https://github.com/longvo92/codegen-compare-tool.git
```
对于无法进行任何安装的设备,请参阅[单文件构建](#single-file-build)。
## 快速开始
```
python -m compare_tool [--report out.html]
```
扫描会生成一个独立的 HTML 报告(默认为 `compare_report.html`),可在任何浏览器中打开,并可作为单个文件共享。
如果省略文件夹,则会改为打开[并排查看器](#side-by-side-viewer) — 将两个文件夹拖放到其中即可:
```
python -m compare_tool
```
退出代码:
| 代码 | 含义 |
|---|---|
| `0` | 无真实变更 |
| `1` | 发现真实变更(可用作 CI 拦截) |
| `2` | **对比未完成** — 部分路径无法列出、读取或对比(权限问题、文件被其他进程锁定、长路径等) |
退出代码 `2` 始终会显示:终端中的 `!!`,报告中的红色横幅。`--exit-zero` 无法抑制它。
## 命令行
| 参数 | 含义 |
|---|---|
| `--report out.html` | 报告输出路径(默认为 `compare_report.html`)。在扫描开始前,已存在的文件会被删除 |
| `--exclude PATTERN` | 跳过匹配 glob 的文件(相对路径或纯文件名),可重复使用。例如:`--exclude compare_report.html` |
| `--exit-zero` | 即使存在真实变更也始终退出代码 0(适用于流水线的纯报告模式)。对比错误仍会返回退出代码 2 |
| `--arxml-only` | 仅扫描 `.arxml`/`.xml`/`.a2l` 并生成按类型分类的紧凑报告(默认为 `arxml_update.html`) — 即使无变更也会生成 |
| `--review FILE` | 从审查文件(`codegen-review.json`,由查看器写入)渲染注释和签署记录,将其显示在所属变更旁边,并附带 `Reviewed` 徽章。必须显式指定;与 `--arxml-only` 一起使用时无效 |
| `--qt`, `--viewer` | 在命令行指定文件夹时打开并排查看器,而不是在终端中进行对比。需要 `viewer` 扩展(见下文) |
省略 `old_dir`/`new_dir` 会打开查看器。`--gui`(tkinter 面板)已 在 1.1.0 版本中移除。
## 并排查看器
桌面应用 (PySide6):文件夹树、带缩略图的双窗格 Diff、单次变更审查备注。
```
pip install "codegen-compare-tool[viewer]" # or: pip install PySide6
python -m compare_tool # then drop the folders in
python -m compare_tool --qt # or start loaded
```

完整的操作指南已内置到应用中 — 工具栏中的 `User guide`(`F1`)或 `Release notes` 均可离线使用。独立 `.exe`(无需 Python):请参阅[单文件构建](#single-file-build)。
## 哪些算作噪声
| 类型 | 规则 | 文件 |
|---|---|---|
| `comment` | C 注释 (`//`, `/* */`)、XML 注释 (``) | .c .h .arxml .a2l |
| `rename` | 一致的 1 对 1 变量重命名(MATLAB 自动生成的名称)。映射无法完全解释的任何内容仍视为真实变更 | .c .h |
| `uuid` | `UUID="..."` 属性 | .arxml .xml |
| `timestamp` | `` 块、`` | .arxml .xml |
| `sw-version` | `` 版本戳(每次重新生成时都会递增)。已锚定,因此 `` 等类似项不受影响 | .arxml .xml |
| `whitespace` | 缩进、行尾空格、空行 | 所有 |
| `line-endings` | CRLF 与 LF,BOM | 所有 |
自动生成的名称扰动被识别为 `rename`:诸如 `rtb_*` 的 Embedded Coder 临时变量、混淆后缀以及重新编号的临时变量在不同运行间会发生变化,但不会改变行为。
**注释变更有其独立的类别。** 如果文件的差异*仅*包含注释,则会报告为**Comment**,与**Unimportant**(UUID、时间戳、SW-VERSION、重命名、空白)分开 — 重写的注释横幅与重命名的标识符在分类上是不同的。CLI 摘要中有独立的计数,查看器中有其专属的树标记和颜色(紫色与黄色)。如果文件中混合了注释*以及*其他噪声,则仍归为 Unimportant。HTML 报告保留判定结果,但不显示注释内容 — 请参阅 [HTML 报告](#html-report)。
## 移动块检测
在一个位置被删除并在其他位置完整重现的代码块(当模型发生变化时,Embedded Coder 会重新排列函数和声明)会被标记为 `moved`,并显示为**蓝色**,而不是红色/绿色。这仍计为**Modified** — 因为重排可能会改变行为 — 只是它比两个巨大的红/绿块更容易查看。
## AUTOSAR 语义摘要
该工具会提取双方的 AUTOSAR 信息,并在**语义**级别(而不仅仅是文本)报告变更:
| 来源 | 提取内容 | 报告内容 |
|---|---|---|
| `.arxml`/`.xml` | **端口接口** (SENDER-RECEIVER, CLIENT-SERVER, MODE-SWITCH, NV-DATA, PARAMETER, TRIGGER) 及其完整的包路径 | 已添加 / 已移除 |
| `.arxml`/`.xml` | **SWCs** (APPLICATION, SENSOR-ACTUATOR, SERVICE, CDD, ECU-ABSTRACTION, NV-BLOCK) | 已添加 / 已移除 |
| `.arxml`/`.xml` | SWC **端口** (P/R/PR + 引用的接口)、**runnables** (+ SYMBOL)、**事件** (类型, PERIOD, 触发的 runnable) | 已添加 / 已移除 / **已变更** (例如 TIMING-EVENT 周期从 `0.01s → 0.02s`,或端口指向了不同的接口) |
| `.c` | **RTE 访问点** — 每个 `Rte_Read/Write/Call/IrvRead/IrvWrite/Mode/Switch/…` 调用(计数前会剥离注释) | 已添加 / 已移除 |
| `.a2l` | **标定对象** — 按名称分类的 `CHARACTERISTIC` / `MEASUREMENT`(优先剥离注释和字符串,因此被注释掉的块不会被计数) | 已添加 / 已移除 |
展示方式:
- **CLI**:`ARXML interfaces`、`AUTOSAR behavior`、`RTE access points` 和 `A2L objects` 块会列出带有各自所属文件的 `+`/`-`/`~` 条目。
- **HTML 报告**:页面顶部的 **AUTOSAR changes** 部分,按类型分组(端口接口 / 软件组件 / 端口 / runnables / 事件 / RTE 访问点 / A2L 特性和测量值)。点击文件名可跳转到其详细的 Diff,且详细变更中的每个文件都会带有其专属的 `Interfaces:` / `Behavior:` / `RTE:` / `A2L:` 备注。
- 整体添加或删除的文件,会将其中包含的所有接口 / SWC / RTE 调用 / A2L 对象计为已添加或已移除。
XML 解析失败的文件将被排除在此摘要之外(但其文本 Diff 仍会完整显示)。未知的 `Rte_` 调用不会在此处计数,但依然会出现在 Diff 中。
## 按模型 / SWC 分组
文件会使用 Embedded Coder AUTOSAR 命名约定(`X.c`、`X.h`、`X.arxml`、`Rte_X.h`、模块化 ARXML 集等)按 **Simulink 模型**进行分组。不匹配任何模型的文件将归入最后的 **Shared / other** 组。
## HTML 报告
每次对比生成一个独立的文件:包含徽章切换、文件夹树、过滤框以及每个文件的可折叠 Diff。默认隐藏 `Unimportant` 并展开 `Modified`,以便直接聚焦于重要内容。

## CI 集成
作为流水线关卡运行 — 一条命令,有意义的退出代码:
```
python -m compare_tool old_dir new_dir --exit-zero --exclude compare_report.html
```
`--exit-zero` 可确保在重新生成的代码上保持构建通过;`--exclude` 可防止将上一次运行的报告计入 Diff。请将 `compare_report.html` 发布为构建产物。
有关具体示例,请参阅 [azure-pipelines.yml](azure-pipelines.yml)(OLD 通过 `git worktree` 检出,NEW 为工作树)。
## 单文件构建
```
.\build.ps1 # dist\compare-tool.exe - one file, nothing to install on the target
.\build.ps1 -Pyz # also dist\compare_tool.pyz (~26 KB) for machines that have Python 3.8+
.\build.ps1 -PyzOnly # zipapp only (building it needs no PyInstaller / PySide6)
```
`dist\compare-tool.exe` 是**一个集成了两个前端的二进制文件**,并带有该工具专属的图标:
| 调用方式 | 结果 |
|---|---|
| `compare-tool.exe [flags]` | CLI:扫描,生成 HTML 报告,退出代码为 `0`/`1`/`2` |
| `compare-tool.exe --qt ` | 并排查看器,自动加载指定的文件夹 |
| 双击(无参数) | 并排查看器,等待放入两个文件夹 |
它作为**控制台**应用程序构建,因此终端运行可以保留其退出代码(`1` = 真实变更,`2` = 对比未完成)供 CI 关卡使用。查看器在运行时会隐藏控制台窗口 — 双击时您会看到短暂闪烁。如果发生崩溃,控制台将取消隐藏,以便查看错误。
- **`.pyz` (zipapp, 标准库)**:`python compare_tool.pyz [flags]`。当有 Python 环境时首选此方式 — 大小约 26 KB,无构建依赖,不会被杀毒软件标记。CLI 可在任何地方运行;查看器额外需要该机器上安装有 PySide6(若未安装,工具会给予提示而不是直接打开)。
- **`.exe` (PyInstaller onefile, ~47 MB)**:目标机器上无需 Python。构建过程需要开发机上安装有 `pyinstaller` 和 `PySide6`(`build.ps1` 会安装它们),并且生成的二进制文件只能在构建它的操作系统上运行。PyInstaller 可执行文件有时会被杀毒软件或 AppLocker 拦截 — 在这种情况下,请退而使用 `.pyz`。
所有 CLI 参数在打包构建版本中的行为完全一致。`build/` 和 `dist/` 已经包含在 `.gitignore` 中。
## 开发
```
python -m unittest discover -s tests
```
CI 会在 Linux 和 Windows 上针对 Python 3.8 和 3.11 运行测试套件,此外还会对 fixture 树进行无头扫描,以检查报告和退出代码。
```
compare_tool/
├── main.py # entry point: picks the CLI or the viewer, run_compare() core
├── resources.py # finds the shipped icons/logo, in a checkout and in the .exe
├── qtviewer/ # PySide6 side-by-side viewer (app, diff pane, minimap, dialogs)
├── scanner.py # walks both trees, pairs files by relative path
├── diff_engine.py # two-pass diff (raw + normalized), hunk classification, moved-block detection
├── c_rules.py # C/H rules: strip comments, tokenize, detect renames, extract RTE access points
├── arxml_rules.py # ARXML rules: UUID, ADMIN-DATA, DATE, comments + extract port interfaces, SWCs (ports/runnables/events)
├── a2l_rules.py # A2L rules: strip C-style comments + extract CHARACTERISTIC/MEASUREMENT
└── report.py # self-contained HTML report (badge toggles, model overview, grouping, filter, collapsible diffs)
```
添加规则的方法:在c_rules.py` / `arxml_rules.py` 中编写过滤函数,然后将其注册到 shadow builder 以及 `diff_engine.py` 中的 `_build_variants`。
欢迎提交 Issues 和 pull requests。请保持**对比核心仅使用标准库** — 它必须在锁定的构建服务器上运行,因此 PySide6 仅限于保留在 `compare_tool/qtviewer/` 中,且仅在查看器打开时才导入 — 并且请在 `tests/` 下为任何新规则添加测试。
## 作者
**Long Vo Thien**
## 许可证
基于 [MIT License](LICENSE) 发布 © 2026 Long Vo Thien。
标签:AUTOSAR, HTML报告, Python, Simulink, SOC Prime, 代码对比, 代码生成, 开发工具, 无后门, 渗透测试工具, 漏洞挖掘, 逆向工具