Spec-Zone.ru › Kotlin 1.7

Сборка конечных нативных библиотек

По умолчанию, цель 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 — создает оптимизированную библиотеку без информации для отладки

Следующий фрагмент создает две исполняемые библиотеки, 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.

Статические и динамические библиотеки имеют суффиксы static и shared соответственно, например, fooDebugStatic или barReleaseShared.

// 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 в API фреймворка. Компилятор добавляет код из этой зависимости в фреймворк, даже если вы используете лишь малую его часть. Это отключает удаление неиспользуемого кода для экспортированной зависимости (и для её зависимостей, в определённой степени).

По умолчанию, экспорт работает не транзитивно. Это означает, что если вы экспортируете библиотеку foo зависящую от библиотеки bar, только методы foo добавляются в выходной фреймворк.

Вы можете изменить это поведение с помощью параметра transitiveExport. Если он установлен на true, объявления библиотеки bar также будут экспортированы.

Не рекомендуется использовать transitiveExport: это добавляет все транзитивные зависимости экспортированных зависимостей в фреймворк. Это может увеличить как время компиляции, так и размер бинарника.

В большинстве случаев вам не нужно добавлять все эти зависимости в API фреймворка. Используйте export явно для зависимостей, к которым вы хотите получить прямой доступ из Swift или Objective-C кода.

binaries {
    framework {
        export(project(":dependency"))
        // Export transitively.
        transitiveExport = true
    }
}
binaries {
    framework {
        export project(':dependency')
        // Export transitively.
        transitiveExport = true
    }
}

Сборка универсальных фреймворков

По умолчанию, фреймворк Objective-C, созданный Kotlin/Native, поддерживает только одну платформу. Однако вы можете объединить такие фреймворки в единый универсальный (fat) бинарник с помощью инструмента lipo. Эта операция особенно уместна для 32-битных и 64-битных iOS фреймворков. В этом случае вы можете использовать получившийся универсальный фреймворк как на 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")
        )
    }
}
END_OF_DOCUMENT_MARKER

Создание 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:

  • assembleXCFramework

  • assembleDebugXCFramework (дополнительно артефакт отладки, содержащий dSYMs)

  • assembleReleaseXCFramework

Если вы используете интеграцию CocoaPods в своих проектах, вы можете создавать XCFrameworks с помощью плагина Kotlin CocoaPods Gradle. Он включает следующие задачи, которые создают XCFrameworks со всеми зарегистрированными целевыми объектами и генерируют файлы podspec:

  • podPublishReleaseXCFramework, которая генерирует релизный XCFramework вместе с файлом podspec.

  • podPublishDebugXCFramework, которая генерирует отладочный XCFramework вместе с файлом podspec.

  • podPublishXCFramework, которая генерирует как отладочный, так и релизный XCFrameworks вместе с файлом podspec.

Это может помочь вам распределять общие части вашего проекта отдельно от мобильных приложений через CocoaPods. Вы также можете использовать XCFrameworks для публикации в частных или публичных репозиториях podspec.

Публикация Kotlin-фреймворков в публичные репозитории не рекомендуется, если эти фреймворки созданы для разных версий Kotlin. Это может привести к конфликтам в проектах конечных пользователей.

Настройка файла Info.plist

При создании фреймворка компилятор Kotlin/Native генерирует файл информации Info.plist, Info.plist. Вы можете настроить его свойства с помощью соответствующего бинарного параметра:

Свойство

Бинарный параметр

CFBundleIdentifier

bundleId

CFBundleShortVersionString

bundleShortVersionString

CFBundleVersion

bundleVersion

Для включения этой функции передайте флаг компилятора Xbinary=$option=$value или установите binaryOption("option", "value") Gradle DSL для конкретного фреймворка:

binaries {
    framework {
        binaryOption("bundleId", "com.example.app")
        binaryOption("bundleVersion", "2")
    }
}
Последнее изменение: 20 сентября 2022 г.
Настройка компиляций Справочник по Gradle DSL для Multiplatform

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API