跨平台程序的 Gradle DSL 参考文档
最终更新: 2025/02/06Kotlin Multiplatform Gradle plugin, 是一个用来创建 Kotlin Multiplatform 项目的工具. 本章我们提供关于它的参考文档; 当你为 Kotlin Multiplatform 项目编写 Gradle 编译脚本时可以参考本文档. 详情请参见 关于 Kotlin Multiplatform 项目的基本概念, 如何创建和配置跨平台项目.
插件 Id 与版本
Kotlin 跨平台 Gradle 插件的完整限定名称是 org.jetbrains.kotlin.multiplatform
. 如果使用 Kotlin Gradle DSL, 可以通过 kotlin("multiplatform")
语句应用这个插件. 插件的版本与 Kotlin 发布版本一致. 最新的版本是 2.1.0.
plugins {
kotlin("multiplatform") version "2.1.0"
}
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '2.1.0'
}
顶级代码块
Gradle 编译脚本中跨平台项目配置的顶级代码块是 kotlin {}
. 在 kotlin {}
之内, 你可以使用以下代码块:
编译目标
编译目标(Target) 是指针对某个特定的支持的平台的一系列编译功能, 包括源代码编译, 测试, 打包. Kotlin 对每个平台提供了编译目标, 让你能够指示 Kotlin 对指定的编译目标编译代码. 学习如何 设置编译目标.
每个编译目标可以包含一个或多个 编译任务(compilation). 除了用于测试和产品的默认的编译任务之外, 你还可以 创建自定义的编译任务.
跨平台项目的编译目标通过 kotlin {}
之内的相应代码块进行描述, 比如, jvm
, androidTarget
, iosArm64
. 可选的编译目标如下:
目标平台 | 编译目标 | 注释 |
---|---|---|
Kotlin/JVM |
| |
Kotlin/Wasm |
| 如果要在 JavaScript 环境中运行你的项目, 请使用这个配置. |
| 如果要支持 WASI 系统接口, 请使用这个配置. | |
Kotlin/JS |
| 选择执行环境:
更多详情请参见 创建 Kotlin JavaScript 项目. |
Kotlin/Native | 对 macOS, Linux, 和 Windows 主机, 目前支持的编译目标请参见 Kotlin/Native 支持的目标平台. | |
Android 应用程序和库 |
| 手动应用 Android Gradle plugin: 对每个 Gradle 子项目, 只能创建一个 Android 编译目标. |
note
构建中会忽略当前主机不支持的编译目标, 因此这些编译目标不会被发布.
kotlin {
jvm()
iosArm64()
macosX64()
js().browser()
}
编译目标的配置包括以下两部分:
对所有编译目标有效的 共通配置.
特定编译目标独有的配置.
每个编译目标可以有一个或多个 编译任务(compilation).
所有编译目标的共通配置
在任何一种编译目标代码块之内, 都可以使用以下声明:
JVM 编译目标
除 所有编译目标的共通配置 之外, jvm
编译目标还支持以下专有函数:
名称 | 解释 |
---|---|
| 在 JVM 编译目标的编译任务中包含 Java 源代码. |
对同时包含 Java 和 Kotlin 源代码文件的项目, 请使用这个函数. 注意 Java 源代码文件的默认目录与 Java 插件的默认设定不同. 相反, 这个默认设定继承自 Kotlin 源代码集. 比如, 如果 JVM 编译目标使用默认名称 jvm
, 那么默认的 Java 源代码文件目录是 src/jvmMain/java
(正式产品的 Java 源代码) 和 src/jvmTest/java
(测试程序的 Java 源代码). 详情请参见 在 JVM 编译任务中使用 Java 源代码.
kotlin {
jvm {
withJava()
}
}
Web 编译目标
js {}
代码块描述 Kotlin/JS 编译目标的配置, wasmJs {}
代码块描述与 JavaScript 交互的 Kotlin/Wasm 编译目标的配置. 根据编译目标的执行环境不同, 它们可以包含以下两个代码块之一:
详情请参见 配置 Kotlin/JS 项目.
还有另一个 wasmWasi {}
代码块描述支持 WASI 系统接口的 Kotlin/Wasm 编译目标的配置. 这种情况下, 只支持 nodejs
执行环境:
kotlin {
wasmWasi {
nodejs()
binaries.executable()
}
}
所有的 Web 编译目标, js
, wasmJs
, 以及 wasmWasi
, 还支持 binaries.executable()
调用. 这个调用明确的指示 Kotlin 编译器生成可执行文件. 更多详情请参见 Kotlin/JS 文档中的 执行环境 部分.
浏览器
browser {}
代码块包含以下配置代码块:
名称 | 解释 |
---|---|
| 测试运行任务的配置. |
| 项目运行的配置. |
| 使用 Webpack 编译项目的配置. |
| 输出文件的路径. |
kotlin {
js().browser {
webpackTask { /* ... */ }
testRuns { /* ... */ }
distribution {
directory = File("$projectDir/customdir/")
}
}
}
Node.js
nodejs {}
代码块包含测试和运行任务的配置:
名称 | 解释 |
---|---|
| 测试任务的配置. |
| 项目运行任务的配置. |
kotlin {
js().nodejs {
runTask { /* ... */ }
testRuns { /* ... */ }
}
}
原生(Native)编译目标
对于原生(Native)编译目标, 可以使用以下代码块:
名称 | 解释 |
---|---|
| 编译输出的 二进制文件(binary) 的配置. |
| 与 C 库文件交互 的配置. |
二进制文件(Binary)
有以下几种二进制文件(Binary)任务:
名称 | 解释 |
---|---|
| 正式产品的可执行文件. |
| 测试程序的可执行文件. |
| 共享的库文件(Shared library). |
| 静态库文件(Static library). |
| Objective-C 框架. |
kotlin {
linuxX64 { // 请在这里使用你的编译目标.
binaries {
executable {
// 针对这个二进制文件的配置.
}
}
}
}
对于二进制文件的配置, 可以设置的参数包括:
名称 | 解释 |
---|---|
| 用于构建二进制文件的编译任务. 默认情况下, |
| 构建二进制文件时, 传递给操作系统链接程序(linker)的选项. |
| 对输出文件自定义它的基本名称(base name). 最终的完整文件名会在这个基本名称之上加上相应系统的前缀和后缀. |
| 可执行二进制文件的入口点(entry point) 函数. 默认情况下, 是顶层包中的 |
| 用于访问输出文件. |
| 用于访问链接任务. |
| 用于访问可执行二进制文件的运行任务. 对于 |
| 用于 Objective-C 框架. 包含静态库(static library), 而不是动态库(dynamic library). |
binaries {
executable("my_executable", listOf(RELEASE)) {
// 以测试编译任务为基础, 构建一个二进制文件.
compilation = compilations["test"]
// 对连接器自定义命令行选项.
linkerOpts = mutableListOf("-L/lib/search/path", "-L/another/search/path", "-lmylib")
// 指定输出文件的基本名称.
baseName = "foo"
// 自定义入口点函数.
entryPoint = "org.example.main"
// 访问输出文件.
println("Executable path: ${outputFile.absolutePath}")
// 访问链接任务.
linkTask.dependsOn(additionalPreprocessingTask)
// 访问运行任务.
// 注意, 对于当前编译环境不支持的(non-host) 平台, runTask 将会是 null.
runTask?.dependsOn(prepareForRun)
}
framework("my_framework" listOf(RELEASE)) {
// 在框架中包含静态库而不是动态库.
isStatic = true
}
}
binaries {
executable('my_executable', [RELEASE]) {
// 以测试编译任务为基础, 构建一个二进制文件.
compilation = compilations.test
// 对连接器自定义命令行选项.
linkerOpts = ['-L/lib/search/path', '-L/another/search/path', '-lmylib']
// 指定输出文件的基本名称.
baseName = 'foo'
// 自定义入口点函数.
entryPoint = 'org.example.main'
// 访问输出文件.
println("Executable path: ${outputFile.absolutePath}")
// 访问链接任务.
linkTask.dependsOn(additionalPreprocessingTask)
// 访问运行任务.
// 注意, 对于当前编译环境不支持的(non-host) 平台, runTask 将会是 null.
runTask?.dependsOn(prepareForRun)
}
framework('my_framework' [RELEASE]) {
// 在框架中包含静态库而不是动态库.
isStatic = true
}
}
详情请参见 构建原生二进制文件.
CInterops
cinterops
用于描述与原生库的交互. 要与一个库交互, 请添加一个 cinterops
代码块, 并定义它的参数, 如下:
名称 | 解释 |
---|---|
| 描述原生 API 的 |
| 生成 Kotlin API 时的包前缀. |
| cinterop 工具传递给编译器的选项. |
| 用于查找头文件的目录. |
| 绑定中需要包含的头文件. |
| 绑定中需要包含的头文件列表. |
kotlin {
linuxX64 { // 这里请替换为你需要的编译目标.
compilations.getByName("main") {
val myInterop by cinterops.creating {
// 描述原生 API 的 def 文件.
// 默认路径是 src/nativeInterop/cinterop/<interop-name>.def
definitionFile.set(project.file("def-file.def"))
// 生成的 Kotlin API 所在的包.
packageName("org.sample")
// cinterop 工具传递给编译器的参数.
compilerOpts("-Ipath/to/headers")
// 用于查找头文件的目录 (等同于 -I<path> 编译选项).
includeDirs.allHeaders("path1", "path2")
// includeDirs.allHeaders 的缩写方式.
includeDirs("include/directory", "another/directory")
// 绑定中需要包含的头文件.
header("path/to/header.h")
headers("path/to/header1.h", "path/to/header2.h")
}
val anotherInterop by cinterops.creating { /* ... */ }
}
}
}
kotlin {
linuxX64 { // 这里请替换为你需要的编译目标.
compilations.main {
cinterops {
myInterop {
// 描述原生 API 的 def 文件.
// 默认路径是 src/nativeInterop/cinterop/<interop-name>.def
definitionFile = project.file("def-file.def")
// 生成的 Kotlin API 所在的包.
packageName 'org.sample'
// cinterop 工具传递给编译器的参数.
compilerOpts '-Ipath/to/headers'
// 用于查找头文件的目录 (等同于 -I<path> 编译选项).
includeDirs.allHeaders("path1", "path2")
// includeDirs.allHeaders 的缩写方式.
includeDirs("include/directory", "another/directory")
// 绑定中需要包含的头文件.
header("path/to/header.h")
headers("path/to/header1.h", "path/to/header2.h")
}
anotherInterop { /* ... */ }
}
}
}
}
关于 cinterop 的属性, 更多详情请参见 定义文件.
Android 编译目标
Kotlin Multiplatform plugin 针对 Android 编译目标提供了两个专有的函数. 这两个函数帮助你设置 构建变体(build variants):
名称 | 解释 |
---|---|
| 指定用于发布的构建变体. 详情请参见 发布 Android 库. |
| 发布所有的构建变体. |
kotlin {
androidTarget {
publishLibraryVariants("release")
}
}
详情请参见 针对 Android 的编译.
note
kotlin {}
代码块之内的androidTarget
配置, 不会替代任何 Android 项目的编译配置. 关于如何为 Android 项目编写编译脚本, 详情请参见 Android 开发文档.
源代码集(Source set)
sourceSets {}
代码块描述项目的源代码集. 源代码集是指在某个编译任务中一起参与编译的 Kotlin 源代码文件, 相关的资源文件, 依赖项目, 以及语言设置.
跨平台项目的各个编译目标都包含 预定义的源代码集; 开发者也可以根据需要创建 自定义的源代码集.
预定义的源代码集
创建会在跨平台项目时会自动设置预定义的源代码集. 可用的预定义源代码集如下:
名称 | 解释 |
---|---|
| 所有平台共用的代码和资源. 对所有的跨平台项目都可用. 项目的所有 main 编译任务都会使用这个源代码集. |
| 所有平台共用的测试代码和资源. 对所有的跨平台项目都可用. 项目的所有 test 编译任务都会使用这个源代码集. |
<targetName><compilationName> | 各个编译目标专有的源代码集. 这里的 <targetName> 是预定义编译目标的名称, <compilationName> 是这个编译目标的编译任务名称. 比如: |
使用 Kotlin Gradle DSL 时, 预定义源代码集的代码块需要标记为 by getting
.
kotlin {
sourceSets {
val commonMain by getting { /* ... */ }
}
}
kotlin {
sourceSets {
commonMain { /* ... */ }
}
}
详情请参见 源代码集.
自定义源代码集
自定义源代码集由项目开发者手动创建. 要创建一个自定义源代码集, 需要在 sourceSets
之内, 使用自定义源代码集的名称, 添加一个代码块. 如果使用 Kotlin Gradle DSL, 需要将自定义源代码集标记为 by creating
.
kotlin {
sourceSets {
val myMain by creating { /* ... */ } // 创建一个新的, 名为 'MyMain' 的源代码集
}
}
kotlin {
sourceSets {
myMain { /* ... */ } // 创建或设置一个名称为 'myMain' 的源代码集
}
}
注意, 新创建的源代码集不会关联到其他源代码集. 如果要在项目的编译任务中使用这个源代码集, 请将它关联到其他源代码集.
源代码集的参数
源代码集的配置保存在相应的 sourceSets {}
代码块之内. 一个源代码集包含以下参数:
kotlin {
sourceSets {
val commonMain by getting {
kotlin.srcDir("src")
resources.srcDir("res")
dependencies {
/* ... */
}
}
}
}
kotlin {
sourceSets {
commonMain {
kotlin.srcDir('src')
resources.srcDir('res')
dependencies {
/* ... */
}
}
}
}
编译任务
一个编译目标可以包含一个或多个编译任务, 比如, 用于正式产品的编译任务, 或用于测试代码的编译任务. 编译目标创建时会自动添加 预定义的编译任务. 你也可以另外创建 自定义编译任务.
如果需要访问一个编译目标的所有编译任务, 或某个特定的编译任务, 请使用 compilations
对象集合. 通过 compilations
, 你可以使用名称来访问一个编译任务.
详情请参见 配置编译任务.
预定义的编译任务
对项目的每个编译目标, 会自动创建预定义的编译任务, Android 编译目标除外. 可用的预定义编译任务如下:
名称 | 解释 |
---|---|
| 用于正式产品源代码的编译任务. |
| 用于测试代码的编译任务. |
kotlin {
jvm {
val main by compilations.getting {
output // 得到 main 编译任务的输出
}
compilations["test"].runtimeDependencyFiles // 得到 test 编译任务的运行时 classpath
}
}
kotlin {
jvm {
compilations.main.output // 得到 main 编译任务的输出
compilations.test.runtimeDependencyFiles // 得到 test 编译任务的运行时 classpath
}
}
自定义编译任务
除了预定义的编译任务之外, 你也可以创建自己的自定义编译任务. 要创建一个自定义编译任务, 请在 compilations
集合中添加一个新的项目. 如果使用 Kotlin Gradle DSL, 自定义编译任务需要标记为 by creating
.
详情请参见 创建自定义编译任务.
kotlin {
jvm() {
compilations {
val integrationTest by compilations.creating {
defaultSourceSet {
dependencies {
/* ... */
}
}
// 创建一个 test 任务, 用于运行这个编译任务产生的测试代码:
tasks.register<Test>("integrationTest") {
/* ... */
}
}
}
}
}
kotlin {
jvm() {
compilations.create('integrationTest') {
defaultSourceSet {
dependencies {
/* ... */
}
}
// 创建一个 test 任务, 用于运行这个编译任务产生的测试代码:
tasks.register('jvmIntegrationTest', Test) {
/* ... */
}
}
}
}
编译任务的参数
一个编译任务可以包含以下参数:
名称 | 解释 |
---|---|
| 编译任务的默认源代码集. |
| 源代码集, 参与这个编译任务. |
| 源代码集, 参与这个编译任务, 以及通过 |
| 应用于这个编译任务的编译器选项. 关于所有可用的选项, 请参见 编译选项. |
| 编译 Kotlin 源代码的 Gradle 任务. |
|
|
| 编译这个编译任务中所有源代码的Gradle 任务的名称. |
| 编译任务的输出. |
| 这个编译任务的编译时刻依赖项目文件(classpath). 对所有的 Kotlin/Native 编译任务, 这个参数自动包含标准库和平台依赖项. |
| 这个编译任务的运行时刻依赖项目文件(classpath). |
kotlin {
jvm {
val main by compilations.getting {
compilerOptions.configure {
// 为 'main' 编译任务设置 Kotlin 编译器选项:
jvmTarget.set(JvmTarget.JVM_1_8)
}
compileKotlinTask // 得到编译 Kotlin 源代码的 Gradle 任务 'compileKotlinJvm'
output // 得到 main 编译任务的输出
}
compilations["test"].runtimeDependencyFiles // 得到 test 编译任务的运行时刻 classpath
}
// 对所有编译目标的所有编译任务的设置:
compilerOptions {
allWarningsAsErrors.set(true)
}
}
kotlin {
jvm {
compilations.main.compilerOptions.configure {
// 为 'main' 编译任务设置 Kotlin 编译器选项:
jvmTarget = JvmTarget.JVM_1_8
}
compilations.main.compileKotlinTask // 得到编译 Kotlin 源代码的 Gradle 任务 'compileKotlinJvm'
compilations.main.output // 得到 main 编译任务的输出
compilations.test.runtimeDependencyFiles // 得到 test 编译任务的运行时刻 classpath
}
// 对所有编译目标的所有编译任务的设置:
compilerOptions {
allWarningsAsErrors = true
}
}
编译器选项
在你的项目中, 你可以在 3 个不同的层级配置编译器选项:
扩展级(Extension Level), 在
kotlin {}
代码块内配置.编译目标级(Target Level), 在一个编译目标代码块内配置.
编译单元级(Compilation Unit Level), 通常在指定的编译任务内配置.
较高层级中的设置, 会用作较低层级中的默认值:
扩展级中设置的编译器选项, 会作为编译目标级选项的默认值, 包括共用的源代码集, 例如
commonMain
,nativeMain
, 和commonTest
.编译目标级中设置的编译器选项, 会作为编译单元 (task) 级选项的默认值, 例如
compileKotlinJvm
和compileTestKotlinJvm
task.
较低层级中的配置, 会覆盖较高层级中的类似设置:
Task 级编译器选项, 会覆盖编译目标级或扩展级中的类似设置.
编译目标级编译器选项, 会覆盖扩展级中的类似设置.
关于可用的编译器选项, 详情请参见 所有编译器选项.
扩展级(Extension Level)
要对你的项目中的所有编译目标配置编译器选项, 请使用顶级代码块中的 compilerOptions {}
代码块:
kotlin {
// 配置所有编译目标的所有编译任务
compilerOptions {
allWarningsAsErrors.set(true)
}
}
kotlin {
// 配置所有编译目标的所有编译任务
compilerOptions {
allWarningsAsErrors = true
}
}
编译目标级(Target Level)
要对你的项目中指定的编译目标配置编译器选项, 请使用编译目标代码块之内的 compilerOptions {}
代码块:
kotlin {
jvm {
// 配置 JVM 编译目标的所有编译任务
compilerOptions {
allWarningsAsErrors.set(true)
}
}
}
kotlin {
jvm {
// 配置 JVM 编译目标的所有编译任务
compilerOptions {
allWarningsAsErrors = true
}
}
}
编译单元级(Compilation Unit Level)
要对指定的 task 配置编译器选项, 请使用 task 之内的 compilerOptions {}
代码块:
task.named<KotlinJvmCompile>("compileKotlinJvm") {
compilerOptions {
allWarningsAsErrors.set(true)
}
}
task.named<KotlinJvmCompile>("compileKotlinJvm") {
compilerOptions {
allWarningsAsErrors = true
}
}
要对指定的编译任务配置编译器选项, 请使用这个编译任务的 task provider 之内的 compilerOptions {}
代码块:
kotlin {
jvm {
compilations.named(KotlinCompilation.MAIN_COMPILATION_NAME) {
compileTaskProvider.configure {
// 配置 'main' 编译任务:
compilerOptions {
allWarningsAsErrors.set(true)
}
}
}
}
}
kotlin {
jvm {
compilations.named(KotlinCompilation.MAIN_COMPILATION_NAME) {
compileTaskProvider.configure {
// 配置 'main' 编译任务:
compilerOptions {
allWarningsAsErrors = true
}
}
}
}
}
依赖项目
源代码集的 dependencies {}
代码块包含这个源代码集的依赖项目.
详情请参见 配置依赖项.
有 4 种类型的依赖项目:
名称 | 解释 |
---|---|
| 当前模块的 API 中使用的依赖项目. |
| 当前模块中使用的依赖项目, 但不向外暴露. |
| 只在当前模块的编译任务中使用的依赖项目. |
| 运行时刻的依赖项目, 但在任何模块的编译任务中都不可见. |
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api("com.example:foo-metadata:1.0")
}
}
val jvmMain by getting {
dependencies {
implementation("com.example:foo-jvm:1.0")
}
}
}
}
kotlin {
sourceSets {
commonMain {
dependencies {
api 'com.example:foo-metadata:1.0'
}
}
jvmMain {
dependencies {
implementation 'com.example:foo-jvm:1.0'
}
}
}
}
除此之外, 源代码集之间还可以相互依赖, 形成一种层级结构. 这种情况下, 应该使用 dependsOn()
关系.
在编译脚本的最顶层 dependencies {}
代码块中, 也可以声明源代码集的依赖项目. 这种情况下, 依赖项目声明需要使用 <sourceSetName><DependencyKind>
格式, 比如, commonMainApi
.
dependencies {
"commonMainApi"("com.example:foo-common:1.0")
"jvm6MainApi"("com.example:foo-jvm6:1.0")
}
dependencies {
commonMainApi 'com.example:foo-common:1.0'
jvm6MainApi 'com.example:foo-jvm6:1.0'
}
语言设置
源代码集的 languageSettings {}
代码块用来定义项目分析和构建的某些方面. 可选的语言设置如下:
名称 | 解释 |
---|---|
| 与某个 Kotlin 版本保持源代码级的兼容性. |
| 允许使用从指定的 Kotlin 版本的库才开始提供的 API 声明. |
| 启用指定的语言特性. 这个参数可选的值, 对应于那些目前还处于试验状态的语言特性, 或还没有正式公布的语言特性. |
| 允许使用指定的 明确要求使用者同意(Opt-in) 注解. |
|
kotlin {
sourceSets.all {
languageSettings.apply {
languageVersion = "2.1" // 可选的值: "1.8", "1.9", "2.0", "2.1"
apiVersion = "2.1" // 可选的值: "1.8", "1.9", "2.0", "2.1"
enableLanguageFeature("InlineClasses") // 这里请使用语言特性的名称
optIn("kotlin.ExperimentalUnsignedTypes") // 这里请使用注解的完全限定名称
progressiveMode = true // 默认值为 false
}
}
}
kotlin {
sourceSets.all {
languageSettings {
languageVersion = '2.1' // 可选的值: '1.8', '1.9', '2.0', '2.1'
apiVersion = '2.1' // 可选的值: '1.8', '1.9', '2.0', '2.1'
enableLanguageFeature('InlineClasses') // 这里请使用语言特性的名称
optIn('kotlin.ExperimentalUnsignedTypes') // 这里请使用注解的完全限定名称
progressiveMode = true // 默认值为 false
}
}
}