课程代码仓库初始化: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 运行通过。
This commit is contained in:
张宗平
2026-06-30 14:16:55 +08:00
commit 13b3ebbe14
287 changed files with 16532 additions and 0 deletions
+211
View File
@@ -0,0 +1,211 @@
# 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` 数。
(手册结)