Files
scuc-qt-course/HANDOFF.md
T
张宗平 13b3ebbe14 课程代码仓库初始化:Part1 (144) + Part3 (29) 全量生成与验证
把川大 wiki「02.Qt方向」课程代码整理为 CMake 管理的可编译运行项目。

Part1 C/C++ 强化 (p01/, 144 目标, host gcc/g++ 构建, 全绿):
- 修复全部编译失败:补 <cstring>/<fstream>/<iomanip>/<vector> 等缺失头
  (common_fix + infer_stl_includes 自动检测注入)、修正 pause() 壳注入
  (改检测已转换后的 pause 调用)、namespace 提升出函数体、const 成员函数
  正确性、dedupe 不再破坏函数重载集、K&R 隐式 int / 动态异常规范等
  C++17 移除特性的可编译等价改写。
- 目录采用深缩写 p01/ch04/s03/ (原 part1_cpp/ch04_class_object/03_ctor_dtor)。

Part3 Qt 桌面 (p03/, 29 目标, 隔离 Qt 5.14.2 构建, 全绿):
- gen_part3.py: Qt 外壳模板 (main+QApplication+show, QTimer 自动退出便于
  offscreen 验证)、AUTOMOC + .moc include、rewrite_* 处理散文混入/重载/
  资源依赖、生成占位 png/gif + .qrc + rundata 样例数据。
- 修正 QLable 笔误、全角分号、.→->、Windows 路径、QApplication 阻塞事件
  循环改为 QCoreApplication 等。

任务1 概念/版本验证:
- tools/std_probe.py: 跨 -std= 编译探针 (--pedantic-errors 让已废除特性硬失败)。
- tools/demo_versions/: K&R 隐式 int、三目左值、void* 转换、enum 赋整、
  const 经指针、动态异常规范 共 6 个跨版本演示。
- docs/VERSION_NOTES.md: 每条「原文说法→C17/C++17 是否成立→何版本成立→已验证」。

文档: 顶层 README、docs/SOURCE_PAGES.md (页面→目录映射)、
docs/ERRATA.md (Part1 修正)、docs/ERRATA_part3.md (Part3 修正)。
另修复 tools/run.sh / run_qt.sh 的 ${1:?...} 引号语法 bug。

隔离 Qt 验证: ldd 0 系统 Qt 引用; 173/173 目标全绿; p03 offscreen 运行通过。
2026-06-30 14:16:55 +08:00

211 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HANDOFF — qt-course 课程代码仓库生成/验证 续接手册
> 本手册供「新开会话」从当前进度继续。读完即可无缝接手。
> 仓库路径:`/home/charles/workspaces/qt-course`
> 上次工作会话日期:2026-06-30
---
## 0. 任务总目标(来自用户原始需求)
从川大 wiki「02. Qt 方向」(需登录 scuc/scuc2025) 提取 QT 方向页面,完成 3 件事:
0. **按章节+话题组织课程代码仓库**,用 CMake 项目管理,每个可执行文件 = 一个独立 `add_executable` 目标;为 Qt 示例准备一套**与主系统隔离**的 Qt 5.14.x 开发环境;示例之间相对隔离。
1. **验证所有示例代码**在原文所述语言(C 或 C++,先按 C17/C++17)下仍能编译通过、概念仍符合当前标准;不符的确认在何版本成立并编译验证;提供「快速演示不同版本对概念支持」的机制。
2. **修正示例代码错误**并演示。
用户后续追加的关键指令:
- 源文件名用**英文**,与章节名匹配;同小节多文件用语义后缀区分。
- 目录约定:`02 Qt方向`为顶层(不编号);`01 C++技术强化及提升`等视为「章」;其下编号子项视为「节」。
- 目录用**深缩写**`p01/ch04/s01/` 这种形式。(**尚未应用**,见 §5)
- 容器方案用「构建容器」:容器编译、宿主机运行;或带 GUI 的容器。
---
## 1. 当前完成度(截至上次会话末)
| 项 | 状态 |
|---|---|
| 抓取解析 35 个 wiki 页面、218 个代码块 | ✅ 完成 |
| 仓库骨架(顶层 CMakeLists、.gitignore、tools/、docs/ | ✅ 完成 |
| **隔离 Qt 5.14.2 安装**`.qt514/`aqtinstall 装在仓库内) | ✅ 完成 |
| 验证隔离有效:`ldd` 0 系统 Qt 引用、offscreen 运行打印 5.14.2 | ✅ 完成 |
| Docker 构建/安装/运行脚本(构建容器模型) | ✅ 完成(轻量 builder 镜像已构建) |
| Part1 C/C++ 源码 + CMakeLists 生成器 | ✅ 可运行(`tools/gen_part1.py` |
| Part1 英文文件名映射表(`tools/file_name_map.py`) | ✅ 完成,113 节全覆盖 |
| Part1 全部编译通过 | ⚠️ **未完成**144 个目标,剩 4 个 FAILED |
| Part3 Qt 源码/CMakeLists/.qrc 生成 | ❌ **未开始** |
| Qt 示例构建运行验证 | ❌ 未开始 |
| `std_probe.py` + 多版本演示 + VERSION_NOTES.md | ❌ 未开始 |
| 各章 README、SOURCE_PAGES.md、最终 clean build、git 提交 | ❌ 未开始 |
**git 状态**:仓库已 `git init`,但**尚未任何提交**(0 个 tracked 文件,所有内容 untracked)。
---
## 2. 仓库当前布局
```
qt-course/
├── CMakeLists.txt # 顶层:C17/C++17 严格、option(BUILD_QT_PART)、隔离 Qt 版本断言
├── .gitignore # 排除 build/ .qt514/ .venv-aqt/ 等
├── tools/
│ ├── gen_sources.py # 共享引擎:标题解析 page_outline()、语言判定 classify_lang()、common_fix()
│ ├── gen_part1.py # Part1 生成器(含 exact_fix、block_classify、wrap_statements、emit_console
│ ├── file_name_map.py # (pageId, section_title) → 英文文件名词根(113 条,全覆盖)
│ ├── run.sh / run_qt.sh # 宿主机运行 part1 / Qt 目标(LD_LIBRARY_PATH 隔离)
│ ├── install_qt_host.sh # 宿主机直装 Qt 5.14.2 到 .qt514/venv+apt
│ ├── docker/ # Dockerfile + docker_build_image/install_qt/build.sh
│ └── wiki_data/ # 抓取的 wiki 正文+代码块(已拷入,生成器输入)
├── docs/
│ └── ERRATA.md # 已记录 30 处修正(自动生成)
├── part1_cpp/ # 已生成 144 个目标(17 个 dir)
└── part3_qt_desktop/ # 空目录,待生成
```
**Part1 当前目录形**(待用户要求改为深缩写,见 §5):
`part1_cpp/ch04_class_object/03_ctor_dtor/ctor_and_dtor.cpp` 等。
---
## 3. 已验证可用的关键命令
```bash
cd /home/charles/workspaces/qt-course
# 重新生成 Part1 全部源码 + CMakeLists(幂等;每次改生成器后先 rm -rf part1_cpp
rm -rf part1_cpp build && python3 tools/gen_part1.py
# 在宿主机配置+构建 Part1(无需 Qt)
cmake -S . -B build -G Ninja -DBUILD_QT_PART=OFF -DCMAKE_BUILD_TYPE=Debug
cmake --build build
# 构建/运行 Qt 部分(需先装隔离 Qt;见下)
cmake -S . -B build -G Ninja -DBUILD_QT_PART=ON \
-DCMAKE_PREFIX_PATH=$PWD/.qt514/5.14.2/gcc_64 -DCMAKE_BUILD_TYPE=Debug
cmake --build build
LD_LIBRARY_PATH=$PWD/.qt514/5.14.2/gcc_64/lib ./tools/run_qt.sh <target> # 或直接 ./tools/run_qt.sh
# 装/重装隔离 Qt 5.14.2(宿主机,一次性)
tools/install_qt_host.sh
# 或用容器装:tools/docker/docker_install_qt.sh(需先 tools/docker/docker_build_image.sh
```
**隔离 Qt 核心事实**(已验证):靶机=gcc13+glibc2.39;容器与宿主机同栈;二进制容器编译宿主机运行;`.qt514` 是唯一真相源;`ldd` 0 系统 Qt 引用;`QT_QPA_PLATFORM=offscreen` 可无 X 运行验证。
---
## 4. Part1 剩余 4 个 FAILED 目标(接手第一件事)
最近一次构建:`FAILED: 4 | Linked: 0`,剩余唯一错误类:
| 失败目标 | 文件 | 根因 |
|---|---|---|
| p1c03_42 | part1_cpp/.../function_overload_basics_2.cpp | dedupe 把重载 `MyFunc` 改名 `MyFunc_2` 后,`MyFunc_2("hello")` 调用对 `MyFunc_2(int)` 和另一重载产生歧义(dedupe 重命名破坏了重载集) |
| p1c03_43 | part1_cpp/.../function_overload_basics.cpp | `namespace` 定义在函数体内(同 block 3/6/7 问题,需在 exact_fix 补 58954439:41/42 的 namespace 提升修正) |
| p1c04_03_01 | .../03_ctor_dtor/ctor_and_dtor.cpp | `strcpy` 未声明:C++ 用 iostream 前言但 wiki 块含 `strcpy`,需补 `<cstring>` |
| p1c04_03_04 | .../03_ctor_dtor/deep_vs_shallow_copy.cpp | 同上:`strcpy`/`strlen` 未声明,补 `<cstring>` |
**建议修法**(在 `tools/gen_part1.py``exact_fix(pid,idx)` 里):
1. **`strcpy`/`strlen` 类**:对 ch04 块(pid 58954451 等),若 code 含 `strcpy`/`strlen`/`strcmp` 等而无 `<cstring>`/`<string.h>`,在 `common_fix``exact_fix` 里补 `#include <cstring>`C++)或 `<string.h>`C)。建议加到 `gen_sources.py``common_fix` 通用补头(类似 NBSP 修复)。
2. **namespace-in-function (block 41/42)**:仿照已写好的 block 3/6/7 的 `exact_fix`,把 `namespace` 定义提到文件作用域。
3. **dedupe 破坏重载集 (block overload_basics_2)**:去重逻辑对**同一块内**的重载不应改名;当前 `dedupe_functions` 跨块去重是为了同名不同块变体。需让 dedupe 只对「同名且跨块」改名,块内多个同名重载视为同一组用序号区分——或更稳妥:函数重载演示块整体改名前先识别是重载集(同名不同参数),统一改名 `MyFunc``MyFunc_<n>` 并同步调用点。已属复杂边界,可单独为 58954439:41/42 写 exact_fix 直接给可编译版本。
**每处修正都要 `record_erratum(...)`** 以自动进 `docs/ERRATA.md`(已有 30 条,结构见现有条目)。
修法后:`rm -rf part1_cpp build && python3 tools/gen_part1.py && cmake -S . -B build -G Ninja -DBUILD_QT_PART=OFF && cmake --build build` 应全绿(144 目标全 Linking executable)。然后即可进 Part3。
---
## 5. 待应用:深缩写目录 `p01/ch04/s01/`(用户明确要求,最后统一改)
用户要求目录形如:`p01/ch04/s01/`part 缩写 pNN / 章缩写 chNN / 节缩写 sNN)。
当前是 `part1_cpp/ch04_class_object/03_ctor_dtor/`
**改法**(在 `gen_part1.py``PAGE_CONFIG` 里把 `dir` 值统一改为深缩写;或在 `main()` 拼接 `out_dir` 处做映射):
- `part1_cpp``p01`
- `ch04_class_object``ch04`
- `01_basic_concepts``s01``02_oo_case``s02`,……
- `ch03_cpp_extends_c``ch03`,等等。
- 主顶层 `CMakeLists.txt``add_subdirectory(part1_cpp)``add_subdirectory(p01)`
- 同步更新 `tools/run.sh` / 任何写死 `part1_cpp` 的地方。
- Part3 同理 `part3_qt_desktop``p03`
**映射依据**`PAGE_CONFIG` 里每个 pageId 的 `dir` 和 wiki 树结构 (`tools/wiki_data/qt_full_tree.json`),可脚本一次性生成 `p NN`/`ch NN`/`s NN` 编号。建议在生成目录的最后统一替换,不破坏 `file_name_map.py`(文件名映射与目录无关,仍按 (pageId, section))。
---
## 6. Part3 Qt 续接要点(接手第二件大事)
**输入**`tools/wiki_data/extracted_code.json` 中 9 个 Qt 页面 pageId5895451558954552),共 73 个代码块。
**已勘察分类**codex subagent 已做,结论在上次会话):
- 3 个完整程序(含 main+QApplication,直接成目标)
- 2 个 Q_OBJECT 类定义(需 moc → 开 AUTOMOC
- 28 个可加 harness 块(包 main+QApplication+show,部分需补 Widget 类骨架)
- 40 个纯签名/单语句(折进各章 README 作文档,不单独建目标)
**已知的 Qt 代码修正点**subagent 已列):
- 笔误:`QLable``QLabel``.``->`、全角```;``"D:\ndrawing.pic"``"D:/drawing.pic"`、类后缺 `;`
- `tr()` 在非 QObject 上下文(main) 不可用 → `QObject::tr`/`QStringLiteral`
- 资源依赖:`:/images/*.png``:/Image/boat.jpg``:/Mario.gif``:/Image/butterfly*.png``in.txt`/`file.dat`/`file.txt` → 各自生成占位文件 + `.qrc`CMake `qt5_add_resources()`
- 过时 APIQt5.14 仍可用,保留并记 VERSION_NOTES):`QMouseEvent::x()/y()``QString::sprintf`、Qt4 `SIGNAL/SLOT``static_cast` 重载解析(Qt6 起弃用)
**生成器骨架**:仿 `gen_part1.py``gen_part3.py`,复用 `gen_sources.py``page_outline`/`classify_lang`(已含 Qt 检测)/`common_fix`,但:
- emit 用 Qt 模板:`#include <QApplication>` 等、`QApplication app(...)``w.show()``return app.exec()``QT_QPA_PLATFORM=offscreen` 时设 `QTimer::singleShot` 让程序自动退出。
-`AUTOMOC`(顶层 CMakeLists 已统一开,但建议在 part3 各目标的子 `CMakeLists``set(CMAKE_AUTOMOC ON)`)。
- 资源目标:需 `.qrc` + 占位 png(用工具生成纯色小 png 即可,不依赖原图)。
- 语言全是 C++(`.cpp`)。
- 英文文件名映射表 `file_name_map.py` 里目前**只有 Part1**Part3 需新增 pageId 5895451558954552 的映射(约 1625 个 section)。
**验证**Docker 容器构建 → host offscreen 运行(`QT_QPA_PLATFORM=offscreen ./tools/run_qt.sh <target>`),用 `QTimer` 自动退出、捕获 stdout/退出码确认。需 X 真窗时给 DISPLAY。
---
## 7. 任务1「概念/版本验证」+ 任务1机制(接手第三件)
用户要「快速演示不同版本支持」。已规划:
- `tools/std_probe.py`:输入片段+标准列表(c89/c99/c11/c17/c23、c++11/14/17/20/23),逐个 `gcc/g++ -std=..` 编译,报 pass/fail+警告。host gcc13 原生支持全部。
- `tools/demo_versions/`:针对 wiki 有版本论断的片段做跨版本对比:K&R 隐式 int、三目返左值(C++独有)、`const int` 改写差异、enum 赋整/`char* p=malloc` 不强转(C vs C++)。
- 结果汇总进 `docs/VERSION_NOTES.md`:每条「文中说法→当前 C17/C++17 是否仍成立→不成立在何版本成立→已编译验证」。
**已知版本相关论断**(来自 Part1 已修的 exact_fix):
- K&R 隐式 int(块 58954439:14)→ C89 成立,C99 起非法
- 三目运算符返左值(块 18)→ C++ 独有
- `const int` 经指针改写 → C/C++ 行为差异
- enum 赋整 / `char* p=malloc` 不强转(块 15)→ C 合法 C++ 报错
- `system("pause")` 平台依赖(已在 common_fix 修为便携 pause()
---
## 8. 接手后立即应做的最小步骤
1. 读本手册 + `tools/gen_part1.py` + `tools/gen_sources.py` 了解生成器。
2. 修 Part1 剩余 4 个 FAILED(§4):补 `<cstring>`、namespace 提升 41/42、dedupe 重载集。重建到 144/144 全绿。
3. 应用深缩写目录(§5):改 `PAGE_CONFIG` 的 dir 为 p/ch/s,全量重建确认路径。
4.`gen_part3.py` + 扩 `file_name_map.py`;生成 Part3Docker/host 构建;offscreen 运行验证。
5.`std_probe.py` + `tools/demo_versions/`;填 `docs/VERSION_NOTES.md`
6.`docs/SOURCE_PAGES.md`(pageId→章节映射表)、各章 README、顶层 README。
7. 全量 clean build`git add -A && git commit`(**目前 0 提交,务必最后提交一次**)。
---
## 9. 关键约束/红线
- **不修改** `tools/wiki_data/` 中的原始抓取数据(生成器输入,保持原貌)。
- 每处对 wiki 代码的修正都要 `record_erratum()``docs/ERRATA.md`(透明可审计)。
- 源文件名英文;CMake 目标名 ASCIICMake 禁非 ASCII 目标名——已踩坑并修好)。
- 隔离 Qt:构建/运行一律走 `.qt514/``-DCMAKE_PREFIX_PATH` + `LD_LIBRARY_PATH`),**不碰系统 Qt 5.15**;顶层 `CMakeLists.txt` 有版本断言(迷连系统 5.15 会 FATAL_ERROR)。
- 不要对 wiki 数据做多块「合并」造符号冲突——已踩坑:跨块同名符号会重定义;最终采用「每块一文件」+ 必要时 `exact_fix` 补前向声明(如 `Person`)。
---
## 10. 上次会话犯过、勿重犯的坑
- `ERRATA``gen_sources.py` 模块级可变列表,`record_erratum` 追加到该列表;`gen_part1.py` 必须 `import gen_sources; ERRATA = gen_sources.ERRATA`(早期误用 `from ... import ERRATA` 独立拷贝导致 write_errata 看到空列表)。
- `block_classify``decl_re` 必须**排除**裸调用 `printf(...);`(无返回类型前缀不算声明),否则语句片段被误判 groupdecl;且要**允许**单独 `{`/`}` 行(namespace 块边界),否则纯 namespace 声明块被误判 statements 进而被包进函数体内(namespace 不能在函数内)。
- `dedupe_functions` 跨块改名会**破坏函数重载集**(块内多个同名重载不应逐个改名)。修 §4 时注意。
- `common_fix` 已含:NBSP→空格、全角分号/引号→半角、`system("pause")``pause()`。再加:`strcpy/strlen` 等补 include 即可(勿重复已有逻辑)。
- `ast.parse` 能过不代表运行正确:函数嵌套/作用域错误会跑到运行才炸。改生成器后务必实跑一遍 `python3 tools/gen_part1.py` 看是否抛异常。
- grep `-c``-E` 混用会 `conflicting matchers`;本会话多次踩,请用单一 matcher 或 `python3 -c` 数。
(手册结)