Kotlin/Native 라이브러리

Kotlin/Native 라이브러리

Kotlin/Native에서는 프로젝트의 빌드 파일이나 Kotlin/Native 컴파일러를 사용해서 라이브러리용 *.klib 아티팩트를 만들 수 있어요.

출처: Kotlin/Native libraries

본문

라이브러리 컴파일

Gradle 빌드 파일 사용하기

Gradle 빌드 파일에서 Kotlin/Native 타깃(지원 타깃)을 지정하면 *.klib 라이브러리 아티팩트를 컴파일할 수 있어요:

  1. build.gradle(.kts) 파일에 Kotlin/Native 타깃을 하나 이상 선언합니다. 예를 들면:
// build.gradle.kts
plugins {
    kotlin("multiplatform") version "2.4.20"
}

kotlin {
    macosArm64()    // on macOS
    // linuxArm64() // on Linux
    // mingwX64()   // on Windows
}
  1. <target>Klib 태스크를 실행합니다. 예를 들면:
./gradlew macosArm64Klib

Gradle은 해당 타깃의 소스 파일을 자동으로 컴파일하고 .klib 아티팩트를 프로젝트의 build/libs 디렉터리에 생성합니다.

Kotlin/Native 컴파일러 사용하기

Kotlin/Native 컴파일러로 라이브러리를 만들려면:

  1. Kotlin/Native 컴파일러를 다운로드하고 설치합니다.(컴파일러 다운로드·설치)
  2. Kotlin/Native 소스 파일을 라이브러리로 컴파일하려면 -produce library 또는 -p library 옵션을 사용하세요:
kotlinc-native foo.kt -p library -o bar

이 명령은 foo.kt 파일의 내용을 bar라는 이름의 라이브러리로 컴파일하여 bar.klib 아티팩트를 생성합니다. 3. 다른 파일을 라이브러리에 링크하려면 -library <name> 또는 -l <name> 옵션을 사용합니다. 예를 들면:

kotlinc-native qux.kt -l bar

이 명령은 qux.kt 소스 파일과 bar.klib 라이브러리 내용을 컴파일하고 최종 실행 바이너리 program.kexe를 생성합니다.

klib 유틸리티

klib 라이브러리 관리 유틸리티를 사용하면 다음 문법으로 라이브러리를 검사할 수 있어요:

klib <command> <library path> [<option>]

현재 사용 가능한 명령은 다음과 같습니다:

명령 설명
info 라이브러리에 대한 일반 정보.
dump-abi 라이브러리의 ABI 스냅샷을 덤프. 스냅샷의 각 줄은 하나의 선언에 해당. 선언에 ABI 비호환 변경이 생기면 스냅샷의 해당 줄에서 확인 가능.
dump-ir 라이브러리 선언의 중간 표현(IR)을 출력으로 덤프. 디버깅에만 사용.
dump-ir-signatures 모든 비공개 라이브러리 선언과 이 라이브러리가 소비하는 모든 비공개 선언의 IR 시그니처를(두 개의 별도 목록으로) 덤프. IR의 데이터만으로 동작.
dump-ir-inlinable-functions 라이브러리의 인라이너블 함수 IR을 출력으로 덤프. 디버깅에만 사용.
dump-metadata 모든 라이브러리 선언의 메타데이터를 출력으로 덤프. 디버깅에만 사용.
dump-metadata-signatures 라이브러리 메타데이터를 기반으로 모든 비공개 라이브러리 선언의 IR 시그니처를 덤프. 대부분의 경우 IR을 기반으로 시그니처를 렌더링하는 dump-ir-signatures 명령과 출력이 같음. 다만 컴파일 중 IR 변환 컴파일러 플러그인(예: Compose)을 사용하면 패치된 선언이 다른 시그니처를 가질 수 있음.

위 덤프 명령들은 모두 시그니처를 덤프할 때 klib 유틸리티가 렌더링할 IR 시그니처 버전을 알려주는 -signature-version {N} 인자를 추가로 받을 수 있어요. 제공하지 않으면 라이브러리가 지원하는 가장 최신 버전을 사용합니다. 예를 들면:

klib dump-metadata-signatures mylib.klib -signature-version 1

또한 dump-metadata 명령은 출력의 모든 선언에 대해 IR 시그니처를 출력하도록 지시하는 -print-signatures {true|false} 인자를 받을 수 있습니다.

라이브러리 만들고 사용하기

  1. 소스 코드를 kotlinizer.kt에 넣어 라이브러리를 만듭니다:
package kotlinizer

val String.kotlinized
    get() = "Kotlin $this"
  1. 라이브러리를 .klib로 컴파일합니다:
kotlinc-native kotlinizer.kt -p library -o kotlinizer
  1. 현재 디렉터리에 만들어진 라이브러리를 확인합니다:
ls kotlinizer.klib
  1. 라이브러리에 대한 일반 정보를 확인합니다:
klib info kotlinizer.klib
  1. use.kt 파일에 짧은 프로그램을 만듭니다:
import kotlinizer.*

fun main(args: Array<String>) {
    println("Hello, ${\"world\".kotlinized}!")
}
  1. use.kt 소스 파일을 라이브러리에 링크해서 프로그램을 컴파일합니다:
kotlinc-native use.kt -l kotlinizer -o kohello
  1. 프로그램을 실행합니다:
./kohello.kexe

출력에 Hello, Kotlin world!가 보일 거예요.

라이브러리 검색 순서

라이브러리 검색 메커니즘은 곧 바뀔 예정이에요. 이 섹션의 업데이트를 기대해 주시고, 폐기된 플래그에 의존하지 마세요.

-library foo 옵션이 주어지면 컴파일러는 foo 라이브러리를 다음 순서로 검색합니다:

  1. 현재 컴파일 디렉터리 또는 절대 경로.
  2. 기본 리포지토리에 설치된 라이브러리. 기본 리포지토리는 ~/.konan입니다. konan.data.dir Gradle 프로퍼티를 설정해 변경할 수 있어요. 또는 -Xkonan-data-dir 컴파일러 옵션으로 cinteropkonanc 도구를 통해 디렉터리의 커스텀 경로를 구성할 수 있습니다.
  3. $installation/klib 디렉터리에 설치된 라이브러리.

라이브러리 형식

Kotlin/Native 라이브러리는 미리 정의된 디렉터리 구조를 가진 zip 파일로, 구성은 다음과 같아요:

foo.klibfoo/로 풀면:

- foo/
  - $component_name/
    - ir/
      - Serialized Kotlin IR.
    - targets/
      - $platform/
        - kotlin/
          - Kotlin compiled to LLVM bitcode.
        - native/
          - Bitcode files of additional native objects.
      - $another_platform/
        - There can be several platform specific kotlin and native pairs.
    - linkdata/
      - A set of ProtoBuf files with serialized linkage metadata.
    - resources/
      - General resources such as images. (Not used yet).
    - manifest - A file in the java property format describing the library.

예시 레이아웃은 Kotlin/Native 컴파일러 설치의 klib/common/stdlib 디렉터리에서 찾을 수 있어요.

klib에서 상대 경로 사용하기

소스 파일의 직렬화된 IR 표현은 klib 라이브러리의 일부입니다. 여기에는 올바른 디버그 정보를 생성하기 위한 파일 경로가 포함됩니다. 기본적으로 저장되는 경로는 절대 경로예요.

-Xklib-relative-path-base 컴파일러 옵션으로 형식을 변경하고 아티팩트에서 상대 경로만 사용할 수 있습니다. 동작하게 하려면 소스 파일의 기본 경로를 하나 이상 인자로 전달하세요:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named<KotlinCompilationTask<*>>("compileKotlin").configure {
    // $base is a base path of source files
    compilerOptions.freeCompilerArgs.add("-Xklib-relative-path-base=$base")
}
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named('compileKotlin', KotlinCompilationTask) {
    compilerOptions {
        // $base is a base path of source files
        freeCompilerArgs.add("-Xklib-relative-path-base=$base")
    }
}

다음 단계

cinterop 도구로 *.klib 아티팩트를 만드는 법을 배워 보세요.(네이티브 정의 파일)

더 알아보기