Xcode 中的 Compilation Mode 是管什么的
“Build Settings > Swift Compiler — Compilation Mode” 到底管什么?
选项 | Xcode UI 中的名字 | 对应编译器参数 | 适用场景 | 优缺点 |
---|---|---|---|---|
Incremental(默认) | Incremental/Single File | -incremental | Debug 构建、反复改代码时 | 只重新编译受影响的 .swift 文件,迭代最快;但编译器只能在文件级做优化,某些边缘 Bug 只在此模式触发 |
Whole Module | Whole Module | -whole-module-optimization (WMO) | Release 构建、需要跨文件优化时 | 编译器一次性把整个模块读进来,能做跨文件内联等深度优化,最终二进制更小/更快;但每次修改都要全量编译,调试周期慢 |
Automatic(Xcode 13 以后出现的 UI) | Default | Xcode 根据 Build Configuration 决定:Debug → Incremental,Release → Whole Module | 大多数项目保持默认即可 | 省心,但遇到编译崩溃时可能需要手动切换 |
⚙️ 底层开关就是
SWIFT_COMPILATION_MODE
,可以在 Build Settings、.xcconfig
,或用
xcodebuild SWIFT_COMPILATION_MODE=wholemodule
覆盖。
该设置只决定 “一次编译多少文件”,与SWIFT_OPTIMIZATION_LEVEL
(-Onone/-Osize/-O
) 是两件事。
详细背景可见这篇总结 ✍️ Compiler Optimizations, Compiling Optimally, and Whole Modules(gist.github.com)
看下这个帖子
Abort trap 6 error: https://developer.apple.com/forums/thread/123426
在这个帖子 “Xcode 11: build fail, Abort trap 6” 中,多位开发者遇到了 Incremental 模式下编译崩溃(序列化 SIL 时触发 Abort trap: 6
)。有人把 Compilation Mode 从 Incremental 切到 Whole Module 后就能先成功编译,证明问题和 Incremental 编译过程有关(developer.apple.com)。
最终楼主找到根因:
- Bridging Header 里
#import "A.h"
写成了相对路径,Incremental 编译会在每个文件中单独处理 Bridging Header,这个不完整的路径导致某些编译阶段内部状态不一致,从而在序列化阶段崩溃。 - Whole Module 编译只处理一次 Bridging Header,没有踩到同一条崩溃路径,所以能“暂时绕过”。
也就是说 Compilation Mode 本身不是 bug,
但不同模式触发了编译器处理流程的差异,暴露/隐藏了你的头文件路径错误。
当你把#import "A.h"
改成#import "A/A.h"
(或直接用模块化的@import
)后,无论是 Incremental 还是 Whole Module 都能正常工作。(developer.apple.com)
什么时候需要手动调整 Compilation Mode?
-
调试编译器问题
- 如果 Incremental 挂掉,先切 Whole Module 证明代码是否干净;
- 反之,Whole Module 崩溃而 Incremental 正常,也可以倒推问题。
-
编译性能权衡
- 大型项目 Debug 编译太慢 → 试着保持 Incremental,并按 WWDC 22《Demystify parallelization in Xcode builds》的建议拆 target、减少依赖。
- 小型/脚手架项目 Release 构建占用时间不敏感 → 直接 Whole Module,获取更佳运行性能。
-
CI 或 SwiftPackageManager/CMake 等外部构建系统
指定SWIFT_COMPILATION_MODE
保持行为一致,避免 CI 与本地不同带来的“works on my machine”。
小贴士
// Debug.xcconfig
SWIFT_COMPILATION_MODE = incremental
SWIFT_OPTIMIZATION_LEVEL = -Onone// Release.xcconfig
SWIFT_COMPILATION_MODE = wholemodule
SWIFT_OPTIMIZATION_LEVEL = -Osize // 或 -O
不要同时开启 wholemodule
+ -Onone
又期待获得运行时优化;
也不要在 Debug 用 wholemodule
却抱怨每次改动都全量编译——这正是设计行为。
总结
“Compilation Mode” 决定 Swift 编译“并行多少份工作 VS 能做多深的跨文件分析”。
帖子中的崩溃只是 Incremental 模式暴露出的头文件问题,而切换到 Whole Module 只是绕过症状,真正的修复是确保 Bridging Header 路径正确。