11.1.5 Kotlin Gradle 插件中的编译器选项

原文链接: https://kotlinlang.org/docs/gradle-compiler-options.html

11.1.5 Kotlin Gradle 插件中的编译器选项

Kotlin 的每个版本都包含面向受支持目标的编译器:JVM、JavaScript,以及面向受支持平台的本地二进制文件。

这些编译器会被以下场景使用:

  • 当你在 IDE 中为 Kotlin 项目点击 Compile 或 Run 按钮时。
  • 当你在控制台或 IDE 中调用 gradle build 时,由 Gradle 使用。
  • 当你在控制台或 IDE 中调用 mvn compile 或 mvn test-compile 时,由 Maven 使用。

你也可以按照使用命令行编译器教程中的说明,从命令行手动运行 Kotlin 编译器。

如何定义选项

Kotlin 编译器有许多选项,可用于定制编译过程。

Gradle DSL 允许对编译器选项进行全面配置。它适用于 Kotlin Multiplatform 和 JVM/Android 项目。

借助 Gradle DSL,你可以在构建脚本中从三个级别配置编译器选项:

Kotlin 编译器选项级别

较高层级的设置会作为较低层级的约定(默认值):

  • 在扩展级别设置的编译器选项是目标级别选项的默认值,包括 commonMain、nativeMain 和 commonTest 等共享源集。
  • 在目标级别设置的编译器选项是编译单元(任务)级别选项的默认值,例如 compileKotlinJvm 和 compileTestKotlinJvm 任务。

相应地,较低层级的配置会覆盖较高层级的相关设置:

  • 任务级编译器选项会覆盖目标级别或扩展级别的相关配置。
  • 目标级编译器选项会覆盖扩展级别的相关配置。

要了解应用了哪个级别的编译器参数,请使用 Gradle 日志的 DEBUG 级别。对于 JVM 和 JS/WASM 任务,请在日志中搜索字符串 "Kotlin compiler args:";对于 Native 任务,请搜索字符串 "Arguments ="。

提示: 如果你是第三方插件作者,最好在项目级别应用你的配置,以避免覆盖问题。为此,你可以使用新的 Kotlin 插件 DSL 扩展类型。建议你在自己这一侧明确记录这一配置。

扩展级别

你可以在顶层的 compilerOptions {} 块中为所有目标和共享源集配置通用的编译器选项:

1
2
3
4
5
kotlin {
    compilerOptions {
        optIn.add("kotlin.RequiresOptIn")
    }
}

目标级别

你可以在 target {} 块内的 compilerOptions {} 块中为 JVM/Android 目标配置编译器选项:

1
2
3
4
5
6
7
kotlin {
    target {
        compilerOptions {
            optIn.add("kotlin.RequiresOptIn")
        }
    }
}

在 Kotlin Multiplatform 项目中,你可以在特定目标内部配置编译器选项。例如 jvm { compilerOptions {}}。更多信息请参阅 Multiplatform Gradle DSL 参考。

编译单元级别

你可以在任务配置内的 compilerOptions {} 块中为特定的编译单元或任务配置编译器选项:

1
2
3
4
5
tasks.named<KotlinJvmCompile>("compileKotlin"){
    compilerOptions {
        optIn.add("kotlin.RequiresOptIn")
    }
}

你也可以通过 KotlinCompilation 在编译单元级别访问并配置编译器选项:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kotlin {
    target {
        val main by compilations.getting {
            compileTaskProvider.configure {
                compilerOptions {
                    optIn.add("kotlin.RequiresOptIn")
                }
            }
        }
    }
}

如果你想配置的插件针对的不是 JVM/Android 和 Kotlin Multiplatform 目标,请使用相应 Kotlin 编译任务的 compilerOptions {} 属性。下面的示例展示了如何在 Kotlin 和 Groovy 两种 DSL 中进行这一配置:

Kotlin

1
2
3
4
5
tasks.named("compileKotlin", org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask::class.java) {
    compilerOptions {
        apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
    }
}

Groovy

1
2
3
4
5
tasks.named('compileKotlin', org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class) {
    compilerOptions {
        apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
    }
}

从 kotlinOptions {} 迁移到 compilerOptions {}

在 Kotlin 2.2.0 之前,你可以使用 kotlinOptions {} 块配置编译器选项。由于从 Kotlin 2.0.0 起 kotlinOptions {} 块已被弃用,本节为你把构建脚本迁移到使用 compilerOptions {} 块提供指导和建议:

集中管理编译器选项并使用类型

只要有可能,请在扩展级别配置编译器选项,并在编译单元级别为特定任务覆盖它们。

你不能在 compilerOptions {} 块中使用原始字符串,因此请把它们转换为有类型的值。例如,如果你有:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
plugins {
    kotlin("jvm") version "2.4.20"
}

tasks.withType<KotlinCompile>().configureEach {
    kotlinOptions {
        jvmTarget = "17"
        languageVersion = "2.4"
        apiVersion = "2.4"
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
plugins {
    id 'org.jetbrains.kotlin.jvm' version '2.4.20'
}

tasks.withType(KotlinCompile).configureEach {
    kotlinOptions {
        jvmTarget = '17'
        languageVersion = '2.4'
        apiVersion = '2.4'
    }
}

迁移后应为:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion

plugins {
    kotlin("jvm") version "2.4.20"
}

kotlin {
    // 扩展级别
    compilerOptions {
        jvmTarget = JvmTarget.fromTarget("17")
        languageVersion = KotlinVersion.fromVersion("2.4")
        apiVersion = KotlinVersion.fromVersion("2.4")
    }
}

// 在编译单元级别覆盖的示例
tasks.named<KotlinJvmCompile>("compileKotlin"){
    compilerOptions {
        apiVersion = KotlinVersion.fromVersion("2.4")
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion

plugins {
    id 'org.jetbrains.kotlin.jvm' version '2.4.20'
}

kotlin {
  // 扩展级别
    compilerOptions {
        jvmTarget = JvmTarget.fromTarget("17")
        languageVersion = KotlinVersion.fromVersion("2.4")
        apiVersion = KotlinVersion.fromVersion("2.4")
    }
}

// 在编译单元级别覆盖的示例
tasks.named("compileKotlin", KotlinJvmCompile).configure {
    compilerOptions {
        apiVersion = KotlinVersion.fromVersion("2.4")
    }
}

从 android.kotlinOptions 迁移

如果你的构建脚本之前使用 android.kotlinOptions,请改为迁移到 kotlin.compilerOptions,可以在扩展级别,也可以在目标级别。

例如,如果你有一个 Android 项目:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
plugins {
    id("com.android.application")
    kotlin("android")
}

android {
    kotlinOptions {
        jvmTarget = "17"
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    kotlinOptions {
        jvmTarget = '17'
    }
}

请把它更新为:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
plugins {
    id("com.android.application")
    kotlin("android")
}

kotlin {
    compilerOptions {
        jvmTarget = JvmTarget.fromTarget("17")
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

kotlin {
    compilerOptions {
        jvmTarget = JvmTarget.fromTarget("17")
    }
}

再例如,如果你有一个带 Android 目标的 Kotlin Multiplatform 项目:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
plugins {
    kotlin("multiplatform")
    id("com.android.application")
}

kotlin {
    androidTarget {
        compilations.all {
            kotlinOptions.jvmTarget = "17"
        }
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
plugins {
    id 'org.jetbrains.kotlin.multiplatform'
    id 'com.android.application'
}

kotlin {
    androidTarget {
        compilations.all {
            kotlinOptions {
                jvmTarget = '17'
            }
        }
    }
}

请把它更新为:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
plugins {
    kotlin("multiplatform")
    id("com.android.application")
}

kotlin {
    androidTarget {
        compilerOptions {
            jvmTarget = JvmTarget.fromTarget("17")
        }
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
plugins {
    id 'org.jetbrains.kotlin.multiplatform'
    id 'com.android.application'
}

kotlin {
    androidTarget {
        compilerOptions {
            jvmTarget = JvmTarget.fromTarget("17")
        }
    }
}

迁移 freeCompilerArgs

  • 把所有 += 操作替换为 add() 或 addAll() 函数。
  • 如果你使用 -opt-in 编译器选项,请检查 KGP API 参考中是否已有专用的 DSL,若有则改用它。
  • 把对 -progressive 编译器选项的任何使用迁移为专用 DSL:progressiveMode.set(true)。
  • 把对 -Xjvm-default 编译器选项的任何使用迁移为使用专用 DSL:jvmDefault.set()。这些选项使用以下映射:

| 之前 | 之后 |

| -Xjvm-default=all-compatibility | jvmDefault.set(JvmDefaultMode.ENABLE) | | -Xjvm-default=all | jvmDefault.set(JvmDefaultMode.NO_COMPATIBILITY) | | -Xjvm-default=disable | jvmDefault.set(JvmDefaultMode.DISABLE) |

例如,如果你有:

Kotlin

1
2
3
4
kotlinOptions {
    freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
    freeCompilerArgs += listOf("-Xcontext-receivers", "-Xinline-classes", "-progressive", "-Xjvm-default=all")
}

Groovy

1
2
3
4
kotlinOptions {
    freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
    freeCompilerArgs += ["-Xcontext-receivers", "-Xinline-classes", "-progressive", "-Xjvm-default=all"]
}

请迁移为:

Kotlin

1
2
3
4
5
6
7
8
kotlin {
    compilerOptions {
        optIn.add("kotlin.RequiresOptIn")
        freeCompilerArgs.addAll(listOf("-Xcontext-receivers", "-Xinline-classes"))
        progressiveMode.set(true)
        jvmDefault.set(JvmDefaultMode.NO_COMPATIBILITY)
    }
}

Groovy

1
2
3
4
5
6
7
8
kotlin {
    compilerOptions {
        optIn.add("kotlin.RequiresOptIn")
        freeCompilerArgs.addAll(["-Xcontext-receivers", "-Xinline-classes"])
        progressiveMode.set(true)
        jvmDefault.set(JvmDefaultMode.NO_COMPATIBILITY)
    }
}

以 JVM 为目标

如前所述,你可以在扩展、目标和编译单元(任务)级别为 JVM/Android 项目定义编译器选项。

默认的 JVM 编译任务中,生产代码为 compileKotlin,测试代码为 compileTestKotlin。自定义源集的任务按 compile<Name>Kotlin 模式命名。

你可以在终端中运行 gradlew tasks --all 命令,并在 Other tasks 组中搜索 compile*Kotlin 任务名称,查看 Android 编译任务的列表。

需要注意的一些重要细节:

  • kotlin.compilerOptions 会配置项目中的每一个 Kotlin 编译任务。
  • 你可以使用 tasks.named<KotlinJvmCompile>("compileKotlin") { }(或 tasks.withType<KotlinJvmCompile>().configureEach { })的方式覆盖 kotlin.compilerOptions DSL 所应用的配置。

以 JavaScript 为目标

JavaScript 编译任务中,生产代码为 compileKotlinJs,测试代码为 compileTestKotlinJs,自定义源集为 compile<Name>KotlinJs。

要配置单个任务,请使用它的名称:

Kotlin

1
2
3
4
5
6
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

val compileKotlin: KotlinCompilationTask<*> by tasks

compileKotlin.compilerOptions.suppressWarnings.set(true)

Groovy

1
2
3
4
5
6
7
8
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named('compileKotlin', KotlinCompilationTask) {
    compilerOptions {
        suppressWarnings = true
    }
}

请注意,使用 Gradle Kotlin DSL 时,你应首先从项目的 tasks 中获取该任务。

对于 JS 和 common 目标,请分别使用 Kotlin2JsCompile 和 KotlinCompileCommon 类型。

你可以在终端中运行 gradlew tasks --all 命令,并在 Other tasks 组中搜索 compile*KotlinJS 任务名称,查看 JavaScript 编译任务的列表。

所有 Kotlin 编译任务

也可以配置项目中的所有 Kotlin 编译任务:

Kotlin

1
2
3
4
5
6
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named<KotlinCompilationTask<*>>("compileKotlin").configure {
    compilerOptions { /*...*/ }
}

Groovy

1
2
3
4
5
6
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named('compileKotlin', KotlinCompilationTask) {
    compilerOptions { /*...*/ }
}

所有编译器选项

以下是 Gradle 编译器选项的完整列表:

通用属性

| 名称 | 说明 | 可能的值 | 默认值 |

| optIn | 用于配置一组选择启用编译器参数的属性 | listOf( /* 选择启用项 */ ) | emptyList() | | progressiveMode | 启用渐进式编译器模式 | true、false | false | | extraWarnings | 启用额外的声明、表达式和类型编译器检查,若为 true 则在有问题时发出警告 | true、false | false |

JVM 特有的属性

| 名称 | 说明 | 可能的值 | 默认值 |

| javaParameters | 为方法参数生成 Java 1.8 反射所需的元数据 | | false | | jvmTarget | 生成的 JVM 字节码的目标版本 | “1.8”、“9”、“10”、…、“25”、26"。另请参阅编译器选项的类型 | “1.8” | | noJdk | 不要自动把 Java 运行时包含到 classpath 中 | | false | | jvmTargetValidationMode | 校验 Kotlin 与 Java 之间 JVM 目标兼容性 的属性,用于 KotlinCompile 类型的任务。 | WARNING、ERROR、IGNORE | ERROR | | jvmDefault | 控制接口中声明的函数如何编译为 JVM 上的默认方法 | ENABLE、NO_COMPATIBILITY、DISABLE | ENABLE |

JVM 与 JavaScript 共有的属性

| 名称 | 说明 | 可能的值 | 默认值 |

| allWarningsAsErrors | 如果有任何警告则报告为错误 | | false | | suppressWarnings | 不生成警告 | | false | | verbose | 启用详细的日志输出。仅在启用 Gradle 调试日志级别时有效 | | false | | freeCompilerArgs | 额外的编译器参数列表。你也可以在这里使用实验性的 -X 参数。参见示例 | | [] | | apiVersion | 控制你的代码可以使用哪些 Kotlin API。更多信息请参阅 -api-version。 | “2.0”、“2.1”、“2.2”、“2.3”、“2.4”、“2.5”(实验性) | | | languageVersion | 控制编译期间可用的 Kotlin 语言特性和语法。更多信息请参阅 -language-version。 | “2.0”、“2.1”、“2.2”、“2.3”、“2.4”、“2.5”(实验性) | |

警告: 我们将在未来的版本中弃用 freeCompilerArgs 属性。如果你在 Kotlin Gradle DSL 中缺少某些选项,请提交 issue。

通过 freeCompilerArgs 使用额外参数的示例

使用 freeCompilerArgs 属性可以提供额外的(包括实验性的)编译器参数。你可以向该属性添加单个参数,也可以添加参数列表:

Kotlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

kotlin {
    compilerOptions {
        // 指定 Kotlin API 的版本和 JVM 目标
        apiVersion.set(KotlinVersion.KOTLIN_2_4)
        jvmTarget.set(JvmTarget.JVM_1_8)

        // 单个实验性参数
        freeCompilerArgs.add("-Xexport-kdoc")

        // 单个额外参数
        freeCompilerArgs.add("-Xno-param-assertions")

        // 参数列表
        freeCompilerArgs.addAll(
            listOf(
                "-Xno-receiver-assertions",
                "-Xno-call-assertions"
            )
        )
    }
}

Groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named('compileKotlin', KotlinCompilationTask) {
    compilerOptions {
        // 指定 Kotlin API 的版本和 JVM 目标
        apiVersion = KotlinVersion.KOTLIN_2_4
        jvmTarget = JvmTarget.JVM_1_8

        // 单个实验性参数
        freeCompilerArgs.add("-Xexport-kdoc")

        // 单个额外参数,可以是键值对
        freeCompilerArgs.add("-Xno-param-assertions")

        // 参数列表
        freeCompilerArgs.addAll(["-Xno-receiver-assertions", "-Xno-call-assertions"])
    }
}

提示: freeCompilerArgs 属性在扩展、目标和编译单元(任务)级别都可用。

设置 languageVersion 的示例

要设置语言版本,请使用以下语法:

Kotlin

1
2
3
4
5
kotlin {
    compilerOptions {
        languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_4)
    }
}

Groovy

1
2
3
4
5
6
tasks
    .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class)
    .configureEach {
        compilerOptions.languageVersion =
            org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_4
    }

另请参阅编译器选项的类型。

JavaScript 特有的属性

| 名称 | 说明 | 可能的值 | 默认值 |

| friendModulesDisabled | 禁用 internal 声明的导出 | | false | | main | 指定执行时是否应调用 main 函数 | JsMainFunctionExecutionMode.CALL、JsMainFunctionExecutionMode.NO_CALL | JsMainFunctionExecutionMode.CALL | | moduleKind | 编译器生成的 JS 模块类型 | JsModuleKind.MODULE_AMD、JsModuleKind.MODULE_PLAIN、JsModuleKind.MODULE_ES、JsModuleKind.MODULE_COMMONJS、JsModuleKind.MODULE_UMD | null | | sourceMap | 生成 source map | | false | | sourceMapEmbedSources | 把源文件嵌入 source map | JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_INLINING、JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_NEVER、JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_ALWAYS | null | | sourceMapNamesPolicy | 把你所声明的变量名和函数名从 Kotlin 代码加入 source map。关于该行为的更多信息,请参阅我们的编译器参考 | JsSourceMapNamesPolicy.SOURCE_MAP_NAMES_POLICY_FQ_NAMES、JsSourceMapNamesPolicy.SOURCE_MAP_NAMES_POLICY_SIMPLE_NAMES、JsSourceMapNamesPolicy.SOURCE_MAP_NAMES_POLICY_NO | null | | sourceMapPrefix | 为 source map 中的路径添加指定前缀 | | null | | target | 为特定的 ECMA 版本生成 JS 文件 | "es5"、"es2015" | "es5" | | useEsClasses | 让生成的 JavaScript 代码使用 ES2015 类。在使用 ES2015 目标时默认启用 | | null |

编译器选项的类型

部分 compilerOptions 使用新的类型而不是 String 类型:

| 选项 | 类型 | 示例 |

| jvmTarget | JvmTarget | compilerOptions.jvmTarget.set(JvmTarget.JVM_11) | | apiVersion 和 languageVersion | KotlinVersion | compilerOptions.languageVersion.set(KotlinVersion.KOTLIN_2_4) | | main | JsMainFunctionExecutionMode | compilerOptions.main.set(JsMainFunctionExecutionMode.NO_CALL) | | moduleKind | JsModuleKind | compilerOptions.moduleKind.set(JsModuleKind.MODULE_ES) | | sourceMapEmbedSources | JsSourceMapEmbedMode | compilerOptions.sourceMapEmbedSources.set(JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_INLINING) | | sourceMapNamesPolicy | JsSourceMapNamesPolicy | compilerOptions.sourceMapNamesPolicy.set(JsSourceMapNamesPolicy.SOURCE_MAP_NAMES_POLICY_FQ_NAMES) |

接下来做什么?

进一步了解: