Компиляция и кэши в плагине Kotlin Gradle
На этой странице вы можете узнать о следующих темах:
Инкрементальная компиляция
Плагин Kotlin Gradle поддерживает инкрементальную компиляцию. Инкрементальная компиляция отслеживает изменения в исходных файлах между сборками, чтобы компилировались только файлы, затронутые этими изменениями.
Инкрементальная компиляция поддерживается для проектов Kotlin/JVM и Kotlin/JS и включена по умолчанию.
Существует несколько способов отключить инкрементальную компиляцию:
Установите
kotlin.incremental=falseдля Kotlin/JVM.Установите
kotlin.incremental.js=falseдля проектов Kotlin/JS.-
Используйте
-Pkotlin.incremental=falseили-Pkotlin.incremental.js=falseв качестве параметра командной строки.Параметр необходимо добавить в каждую последующую сборку.
Примечание: любая сборка с отключенной инкрементальной компиляцией делает кэши инкрементальной компиляции недействительными. Первая сборка никогда не является инкрементальной.
Новый подход к инкрементальной компиляции
Новый подход к инкрементальной компиляции доступен начиная с Kotlin 1.7.0 для JVM-бекенда в системе сборки Gradle. Этот подход поддерживает изменения, внесённые в зависимые модули, не написанные на Kotlin, включает улучшенную возможность избежания компиляции и совместим с кэшем сборки Gradle.
Все эти улучшения уменьшают количество неинкрементальных сборок, что ускоряет общую время компиляции. Вы получите наибольшую выгоду, если используете кэш сборки или часто вносите изменения в не-Kotlin модули Gradle.
Чтобы включить этот новый подход, установите соответствующий параметр в вашем gradle.properties.
kotlin.incremental.useClasspathSnapshot=true
Узнайте, как реализован новый подход к инкрементальной компиляции в этой статье блога.
Поддержка кэша сборки Gradle
Плагин Kotlin использует кэш сборки Gradle, который хранит выходные данные сборки для повторного использования в будущих сборках.
Чтобы отключить кэширование для всех задач Kotlin, установите системную переменную kotlin.caching.enabled в false (запустите сборку с аргументом -Dkotlin.caching.enabled=false).
Если вы используете kapt, обратите внимание, что задачи аннотационной обработки kapt по умолчанию не кэшируются. Однако, вы можете включить кэширование для них вручную.
Поддержка кэша конфигурации Gradle
Плагин Kotlin использует кэш конфигурации Gradle, который ускоряет процесс сборки, повторно используя результаты фазы конфигурации.
См. документацию Gradle, чтобы узнать, как включить кэш конфигурации. После включения этой функции, плагин Kotlin Gradle автоматически начнёт его использовать.
Демон Kotlin и его использование с Gradle
Демон Kotlin:
Запускается вместе с демоном Gradle для компиляции проекта.
Запускается отдельно от демона Gradle, когда вы компилируете проект с помощью встроенной системы сборки IntelliJ IDEA.
Демон Kotlin запускается на стадии выполнения Gradle исполнения, когда одна из задач компиляции Kotlin начинает компилировать исходные файлы. Демон Kotlin останавливается вместе с демоном Gradle или через два часа бездействия без компиляции Kotlin.
Демон Kotlin использует ту же JDK, что и демон Gradle.
Установка аргументов JVM для демона Kotlin
Каждый из следующих способов установки аргументов переопределяет предыдущие:
Наследование аргументов демона Gradle
Если ничего не указано, демон Kotlin наследует аргументы от демона Gradle. Например, в файле gradle.properties:
org.gradle.jvmargs=-Xmx1500m -Xms=500m
Системная переменная kotlin.daemon.jvm.options
Если у аргументов JVM демона Gradle есть системная переменная kotlin.daemon.jvm.options – используйте её в файле gradle.properties:
org.gradle.jvmargs=-Dkotlin.daemon.jvm.options=-Xmx1500m,Xms=500m
При передаче аргументов следуйте этим правилам:
Используйте знак минус
-только перед аргументамиXmx,XX:MaxMetaspaceSize, иXX:ReservedCodeCacheSize.Разделяйте аргументы запятыми (
,) без пробелов. Аргументы, следующие за пробелом, будут использованы для демона Gradle, а не для демона Kotlin.
Свойство kotlin.daemon.jvmargs
Вы можете добавить свойство kotlin.daemon.jvmargs в файле gradle.properties:
kotlin.daemon.jvmargs=-Xmx1500m -Xms=500m
Расширение kotlin
Вы можете указать аргументы в расширении kotlin:
kotlin {
kotlinDaemonJvmArgs = listOf("-Xmx486m", "-Xms256m", "-XX:+UseParallelGC")
}
kotlin {
kotlinDaemonJvmArgs = ["-Xmx486m", "-Xms256m", "-XX:+UseParallelGC"]
}
Определение конкретной задачи
Вы можете указать аргументы для конкретной задачи:
tasks.withType<CompileUsingKotlinDaemon>().configureEach {
kotlinDaemonJvmArguments.set(listOf("-Xmx486m", "-Xms256m", "-XX:+UseParallelGC"))
}
tasks.withType(CompileUsingKotlinDaemon::class).configureEach { task ->
task.kotlinDaemonJvmArguments.set(["-Xmx1g", "-Xms512m"])
}
Поведение демона Kotlin с аргументами JVM
При настройке аргументов JVM для демона Kotlin обратите внимание на следующее:
Ожидается, что несколько экземпляров демона Kotlin будут работать одновременно, когда разные подпроекты или задачи имеют различные наборы аргументов JVM.
-
Новый экземпляр демона Kotlin запускается только при выполнении Gradle связанной задачи компиляции, и существующие демоны Kotlin не имеют одинакового набора аргументов JVM. Представьте, что ваш проект содержит множество подпроектов. Большинство из них требуют некоторого объема памяти для демона Kotlin, но один модуль требует значительного объема (хотя и компилируется редко). В этом случае вы должны предоставить другой набор аргументов JVM для такого модуля, чтобы демон Kotlin с большим объемом памяти запускался только для разработчиков, работающих с этим конкретным модулем.
Если аргумент
Xmxне указан, демон Kotlin унаследует его от демона Gradle.
Определение стратегии выполнения компилятора Kotlin
Стратегия выполнения компилятора Kotlin определяет место выполнения компилятора Kotlin и поддерживается ли инкрементная компиляция в каждом случае.
Существует три стратегии выполнения компилятора:
Стратегия |
Место выполнения компилятора Kotlin |
Инкрементная компиляция |
Другие характеристики и замечания |
|---|---|---|---|
Демон |
Внутри собственного демона процесса |
Да |
По умолчанию и самая быстрая стратегия. Может быть совмещена между различными демонами Gradle и несколькими параллельными компиляциями. |
В процессе |
Внутри процесса демона Gradle |
Нет |
Может совместно использовать кучу с демоном Gradle. Стратегия выполнения "В процессе" медленнее, чем стратегия "Демон". Каждый воркер создаёт отдельный класслоадер компилятора Kotlin для каждой компиляции. |
Вне процесса |
В отдельном процессе для каждой компиляции |
Нет |
Самая медленная стратегия выполнения. Похожа на стратегию "В процессе", но дополнительно создаёт отдельный процесс Java внутри воркера Gradle для каждой компиляции. |
Для определения стратегии выполнения компилятора Kotlin можно использовать одно из следующих свойств:
kotlin.compiler.execution.strategyсвойство Gradle.compilerExecutionStrategyсвойство задачи компиляции.
Свойство задачи compilerExecutionStrategy имеет приоритет над свойством Gradle kotlin.compiler.execution.strategy.
Доступные значения для свойства kotlin.compiler.execution.strategy:
daemon(по умолчанию)in-processout-of-process
Используйте свойство Gradle kotlin.compiler.execution.strategy в файле gradle.properties:
kotlin.compiler.execution.strategy=out-of-process
Доступные значения для свойства задачи compilerExecutionStrategy:
org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.DAEMON(по умолчанию)org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.IN_PROCESSorg.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.OUT_OF_PROCESS
Используйте свойство задачи compilerExecutionStrategy в ваших скриптах сборки:
import org.jetbrains.kotlin.gradle.tasks.CompileUsingKotlinDaemon
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
// ...
tasks.withType<CompileUsingKotlinDaemon>().configureEach {
compilerExecutionStrategy.set(KotlinCompilerExecutionStrategy.IN_PROCESS)
}
import org.jetbrains.kotlin.gradle.tasks.CompileUsingKotlinDaemon
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
// ...
tasks.withType(CompileUsingKotlinDaemon)
.configureEach {
compilerExecutionStrategy.set(KotlinCompilerExecutionStrategy.IN_PROCESS)
}
Стратегия резервного копирования компилятора Kotlin
Стратегия резервного копирования компилятора Kotlin заключается в запуске компиляции вне демона Kotlin, если демон по какой-то причине терпит неудачу. Если демон Gradle активен, компилятор использует стратегию "В процессе". Если демон Gradle выключен, компилятор использует стратегию "Вне процесса".
Когда происходит эта резервная стратегия, в выходных данных сборки Gradle отображаются следующие предупреждающие строки:
Failed to compile with Kotlin daemon: java.lang.RuntimeException: Could not connect to Kotlin compile daemon [exception stacktrace] Using fallback strategy: Compile without Kotlin daemon Try ./gradlew --stop if this issue persists.
Однако, пассивное переключение на другую стратегию может потреблять много системных ресурсов или приводить к непредсказуемым сборкам. Подробнее об этом можно прочитать в этом вопросе на YouTrack. Чтобы этого избежать, существует свойство Gradle kotlin.daemon.useFallbackStrategy, значение которого по умолчанию true. Когда значение равно false, сборки завершаются ошибкой при проблемах с запуском или взаимодействием демона. Объявите это свойство в gradle.properties:
kotlin.daemon.useFallbackStrategy=false
Также есть свойство useDaemonFallbackStrategy в задачах компиляции Kotlin, которое имеет приоритет над свойством Gradle, если вы используете оба.
tasks {
compileKotlin {
useDaemonFallbackStrategy.set(false)
}
}
tasks.named("compileKotlin").configure {
useDaemonFallbackStrategy = false
}
Если памяти недостаточно для выполнения компиляции, в логах отобразится сообщение об этом.
Отчёты о сборке
Отчёты о сборках для отслеживания производительности компилятора доступны начиная с Kotlin 1.7.0. Отчёты содержат длительность различных этапов компиляции и причины, по которым компиляция не могла быть инкрементальной.
Используйте отчёты о сборках для изучения проблем с производительностью, когда время компиляции слишком велико или различается для одного и того же проекта.
Отчёты о сборке Kotlin помогают более эффективно изучить проблемы, чем Gradle build scans. Множество инженеров используют их для изучения производительности сборки, но единицей детализации в Gradle scans является отдельная задача Gradle.
Существует две распространённые ситуации, при решении которых анализ отчётов о сборке для длительных компиляций может быть полезен:
Сборка не была инкрементальной. Проанализируйте причины и исправьте лежащие в основе проблемы.
Сборка была инкрементальной, но заняла слишком много времени. Попробуйте переорганизовать исходные файлы — разделить большие файлы, сохранить отдельные классы в разных файлах, переработать большие классы, объявить функции верхнего уровня в разных файлах и так далее.
Узнайте как читать отчёты о сборке и как JetBrains использует отчёты о сборке.
Включение отчётов о сборке
Чтобы включить отчёты о сборке, укажите, где сохранить выходные данные отчёта о сборке в gradle.properties:
kotlin.build.report.output=file
Доступны следующие значения и их комбинации для вывода:
Вариант |
Описание |
|
|---|---|---|
|
Сохраняет отчёты о сборке в удобочитаемом формате в локальный файл. По умолчанию |
|
|
Сохраняет отчёты о сборке в формате объекта в указанный локальный файл |
|
|
Сохраняет отчёты о сборке в разделе |
|
|
Отправляет отчёты о сборке с помощью HTTP(S). Метод POST отправляет метрики в формате JSON. Текущую версию отправляемых данных можно посмотреть в репозитории Kotlin. Примеры HTTP-конечных точек можно найти в этой статье в блоге |
Полный список доступных вариантов для kotlin.build.report:
# Required outputs. Any combination is allowed kotlin.build.report.output=file,single_file,http,build_scan # Mandatory if single_file output is used. Where to put reports # Use instead of the deprecated `kotlin.internal.single.build.metrics.file` property kotlin.build.report.single_file=some_filename # Optional. Output directory for file-based reports. Default: build/reports/kotlin-build/ kotlin.build.report.file.output_dir=kotlin-reports # Mandatory if HTTP output is used. Where to post HTTP(S)-based reports kotlin.build.report.http.url=http://127.0.0.1:8080 # Optional. User and password if the HTTP endpoint requires authentication kotlin.build.report.http.user=someUser kotlin.build.report.http.password=somePassword # Optional. Label for marking your build report (for example, debug parameters) kotlin.build.report.label=some_label
Предел настраиваемых значений
Для сбора статистики о сводках о сборке отчёты о сборке Kotlin используют настраиваемые значения Gradle. И вы, и различные плагины Gradle можете записывать данные в настраиваемые значения. Количество настраиваемых значений ограничено. См. текущее максимальное количество настраиваемых значений в документации плагина сводки о сборке.
Если у вас большой проект, количество таких настраиваемых значений может быть довольно большим. Если это количество превышает предел, в логах может отобразиться следующее сообщение:
Maximum number of custom values (1,000) exceeded
Чтобы уменьшить количество настраиваемых значений, которые создаёт плагин Kotlin, вы можете использовать следующее свойство в gradle.properties:
kotlin.build.report.build_scan.custom_values_limit=500
Отключение сбора свойств проекта и системы
Логи HTTP-статистики сборки могут содержать некоторые свойства проекта и системы. Эти свойства могут изменять поведение сборок, поэтому их полезно регистрировать в статистике сборки. Эти свойства могут хранить конфиденциальные данные, например, пароли или полный путь к проекту.
Вы можете отключить сбор этой статистики, добавив свойство kotlin.build.report.http.verbose_environment в gradle.properties.
Что дальше?
Узнайте больше о:
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/gradle-compilation-and-caches.html