*Release 下保留调试符号¶
这页也是明确的进阶内容,因为它讨论的不是“怎么写战术”,而是比赛工程里一个非常现实的折中方案:尽量保持 Release 运行形态,但同时保留足够的符号,让 C++ 仍然可以调试。
目标从来不是“完整 Debug 构建”¶
当前项目并没有把日常主工作流切成那种传统、完整、重依赖的 Qt Debug 套件模式。它走的是另一条更适合比赛工程的路:
主体尽量仍按 Release 方式运行,但通过编译和链接选项保留可用的调试信息。
这个取舍背后的动机其实非常实际:
- 不想为了日常调试,强依赖完整的 Qt Debug DLL 套件;
- 希望运行环境尽量贴近比赛时真正会跑的那套二进制;
- 但又不能因为追求接近实战,就彻底放弃源码级调试能力。
当前工程是怎么做到这件事的¶
根 CMakeLists.txt 里已经明确加了这些关键选项:
/Od:关闭优化;/Zi:生成调试信息;/DEBUG:链接阶段生成调试信息。
同时,CMakePresets.json 里主预设仍然是 Release。把这两件事放在一起理解,你就会明白当前工程的取向:它并不是在“假装 Release”,而是在有意识地做一种偏 Release 形态、但仍保留 PDB 的构建。
你应该在产物里看到什么¶
正常情况下,构建完成后在 ZBin/ 一类运行目录下,你应该能看到:
Medusa.pdbMedusaCore.pdbClient.pdb
这些符号文件的存在,基本就是 VS Code 或 Visual Studio 能否把断点准确映射回源码的重要前提。
这套方案真正解决了什么问题¶
它最大的价值,不在于让调试体验完美媲美传统 Debug 套件,而在于用更低的维护成本,把“足够好用的 C++ 单步能力”保留在了比赛主工作流里。换句话说,你不需要为了打断点,就把整套运行环境切到一套与比赛形态差别很大的 Debug 版本。
这对比赛工程非常重要。因为很多 bug 只有在更接近真实运行形态时才会暴露,如果调试环境和比赛环境差得太远,排查出来的问题有时反而不具代表性。
但要对它的边界有预期¶
第一,/Od、/Zi 和 PDB 能让你调得动代码,但它们并不意味着体验会和纯 Debug 构建一模一样。跨模块、模板、内联函数以及某些编译器优化边界,仍然可能让单步体验显得没那么丝滑。
第二,很多所谓“断点飘了”的问题,最后并不是符号没开,而是你调到的根本不是最新二进制。比如你改了 MedusaCore.dll 对应源码,却没有重新编译;或者 Python 顶层仍在加载旧的 CppPackage.pyd。这种情况下,就算 PDB 在,也一样会让人误以为调试器出问题了。
第三,在 Python-C++ 混合调试时,别忘了产物同步问题永远比单独调 C++ 更复杂。至少要确认:
CppPackage.pydMedusaCore.dll- 对应的
pdb
是真正同一轮构建出来的一套。
最后记一句最实用的话¶
当前项目的调试思路,不是“先切 Debug 再说”,而是:
在主 Release 工作流里,尽量保留足够的符号和可单步能力。
这正是它适合长期维护、也更适合比赛工程节奏的地方。