# 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 | ✅ 完成 | | 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 状态**(此表为历史快照,已被后续提交超越):首次提交为 `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 到 .qt514/(venv+apt) │ ├── docker/ # Dockerfile + docker_build_image/install_qt/build.sh │ └── 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 # 或直接 ./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`,需补 `` | | p1c04_03_04 | .../03_ctor_dtor/deep_vs_shallow_copy.cpp | 同上:`strcpy`/`strlen` 未声明,补 `` | **建议修法**(在 `tools/gen_part1.py` 的 `exact_fix(pid,idx)` 里): 1. **`strcpy`/`strlen` 类**:对 ch04 块(pid 58954451 等),若 code 含 `strcpy`/`strlen`/`strcmp` 等而无 ``/``,在 `common_fix` 或 `exact_fix` 里补 `#include `(C++)或 ``(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_` 并同步调用点。已属复杂边界,可单独为 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 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)。 **验证**:Docker 容器构建 → host offscreen 运行(`QT_QPA_PLATFORM=offscreen ./tools/run_qt.sh `),用 `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):补 ``、namespace 提升 41/42、dedupe 重载集。重建到 144/144 全绿。 3. 应用深缩写目录(§5):改 `PAGE_CONFIG` 的 dir 为 p/ch/s,全量重建确认路径。 4. 写 `gen_part3.py` + 扩 `file_name_map.py`;生成 Part3;Docker/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` 数。 (手册结)