6.3.9 缩短编译时间的技巧
5 分钟阅读
原文链接: https://kotlinlang.org/docs/native-improving-compilation-time.html
6.3.9 缩短编译时间的技巧
Kotlin/Native 编译器不断获得改进其性能的更新。使用最新的 Kotlin/Native 编译器并正确配置构建环境,你可以显著缩短带有 Kotlin/Native 目标的项目的编译时间。
继续阅读,了解我们关于如何加速 Kotlin/Native 编译过程的建议。
一般建议
使用最新的 Kotlin 版本
这样你就能始终获得最新的性能改进。最新的 Kotlin 版本是 2.4.20。
避免创建超大的类
尽量避免创建编译耗时长、执行期间加载也慢的超大类。
在多次构建之间保留已下载和缓存的内容
编译项目时,Kotlin/Native 会下载所需的组件,并把部分工作结果缓存到 $USER_HOME/.konan 目录中。编译器会在后续编译中使用该目录,从而缩短完成时间。
在容器(例如 Docker)中构建或使用持续集成系统时,编译器可能不得不为每次构建从头创建 ~/.konan 目录。要避免这一步,请把你的环境配置为在多次构建之间保留 ~/.konan。例如,使用 konan.data.dir Gradle 属性重新定义它的位置。
或者,你可以使用 -Xkonan-data-dir 编译器选项,通过 cinterop 和 konanc 工具为该目录配置自定义路径。
Gradle 配置
使用 Gradle 进行的第一次编译通常比后续编译耗时长,因为需要下载依赖、构建缓存并执行额外步骤。你应该至少构建项目两次,才能得到实际编译时间的准确读数。
以下是一些为获得更好编译性能而配置 Gradle 的建议。
增大 Gradle 堆大小
要增大 Gradle 堆大小,请在 gradle.properties 文件中添加 org.gradle.jvmargs=-Xmx3g。
如果你使用并行构建,可能需要通过 org.gradle.workers.max 属性或 --max-workers 命令行选项来选择合适的工作进程数量。默认值是 CPU 处理器数量。
只构建必要的二进制文件
除非确实需要,否则不要运行 build 或 assemble 之类会构建整个项目的 Gradle 任务。这些任务会对同一份代码构建多次,从而增加编译时间。在典型情况下,例如从 IntelliJ IDEA 运行测试或从 Xcode 启动应用,Kotlin 工具链会避免执行不必要的任务。
如果你的情况或构建配置不典型,可能需要自己选择任务:
linkDebug*。在开发过程中运行代码通常只需要一个二进制文件,因此运行相应的linkDebug*任务就足够了。embedAndSignAppleFrameworkForXcode。由于 iOS 模拟器和设备具有不同的处理器架构,把 Kotlin/Native 二进制文件分发为通用(fat)框架是常见的做法。
不过,在本地开发期间,只为你所使用的平台构建 .framework 文件会更快。要构建特定于平台的框架,请使用 embedAndSignAppleFrameworkForXcode 任务。
只为必要的目标构建
与上面的建议类似,不要一次为所有原生平台构建二进制文件。例如,编译 XCFramework(使用 *XCFramework 任务)会为所有目标构建同一份代码,比只为单个目标构建耗时成比例地更多。
如果你的设置确实需要 XCFramework,可以减少目标数量。例如,如果你不在基于 Intel 的 Mac 上为 iOS 模拟器运行该项目,就不需要 iosX64。
提示: 不同目标的二进制文件通过
linkDebug*$Target和linkRelease*$TargetGradle 任务构建。你可以通过使用--scan选项运行 Gradle 构建,在构建日志或 Gradle 构建扫描中查找已执行的任务。
不要构建不必要的 release 二进制文件
Kotlin/Native 支持两种构建模式:debug 和 release。release 模式经过高度优化,而这会耗费大量时间:release 二进制文件的编译耗时比 debug 二进制文件高一个数量级。
除了实际发布之外,在典型的开发循环中这些优化可能都不必要。如果你在开发过程中使用了名称中包含 Release 的任务,请考虑把它替换为 Debug。类似地,例如你可以运行 assembleSharedDebugXCFramework,而不是 assembleXCFramework。
提示: release 二进制文件通过
linkRelease*Gradle 任务构建。你可以通过使用--scan选项运行 Gradle 构建,在构建日志或 Gradle 构建扫描中检查它们。
为 release 二进制文件启用缓存
实验性
默认情况下,Kotlin/Native 以链接时优化(LTO)模式编译 release 二进制文件:所有模块一起编译和优化。这会让 release 二进制文件在运行时更快,但会显著增加编译时间。
如果你更希望优先考虑更快的编译速度,而不是某些编译器优化,可以在 release 模式下启用缓存。要启用缓存,请在 gradle.properties 文件中添加以下两个选项:
| |
警告: 该特性仍在积极开发中,因此运行时性能仍有提升空间。性能改进已计划在即将发布的 Kotlin 版本中提供。
减小 release 二进制文件的大小
实验性
要减小 release 二进制文件的大小并改善构建时间,请尝试启用二进制选项 smallBinary。
它实际上会把 -Oz 设置为编译器在 LLVM 编译阶段的默认优化参数。该选项仍处于实验性阶段,在某些情况下可能影响运行时性能。
不要使用传递导出
使用 transitiveExport = true 会在许多情况下禁用无用代码消除,因此编译器必须处理大量未使用的代码。这会增加编译时间。请改为对需要导出的项目和依赖显式使用 export 方法。
不要导出过多模块
请尽量避免不必要的模块导出。每个被导出的模块都会对编译时间和二进制文件大小产生负面影响。
使用 Gradle 构建缓存
启用 Gradle 构建缓存特性:
- 本地构建缓存。对于本地缓存,请在
gradle.properties文件中添加org.gradle.caching=true,或在命令行中使用--build-cache选项运行构建。 - 远程构建缓存。了解如何为持续集成环境配置远程构建缓存。
使用 Gradle 配置缓存
Gradle 配置缓存通过缓存配置阶段的结果来改善构建性能。它还支持在单个项目内并行执行独立任务,并隐式启用 org.gradle.parallel 属性,让不同项目中的任务可以并行执行。
要使用 Gradle 配置缓存,请在 gradle.properties 文件中添加 org.gradle.configuration-cache=true 属性。
注意: 配置缓存还会让
link*任务并行运行,这可能给机器带来很大负载,尤其是 CPU 核心较多时。该问题将在 KT-70915 中修复。
启用之前被禁用的特性
你过去可能为了绕过构建问题而禁用过某些 Kotlin/Native 特性。例如:
kotlin.native.disableCompilerDaemon=true会禁用 Gradle 守护进程。disableNativeCache会禁用编译缓存。
当初需要这些变通办法的问题可能已经修复。如果你的 gradle.properties 文件或 Gradle 构建文件中包含这些行,请把它们删除,并检查构建是否能成功完成。
尝试 klib 产物的增量编译
Beta
有了增量编译,如果项目模块生成的 klib 产物只有一部分发生变化,那么只有 klib 的一部分会被进一步重新编译为二进制文件。
该特性处于 Beta 阶段。要启用它,请在 gradle.properties 文件中添加以下选项:
| |
如果你遇到任何问题,请在 YouTrack 中创建 issue。
Windows 配置
Windows 安全中心可能会拖慢 Kotlin/Native 编译器。你可以通过把 .konan 目录(默认位于 %\USERPROFILE%)添加到 Windows 安全中心的排除项来避免这一点。了解如何向 Windows 安全中心添加排除项。
LLVM 配置
高级
如果上述建议没能帮助改善编译时间,请考虑自定义 LLVM 后端。