Создание окончательных нативных библиотек
По умолчанию, целевой объект Kotlin/Native компилируется в библиотеку *.klib , которую можно использовать в Kotlin/Native как зависимость, но нельзя запускать или использовать как нативную библиотеку.
Для объявления окончательных нативных библиотек, таких как исполняемые файлы или динамические библиотеки, используйте свойство binaries целевого объекта. Это свойство представляет коллекцию нативных библиотек, созданных для данного объекта, помимо стандартной библиотеки *.klib , и предоставляет набор методов для их объявления и настройки.
Плагин
kotlin-multiplatformпо умолчанию не создаёт никаких библиотек для производства. Единственная доступная по умолчанию библиотека — это исполняемый файл для отладки тестов, который позволяет запускать модульные тесты из компиляцииtest.
Объявление библиотек
Используйте следующие фабричные методы для объявления элементов коллекции binaries.
| Фабричный метод | Тип библиотеки | Доступно для |
|---|---|---|
executable | Исполняемый файл продукта | Все нативные целевые объекты |
test | Исполняемый файл теста | Все нативные целевые объекты |
sharedLib | Динамическая нативная библиотека | Все нативные целевые объекты, кроме WebAssembly
|
staticLib | Статическая нативная библиотека | Все нативные целевые объекты, кроме WebAssembly
|
framework | Фреймворк Objective-C | Только целевые объекты macOS, iOS, watchOS и tvOS |
Простейшая версия не требует дополнительных параметров и создаёт по одной библиотеке для каждого типа сборки. В настоящее время доступны два типа сборки:
-
DEBUG— создаёт не оптимизированную библиотеку с информацией для отладки -
RELEASE— создаёт оптимизированную библиотеку без информации для отладки
Следующий фрагмент кода создаёт две исполняемые библиотеки: для отладки и релизной сборки.
kotlin {
linuxX64 { // Use your target instead.
binaries {
executable {
// Binary configuration.
}
}
}
}
Вы можете опустить лямбда-выражение, если не требуется дополнительная настройка:
binaries {
executable()
}
Можно указать, для каких типов сборки создавать библиотеки. В следующем примере создаётся только исполняемый файл для отладки debug.
binaries {
executable([DEBUG]) {
// Binary configuration.
}
}
binaries {
executable(listOf(DEBUG)) {
// Binary configuration.
}
}
Также можно объявлять библиотеки с пользовательскими именами.
binaries {
executable('foo', [DEBUG]) {
// Binary configuration.
}
// It's possible to drop the list of build types (in which case, all the available build types will be used).
executable('bar') {
// Binary configuration.
}
}
binaries {
executable("foo", listOf(DEBUG)) {
// Binary configuration.
}
// It's possible to drop the list of build types (in which case, all the available build types will be used).
executable("bar") {
// Binary configuration.
}
}
Первый аргумент задаёт префикс имени, который является стандартным именем файла библиотеки. Например, для Windows код создаёт файлы foo.exe и bar.exe. Вы также можете использовать префикс имени для доступа к библиотеке в скрипте сборки.
Доступ к библиотекам
Вы можете получить доступ к библиотекам, чтобы настроить их или получить их свойства (например, путь к выходному файлу).
Вы можете получить доступ к библиотеке по её уникальному имени. Это имя основано на префиксе имени (если он указан), типе сборки и типу библиотеки, следуя шаблону: <optional-name-prefix><build-type><binary-kind>, например, releaseFramework или testDebugExecutable.
Статические и динамические библиотеки имеют суффиксы static и shared соответственно, например,
fooDebugStaticилиbarReleaseShared.
// Fails if there is no such binary.
binaries['fooDebugExecutable']
binaries.fooDebugExecutable
binaries.getByName('fooDebugExecutable')
// Returns null if there is no such binary.
binaries.findByName('fooDebugExecutable')
// Fails if there is no such binary.
binaries["fooDebugExecutable"]
binaries.getByName("fooDebugExecutable")
// Returns null if there is no such binary.
binaries.findByName("fooDebugExecutable")
Альтернативно, вы можете получить доступ к библиотеке по её префиксу имени и типу сборки, используя типизированные геттеры.
// Fails if there is no such binary.
binaries.getExecutable('foo', DEBUG)
binaries.getExecutable(DEBUG) // Skip the first argument if the name prefix isn't set.
binaries.getExecutable('bar', 'DEBUG') // You also can use a string for build type.
// Similar getters are available for other binary kinds:
// getFramework, getStaticLib and getSharedLib.
// Returns null if there is no such binary.
binaries.findExecutable('foo', DEBUG)
// Similar getters are available for other binary kinds:
// findFramework, findStaticLib and findSharedLib.
// Fails if there is no such binary.
binaries.getExecutable("foo", DEBUG)
binaries.getExecutable(DEBUG) // Skip the first argument if the name prefix isn't set.
binaries.getExecutable("bar", "DEBUG") // You also can use a string for build type.
// Similar getters are available for other binary kinds:
// getFramework, getStaticLib and getSharedLib.
// Returns null if there is no such binary.
binaries.findExecutable("foo", DEBUG)
// Similar getters are available for other binary kinds:
// findFramework, findStaticLib and findSharedLib.
Экспорт зависимостей в библиотеки
При построении фреймворка Objective-C или нативной библиотеки (динамической или статической), вам может потребоваться упаковать не только классы текущего проекта, но и классы его зависимостей. Укажите, какие зависимости экспортировать в библиотеку, используя метод export.
kotlin {
sourceSets {
macosMain.dependencies {
// Will be exported.
api project(':dependency')
api 'org.example:exported-library:1.0'
// Will not be exported.
api 'org.example:not-exported-library:1.0'
}
}
macosX64("macos").binaries {
framework {
export project(':dependency')
export 'org.example:exported-library:1.0'
}
sharedLib {
// It's possible to export different sets of dependencies to different binaries.
export project(':dependency')
}
}
}
kotlin {
sourceSets {
macosMain.dependencies {
// Will be exported.
api(project(":dependency"))
api("org.example:exported-library:1.0")
// Will not be exported.
api("org.example:not-exported-library:1.0")
}
}
macosX64("macos").binaries {
framework {
export(project(":dependency"))
export("org.example:exported-library:1.0")
}
sharedLib {
// It's possible to export different sets of dependencies to different binaries.
export(project(':dependency'))
}
}
}
Вы можете экспортировать только
apiзависимости соответствующего набора исходных кодов.
Вы можете экспортировать зависимости Maven, но из-за текущих ограничений Gradle metadata такая зависимость должна быть либо зависимостью платформы (например,kotlinx-coroutines-core-native_debug_macos_x64вместоkotlinx-coroutines-core-native), либо экспортироваться транзитивно.
По умолчанию, экспорт работает не транзитивно. Это означает, что если вы экспортируете библиотеку foo , которая зависит от библиотеки bar , в выходной фреймворк будут добавлены только методы foo.
Вы можете изменить это поведение, используя флаг transitiveExport. Если он установлен в true , то объявления библиотеки bar также будут экспортированы.
binaries {
framework {
export project(':dependency')
// Export transitively.
transitiveExport = true
}
}
binaries {
framework {
export(project(":dependency"))
// Export transitively.
transitiveExport = true
}
}
Например, предположим, что вы написали несколько модулей на Kotlin и хотите получить к ним доступ из Swift. Поскольку использование нескольких фреймворков Kotlin/Native в одном приложении Swift ограничено, вы можете создать один универсальный фреймворк и экспортировать в него все эти модули.
Создание универсальных фреймворков
По умолчанию, фреймворк Objective-C, созданный Kotlin/Native, поддерживает только одну платформу. Однако вы можете объединить такие фреймворки в единую универсальную (fat) библиотеку, используя инструмент lipo. Это особенно полезно для iOS-фреймворков 32- и 64-битных архитектур. В этом случае вы можете использовать получившийся универсальный фреймворк как на устройствах с 32-битной, так и на 64-битной архитектурой.
Универсальный фреймворк должен иметь то же базовое имя, что и исходные фреймворки.
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
kotlin {
// Create and configure the targets.
targets {
iosArm32("ios32")
iosArm64("ios64")
configure([ios32, ios64]) {
binaries.framework {
baseName = "my_framework"
}
}
}
// Create a task building a fat framework.
task debugFatFramework(type: FatFrameworkTask) {
// The fat framework must have the same base name as the initial frameworks.
baseName = "my_framework"
// The default destination directory is '<build directory>/fat-framework'.
destinationDir = file("$buildDir/fat-framework/debug")
// Specify the frameworks to be merged.
from(
targets.ios32.binaries.getFramework("DEBUG"),
targets.ios64.binaries.getFramework("DEBUG")
)
}
}
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
kotlin {
// Create and configure the targets.
val ios32 = iosArm32("ios32")
val ios64 = iosArm64("ios64")
configure(listOf(ios32, ios64)) {
binaries.framework {
baseName = "my_framework"
}
}
// Create a task to build a fat framework.
tasks.create("debugFatFramework", FatFrameworkTask::class) {
// The fat framework must have the same base name as the initial frameworks.
baseName = "my_framework"
// The default destination directory is '<build directory>/fat-framework'.
destinationDir = buildDir.resolve("fat-framework/debug")
// Specify the frameworks to be merged.
from(
ios32.binaries.getFramework("DEBUG"),
ios64.binaries.getFramework("DEBUG")
)
}
}
© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/mpp-build-native-binaries.html