【发布时间】:2014-10-21 15:43:59
【问题描述】:
我正在使用 Xcode 6 Beta 6。
这已经困扰我一段时间了,但它现在已经到了几乎无法使用的地步。
我的项目开始有一个体面大小的 65 个 Swift 文件和一些桥接的 Objective-C 文件(这真的不是问题的原因)。
似乎对任何 Swift 文件的任何轻微修改(例如在应用程序中几乎不使用的类中添加一个简单的空格)都会导致指定目标的整个 Swift 文件被重新编译。
经过深入调查,我发现占用编译器时间几乎 100% 的是 CompileSwift 阶段,在该阶段 Xcode 对目标的所有 Swift 文件运行 swiftc 命令。
我做了一些进一步的调查,如果我只使用默认控制器保留应用程序委托,编译速度非常快,但是随着我添加越来越多的项目文件,编译时间开始变得非常慢。
现在只有 65 个源文件,每次编译大约需要 8/10 秒。一点也不迅速。
除了this one,我没有看到任何关于这个问题的帖子,但它是 Xcode 6 的旧版本。所以我想知道是否只有我一个人在这种情况下。
更新
我检查了GitHub 上的一些 Swift 项目,例如 Alamofire、Euler 和 CryptoSwift,但没有一个有足够的 Swift 文件来进行实际比较。我发现的唯一一个开始具有体面大小的项目是SwiftHN,即使它只有十几个源文件,我仍然能够验证同样的事情,一个简单的空间和整个项目需要重新编译,这开始需要一点时间(2/3 秒)。
与分析器和编译速度都非常快的 Objective-C 代码相比,这确实感觉 Swift 永远无法处理大型项目,但请告诉我我错了。
使用 Xcode 6 Beta 7 更新
仍然没有任何改善。这开始变得荒谬了。由于 Swift 中缺少 #import,我真的不知道 Apple 将如何优化这一点。
使用 Xcode 6.3 和 Swift 1.2 更新
Apple 添加了incremental builds(以及许多其他编译器优化)。您必须将代码迁移到 Swift 1.2 才能看到这些好处,但 Apple 在 Xcode 6.3 中添加了一个工具来帮助您这样做:
但是
不要像我一样高兴得太快。他们用来进行增量构建的图形求解器尚未得到很好的优化。
首先,它不会查看函数签名的更改,因此如果您在一个方法的块中添加一个空格,所有依赖于该类的文件都将被重新编译。
其次,它似乎是根据重新编译的文件创建树,即使更改不会影响它们。例如,如果将这三个类移动到不同的文件中
class FileA: NSObject {
var foo:String?
}
class FileB: NSObject {
var bar:FileA?
}
class FileC: NSObject {
var baz:FileB?
}
现在如果你修改FileA,编译器显然会将FileA标记为重新编译。它还将重新编译FileB(根据对FileA 的更改,这将是可以的),但是还有FileC,因为FileB 被重新编译,这非常糟糕,因为FileC从不在这里使用FileA。
所以我希望他们改进依赖树求解器...我用这个示例代码打开了radar。
使用 Xcode 7 beta 5 和 Swift 2.0 更新
昨天 Apple 发布了 beta 5,在发行说明中我们可以看到:
Swift 语言和编译器 • 增量构建:仅更改函数体不应再导致依赖文件重新构建。 (15352929)
我已经尝试过了,我必须说它现在真的(真的!)运行良好。他们极大地优化了 swift 中的增量构建。
我强烈建议您创建一个 swift2.0 分支并使用 XCode 7 beta 5 使您的代码保持最新。您会对编译器的增强感到高兴(但是我想说 XCode 7 的全局状态仍然是慢且有问题)
使用 Xcode 8.2 更新
自从我上次更新这个问题以来已经有一段时间了,所以在这里。
我们的应用程序现在大约有 20k 行几乎完全是 Swift 代码,这很不错,但并不出色。它经历了 swift 2 和 swift 3 迁移。在 2014 年中期的 Macbook pro(2.5 GHz Intel Core i7)上编译大约需要 5/6m,这在干净的构建上是可以的。
尽管 Apple 声称,增量构建仍然是一个笑话:
当仅发生很小的更改时,Xcode 不会重建整个目标。 (28892475)
显然,我认为我们中的许多人在检查完这些废话后只是笑了(向我的项目的任何文件添加一个私有(私有!)属性将重新编译整个事情......)
我想向你们指出 Apple 开发者论坛上的 this thread,其中包含有关该问题的更多信息(以及不时感谢 Apple 开发者就此事进行的交流)
基本上人们想出了一些办法来尝试改进增量构建:
- 添加一个
HEADER_MAP_USES_VFS项目设置设置为true - 从您的方案中禁用
Find implicit dependencies - 创建一个新项目并将文件层次结构移至新项目。
我会尝试解决方案 3,但解决方案 1/2 对我们不起作用。
在整个情况下具有讽刺意味的有趣之处在于,在查看有关此问题的第一篇文章时,我们使用 Xcode 6 和我相信 swift 1 或 swift 1.1 代码,当时我们遇到了第一次编译缓慢,而现在大约两年后,尽管实际改进了Apple 的情况与 Xcode 6 一样糟糕。真是讽刺。
我真的真的后悔为我们的项目选择了 Swift 而不是 Obj/C,因为它每天都会带来挫败感。 (我什至切换到 AppCode 但这是另一回事)
无论如何,我看到这篇 SO 帖子在撰写本文时有 32k+ 的浏览量和 143 次浏览量,所以我想我不是唯一一个。尽管对这种情况持悲观态度,但请坚持下去,隧道尽头可能会有一些曙光。
如果你有时间(和勇气!),我猜 Apple 很欢迎你对此有所了解。
下次见!干杯
使用 Xcode 9 更新
今天偶然发现this。 Xcode 悄悄地引入了一个新的构建系统来改进当前糟糕的性能。您必须通过工作区设置启用它。
已经尝试过,但完成后会更新这篇文章。不过看起来很有希望。
【问题讨论】:
-
有趣!不知是缺少优化还是因为没有接口文件需要解析这么多文件。
-
有类似的问题,最后我意识到这是因为实体类中使用自定义运算符从 JSON 反序列化。如果你正在使用any,我建议你尝试一个一个转换为正常功能,看看是否有任何变化。
-
自 XCode 6 beta 6 以来,我的项目中的编译变得非常缓慢。我不确定这是由于 beta 的更改还是由于我的代码。但我的项目还不算大(约 40-50 个 Swift 文件)。
-
随着我的项目的增长,编译变得非常缓慢。我还依赖于几个 pod,我确信这会激怒这个问题。这是使用最近的非测试版。
-
增量构建仍然是在“保守的依赖分析中进行的,因此您可能仍然会看到比绝对必要的更多的文件重建”。希望随着时间的推移会有所改善。
标签: swift optimization compilation type-inference compilation-time