# HANDOFF — qt-course 课程代码仓库生成/验证 续接手册

> 本手册供「新开会话」从当前进度继续。读完即可无缝接手。
> 仓库路径：`/home/charles/workspaces/qt-course`
> 上次工作会话日期：2026-06-30（**全部完成**，已首次 git 提交）

---

## ⚠️ 当前状态：全部完成（2026-06-30 第二次会话）

本会话已把 HANDOFF §1 中所有「未完成」项做完。仓库已首次提交
（commit `13b3ebb`，287 文件）。**后续会话主要做维护/扩展，不需重做以下工作。**

- Part1：144/144 全绿（原剩 13 个 FAILED 已全部修复，见 §4 新增的修正清单）。
- 目录深缩写已应用：`p01/ch04/s03/` 形式。
- Part3 Qt：29 目标全绿，offscreen 运行验证通过。
- 任务1 版本机制：`std_probe.py` + `demo_versions/`(6 个) + `VERSION_NOTES.md`。
- 文档：顶层 README、SOURCE_PAGES.md、ERRATA.md / ERRATA_part3.md。
- 修复了 `run.sh` / `run_qt.sh` 的 `${1:?...}` 引号语法 bug。

> 重新生成命令（幂等）：`rm -rf p01 p03 build && python3 tools/gen_part1.py && python3 tools/gen_part3.py`

> ⚠️ **下文 §1–§10 为过程记录，未随本次完成同步重写**：其中出现的旧目录名
> （`part1_cpp/`、`part3_qt_desktop/`）、旧状态（Part3「未开始」等）及 §3 的旧重生成
> 命令均已**过时**。一切以本 banner、`README.md`、当前仓库实际目录（`p01/`、`p03/`）为准。
> 2026-06-30 第三次会话已对全仓库脚本指引与 wiki 引用做端到端核实，结论：README 脚本全部
> 有效、173 目标全绿、92 条 ERRATA 引用与实时 wiki 一致（详见本次会话记录）。

---

## 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 | ✅ 完成 |
| 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 状态**（此表为历史快照，已被后续提交超越）：首次提交为 `13b3ebb`（287 文件）；
截至 2026-06-30 已有多次提交，HEAD 在 main 分支，工作区干净。以 `git log` 为准。

---

## 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 + Qt Creator 4.11.0 到 .qt514/
│   └── wiki_data/          # 抓取的 wiki 正文+代码块（已拷入，生成器输入）
├── docs/
│   ├── ERRATA.md           # Part1 代码修正记录（自动生成，72 条）
│   ├── ERRATA_part3.md     # Part3 Qt 代码修正记录（自动生成，20 条）
│   ├── SOURCE_PAGES.md     # pageId→章节映射表
│   └── VERSION_NOTES.md    # 版本相关概念验证记录
├── p01/                    # Part1：已生成 144 目标，深缩写 chNN/sNN（17 个 dir）
└── p03/                    # Part3：已生成 29 目标，深缩写 chNN/sNN
```

**实际目录形**（深缩写已应用，见 §5）：`p01/ch04/s03/ctor_and_dtor.cpp` 等。

---

## 3. 已验证可用的关键命令

```bash
cd /home/charles/workspaces/qt-course

# 重新生成全部源码 + CMakeLists（幂等；每次改生成器后先 rm -rf p01 p03）
rm -rf p01 p03 build && python3 tools/gen_part1.py && python3 tools/gen_part3.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（宿主机，一次性；同时装 Qt Creator 4.11.0）
tools/install_qt_host.sh
```

**隔离 Qt 核心事实**（已验证）：`.qt514` 是唯一真相源；`ldd` 0 系统 Qt 引用；`QT_QPA_PLATFORM=offscreen` 可无 X 运行验证。学生主要用 Windows，构建/运行方案不引入 Docker。

---

## 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 页面 pageId（58954515–58954552），共 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()`
- 过时 API（Qt5.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 58954515–58954552 的映射（约 16–25 个 section）。

**验证**：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`；生成 Part3；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 目标名 ASCII（CMake 禁非 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` 数。

（手册结）