Xcode 10 iOS 次应用构建,"hidden" 任务占用了大部分构建时间
Xcode 10 iOS app build, "hidden" task takes most of build time
在更改单行代码并在大型项目中执行 Xcode 10.1 增量构建后,Xcode 在完成所有列出的任务后将大部分构建时间花费在 "Compile swift source files" 阶段(编译更改文件和合并 swift 模块都已完成)
显示任务列表的屏幕截图:https://imgur.com/a/JoVI0zB
虽然编译和合并 swift 模块用时不到一秒,但在我的项目中整个阶段最多可能需要 2 分钟(300k LOC)。
这段时间Xcode做了什么?有什么办法可以加快这个过程吗?
用 Obj-C 编写的类似项目在更改 1 行代码后只需几秒钟即可启动。
我遇到了同样的问题,经过大量调查,我确定无论它在做什么,它都是基于 swift 个源文件的数量 你有。
根本原因
在 2018 wwdc talk about the Xcode build system 中,演示者说(可在视频抄本中搜索):
What this means is that unlike Clang, when compiling one Swift file, the compiler will parse all the other Swift files in the target.
所以即使if/though增量构建只需要重新编译一个单个文件,它仍然每隔一个swift 文件.
我们的项目有超过 2000 个 swift 源文件,我们看到重新编译单个独立文件的增量构建时间超过 3 分钟。
测试以证明根本原因
因为在 WWDC talk 中听到它还不够,所以我做了以下测试:
- 创建了一个新项目
- 测试几乎为空的项目的增量构建时间,更改单个文件
- 增量构建几乎瞬间完成(< 1-2 秒)
- 使用脚本生成了 2,000 个 swift 文件,每个文件都包含一个具有唯一名称的简单结构、2 个变量和一个简单函数。任何文件之间都没有依赖关系。
- 将包含 2,000 个新 swift 文件的目录添加到项目并完成完整构建。
- 再次测试单个文件的增量构建时间
- 增量构建时间超过 1 分钟
在我的测试中,附加 swift 个文件的内容的复杂性似乎并不重要,只是文件的数量。
解决方案 - Modularization/Frameworks
将您的应用分成更小的框架,以减少每个目标中 swift 源文件的数量。
This is a decent guide 展示了如果您还不知道如何操作的步骤。
在我上面的测试用例中,我创建了一个新框架并将 2,000 个 swift 文件移动到框架中,然后在原始项目(导入框架)中测试了增量构建时间,构建时间又回来了< 1-2 秒。当然,在框架内进行增量构建仍然很慢,但理想情况下,您可以将项目拆分为许多较小的框架,以便每个框架都有更快的增量构建时间。
不是解决方案 - 合并文件
如果是文件数量的问题,为什么不合并一堆文件来减少数量呢?因为它可能会导致增量构建变慢。
根据2018 WWDC's Building Faster in Xcode:
Swift's dependency model is based around files
这与我们当前的问题有关,因为这意味着对文件的任何更改(仅对函数体内容的更改除外)都会导致对任何依赖于更改文件中任何内容的文件进行重新编译。
如果您将多种类型合并到一个文件中,如果任何更改触及大文件或其任何依赖项,将导致更多代码在增量构建中重新编译。它还会增加大文件的依赖项数量,这样一来,如果修改了大文件中的任何类型,就会重新编译所有依赖项。
在更改单行代码并在大型项目中执行 Xcode 10.1 增量构建后,Xcode 在完成所有列出的任务后将大部分构建时间花费在 "Compile swift source files" 阶段(编译更改文件和合并 swift 模块都已完成) 显示任务列表的屏幕截图:https://imgur.com/a/JoVI0zB
虽然编译和合并 swift 模块用时不到一秒,但在我的项目中整个阶段最多可能需要 2 分钟(300k LOC)。
这段时间Xcode做了什么?有什么办法可以加快这个过程吗?
用 Obj-C 编写的类似项目在更改 1 行代码后只需几秒钟即可启动。
我遇到了同样的问题,经过大量调查,我确定无论它在做什么,它都是基于 swift 个源文件的数量 你有。
根本原因
在 2018 wwdc talk about the Xcode build system 中,演示者说(可在视频抄本中搜索):
What this means is that unlike Clang, when compiling one Swift file, the compiler will parse all the other Swift files in the target.
所以即使if/though增量构建只需要重新编译一个单个文件,它仍然每隔一个swift 文件.
我们的项目有超过 2000 个 swift 源文件,我们看到重新编译单个独立文件的增量构建时间超过 3 分钟。
测试以证明根本原因
因为在 WWDC talk 中听到它还不够,所以我做了以下测试:
- 创建了一个新项目
- 测试几乎为空的项目的增量构建时间,更改单个文件
- 增量构建几乎瞬间完成(< 1-2 秒)
- 使用脚本生成了 2,000 个 swift 文件,每个文件都包含一个具有唯一名称的简单结构、2 个变量和一个简单函数。任何文件之间都没有依赖关系。
- 将包含 2,000 个新 swift 文件的目录添加到项目并完成完整构建。
- 再次测试单个文件的增量构建时间
- 增量构建时间超过 1 分钟
在我的测试中,附加 swift 个文件的内容的复杂性似乎并不重要,只是文件的数量。
解决方案 - Modularization/Frameworks
将您的应用分成更小的框架,以减少每个目标中 swift 源文件的数量。
This is a decent guide 展示了如果您还不知道如何操作的步骤。
在我上面的测试用例中,我创建了一个新框架并将 2,000 个 swift 文件移动到框架中,然后在原始项目(导入框架)中测试了增量构建时间,构建时间又回来了< 1-2 秒。当然,在框架内进行增量构建仍然很慢,但理想情况下,您可以将项目拆分为许多较小的框架,以便每个框架都有更快的增量构建时间。
不是解决方案 - 合并文件
如果是文件数量的问题,为什么不合并一堆文件来减少数量呢?因为它可能会导致增量构建变慢。
根据2018 WWDC's Building Faster in Xcode:
Swift's dependency model is based around files
这与我们当前的问题有关,因为这意味着对文件的任何更改(仅对函数体内容的更改除外)都会导致对任何依赖于更改文件中任何内容的文件进行重新编译。
如果您将多种类型合并到一个文件中,如果任何更改触及大文件或其任何依赖项,将导致更多代码在增量构建中重新编译。它还会增加大文件的依赖项数量,这样一来,如果修改了大文件中的任何类型,就会重新编译所有依赖项。