关闭SWIFT_WHOLE_MODULE_OPTIMIZATION致重复编译耗时,原因何在?
问题原因及全模块优化的作用解析
这是个挺典型的旧版本Xcode+Swift组合下的构建系统问题,我来一步步拆解:
1. 关闭全模块优化时的编译逻辑与问题根源
当SWIFT_WHOLE_MODULE_OPTIMIZATION设为NO时,Swift编译器采用单文件编译模式:每个Swift源文件会被单独编译成中间文件,再进行链接。
在Xcode 9.2 + Swift 4.0.3这个较早期的组合里,构建系统的依赖跟踪存在bug:
- 对于桥接头文件(
*-Bridging-Header.h),单文件编译时每个Swift文件的编译任务都可能触发一次桥接头文件的预编译检查,旧版Xcode无法正确识别“桥接头文件已经预编译完成”的状态,导致重复执行预编译步骤(你看到的三次就是这么来的)。 - 对于Swift源码本身,构建系统可能因为跨文件依赖的解析错误,误以为某些文件需要重新编译,或者任务调度时重复触发了编译流程,最终出现“编译两次”的情况。
这些重复步骤叠加起来,直接把干净编译的时间拉到了11分钟——毕竟每多一次编译/预编译,都是在消耗额外的CPU和IO资源。
2. 全模块优化(WMO)如何解决问题
开启SWIFT_WHOLE_MODULE_OPTIMIZATION=YES后,编译器切换为全模块编译模式:
- 它会把整个模块内的所有Swift文件作为一个整体来处理,依赖解析只需要做一次:桥接头文件预编译一次就够了,所有Swift源码一次性完成编译,从根源上避免了重复执行构建步骤。
- 同时,全模块编译允许编译器进行跨文件的优化(比如内联跨文件的函数、合并重复的符号处理等),整体编译效率比单文件模式高得多,这也是耗时从11分钟降到150秒的核心原因之一。
额外补充
这个问题主要出现在Xcode 9.x及更早的版本,苹果在后续的Xcode 10+版本里修复了大量构建系统的依赖跟踪bug,同时Swift编译器本身也做了很多性能优化,类似的重复编译问题在新版本里会大幅减少。
内容的提问来源于stack exchange,提问作者barndog




