Сборка конечных нативных библиотек
По умолчанию, целевой Kotlin/Native компилируется в библиотеку *.klib артефакт, который может быть использован Kotlin/Native как зависимость, но не может быть запущен или использован как нативная библиотека.
Для объявления конечных нативных библиотек, таких как исполняемые файлы или динамические библиотеки, используйте свойство binaries нативного целевого объекта. Это свойство представляет собой коллекцию нативных библиотек, собранных для этого целевого объекта дополнительно к стандартному *.klib артефакту и предоставляет набор методов для их объявления и конфигурации.
Объявление библиотек
Используйте следующие фабричные методы для объявления элементов коллекции binaries.
Фабричный метод |
Тип библиотеки |
Доступно для |
|---|---|---|
|
Исполняемый файл |
Все нативные целевые объекты |
|
Исполняемый файл для тестов |
Все нативные целевые объекты |
|
Динамическая нативная библиотека |
Все нативные целевые объекты, кроме |
|
Статическая нативная библиотека |
Все нативные целевые объекты, кроме |
|
Фреймворк Objective-C |
Только целевые объекты macOS, iOS, watchOS и tvOS |
Самый простой вариант не требует дополнительных параметров и создаёт по одной библиотеке для каждого типа сборки. В настоящее время доступны два типа сборки:
DEBUG— создаёт не оптимизированную библиотеку с информацией об отладкеRELEASE— создаёт оптимизированную библиотеку без информации об отладке
Следующий фрагмент кода создаёт две исполняемые библиотеки, для отладки и релизной сборки:
kotlin {
linuxX64 { // Define your target instead.
binaries {
executable {
// Binary configuration.
}
}
}
}
Можно опустить лямбда-выражение, если нет необходимости в дополнительной конфигурации:
binaries {
executable()
}
Можно указать для каких типов сборки создавать библиотеки. В следующем примере создаётся только исполняемый файл debug:
binaries {
executable(listOf(DEBUG)) {
// Binary configuration.
}
}
binaries {
executable([DEBUG]) {
// Binary configuration.
}
}
Также можно объявлять библиотеки с пользовательскими именами:
binaries {
executable("foo", listOf(DEBUG)) {
// Binary configuration.
}
// It's possible to drop the list of build types
// (in this case, all the available build types will be used).
executable("bar") {
// Binary configuration.
}
}
binaries {
executable('foo', [DEBUG]) {
// Binary configuration.
}
// It's possible to drop the list of build types
// (in this 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.
// 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['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.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')
}
}
}
Например, вы реализуете несколько модулей на Kotlin и хотите получить доступ к ним из Swift. Использование нескольких Kotlin/Native фреймворков в приложении Swift ограничено, но вы можете создать общий фреймворк и экспортировать в него все эти модули.
Когда вы экспортируете зависимость, она включает весь её API в API фреймворка. Компилятор добавляет код из этой зависимости в фреймворк, даже если вы используете лишь малую его часть. Это отключает удаление неиспользуемого кода для экспортируемой зависимости (и для её зависимостей, до некоторой степени).
По умолчанию, экспорт работает не транзитивно. Это означает, что если вы экспортируете библиотеку foo зависящую от библиотеки bar, только методы foo будут добавлены в выходной фреймворк.
Вы можете изменить это поведение, используя опцию transitiveExport. Если она установлена в значение true, объявления библиотеки bar также будут экспортированы.
binaries {
framework {
export(project(":dependency"))
// Export transitively.
transitiveExport = true
}
}
binaries {
framework {
export project(':dependency')
// Export transitively.
transitiveExport = true
}
}
Создание универсальных фреймворков
По умолчанию, фреймворк Objective-C, созданный Kotlin/Native, поддерживает только одну платформу. Однако, вы можете объединить такие фреймворки в одну универсальную (fat) библиотеку, используя инструмент lipo. Эта операция особенно полезна для iOS фреймворков 32-битных и 64-битных. В этом случае, вы можете использовать полученный универсальный фреймворк как на 32-битных, так и на 64-битных устройствах.
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.register<FatFrameworkTask>("debugFatFramework") {
// 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")
)
}
}
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.
tasks.register("debugFatFramework", 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")
)
}
}
Создание XCFrameworks
Все проекты Kotlin Multiplatform могут использовать XCFrameworks в качестве выходного результата для сбора логики для всех целевых платформ и архитектур в одном пакете. В отличие от универсальных (fat) фреймворков, вам не нужно удалять все ненужные архитектуры перед публикацией приложения в App Store.
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
plugins {
kotlin("multiplatform")
}
kotlin {
val xcf = XCFramework()
ios {
binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
watchos {
binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
tvos {
binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
}
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkConfig
plugins {
id 'org.jetbrains.kotlin.multiplatform'
}
kotlin {
def xcf = new XCFrameworkConfig(project)
ios {
binaries.framework {
baseName = "shared"
xcf.add(it)
}
}
watchos {
binaries.framework {
baseName = "shared"
xcf.add(it)
}
}
tvos {
binaries.framework {
baseName = "shared"
xcf.add(it)
}
}
}
При объявлении XCFrameworks плагин Kotlin Gradle зарегистрирует три задачи Gradle:
assembleXCFrameworkassembleDebugXCFramework(дополнительный артефакт отладки, содержащий dSYMs)assembleReleaseXCFramework
Если вы используете интеграцию CocoaPods в своих проектах, вы можете создать XCFrameworks с помощью плагина Kotlin CocoaPods Gradle. Он включает следующие задачи, которые создают XCFrameworks со всеми зарегистрированными целевыми платформами и генерируют файлы podspec:
podPublishReleaseXCFramework, который генерирует релизный XCFramework вместе с файлом podspec.podPublishDebugXCFramework, который генерирует отладочный XCFramework вместе с файлом podspec.podPublishXCFramework, который генерирует как отладочный, так и релизный XCFrameworks вместе с файлом podspec.
Это может помочь вам распространять общие части вашего проекта отдельно от мобильных приложений через CocoaPods. Вы также можете использовать XCFrameworks для публикации в частных или публичных репозиториях podspec.
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform-build-native-binaries.html