정의 파일
Kotlin/Native를 사용하면 C 및 Objective-C 라이브러리를 가져와서 해당 기능을 Kotlin에서 사용할 수 있습니다. cinterop이라는 특수 도구는 C 또는 Objective-C 라이브러리를 읽어 그에 해당하는 Kotlin 바인딩(bindings)을 생성하며, 이를 통해 라이브러리의 메서드를 일반적인 Kotlin 코드처럼 사용할 수 있게 해줍니다.
이러한 바인딩을 생성하려면 각 라이브러리에 대해 정의 파일(definition file)이 필요하며, 일반적으로 라이브러리와 동일한 이름을 사용합니다. 정의 파일은 라이브러리를 정확히 어떻게 사용해야 하는지 기술하는 속성(property) 파일입니다. 전체 사용 가능한 속성 목록을 확인해 보세요.
프로젝트 작업 시의 일반적인 워크플로우는 다음과 같습니다:
- 바인딩에 포함할 내용을 기술하는
.def파일을 생성합니다. - 생성된 바인딩을 Kotlin 코드에서 사용합니다.
- Kotlin/Native 컴파일러를 실행하여 최종 실행 파일을 생성합니다.
정의 파일 생성 및 구성
C 라이브러리에 대한 정의 파일을 만들고 바인딩을 생성해 보겠습니다:
IDE에서
src폴더를 선택하고 File | New | Directory를 통해 새 디렉토리를 생성합니다.새 디렉토리 이름을
nativeInterop/cinterop으로 지정합니다.이것이
.def파일 위치에 대한 기본 규칙이지만, 다른 위치를 사용하는 경우build.gradle.kts파일에서 이를 재정의할 수 있습니다.새 하위 폴더를 선택하고 File | New | File을 통해
png.def파일을 생성합니다.필요한 속성들을 추가합니다:
noneheaders = png.h headerFilter = png.h package = png compilerOpts.linux = -I/usr/include -I/usr/include/x86_64-linux-gnu linkerOpts.osx = -L/opt/local/lib -L/usr/local/opt/png/lib -lpng linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu -lpngheaders는 Kotlin 스텁(stub)을 생성할 헤더 파일의 목록입니다. 이 항목에 여러 파일을 공백으로 구분하여 추가할 수 있습니다. 이 예제에서는png.h만 해당합니다. 참조된 파일은 지정된 경로(이 경우/usr/include/png)에 존재해야 합니다.headerFilter는 정확히 무엇이 포함되는지를 나타냅니다. C에서는 한 파일이#include지시문으로 다른 파일을 참조할 때 모든 헤더가 포함됩니다. 때로는 이것이 필요하지 않을 수 있으며, 글로브(glob) 패턴을 사용하여 이 매개변수를 조정할 수 있습니다.시스템
stdint.h헤더와 같은 외부 종속성을 상호운용(interop) 라이브러리로 가져오고 싶지 않은 경우headerFilter를 사용할 수 있습니다. 또한, 라이브러리 크기 최적화 및 시스템과 제공된 Kotlin/Native 컴파일 환경 간의 잠재적 충돌을 해결하는 데 유용할 수 있습니다.특정 플랫폼에 대한 동작을 수정해야 하는 경우,
compilerOpts.osx또는compilerOpts.linux와 같은 형식을 사용하여 옵션에 플랫폼별 값을 제공할 수 있습니다. 이 예제에서는 macOS(.osx접미사)와 Linux(.linux접미사)입니다. 접미사가 없는 매개변수(예:linkerOpts=)도 가능하며 모든 플랫폼에 적용됩니다.
바인딩을 생성하려면 알림창에서 Sync Now를 클릭하여 Gradle 파일을 동기화합니다.

바인딩 생성이 완료되면 IDE는 이를 네이티브 라이브러리의 프록시 뷰(proxy view)로 사용할 수 있습니다.
명령줄에서 cinterop 도구를 사용하여 바인딩 생성을 구성할 수도 있습니다.
속성(Properties)
다음은 생성된 바이너리의 내용을 조정하기 위해 정의 파일에서 사용할 수 있는 전체 속성 목록입니다. 자세한 정보는 아래의 해당 섹션을 참조하세요.
| 속성(Property) | 설명 |
|---|---|
headers | 바인딩에 포함될 라이브러리의 헤더 목록입니다. |
modules | 바인딩에 포함될 Objective-C 라이브러리의 Clang 모듈 목록입니다. |
language | 언어를 지정합니다. 기본값은 C이며, 필요한 경우 Objective-C로 변경하세요. |
compilerOpts | cinterop 도구가 C 컴파일러에 전달하는 컴파일러 옵션입니다. |
linkerOpts | cinterop 도구가 링커(linker)에 전달하는 링커 옵션입니다. |
excludedFunctions | 무시해야 할 함수 이름의 공백 구분 목록입니다. |
staticLibraries | 실험적 기능. 정적 라이브러리를 .klib에 포함합니다. |
libraryPaths | 실험적 기능. cinterop 도구가 .klib에 포함할 라이브러리를 검색할 디렉토리의 공백 구분 목록입니다. |
package | 생성된 Kotlin API의 패키지 접두사입니다. |
headerFilter | 헤더를 글로브(glob)로 필터링하고 라이브러리를 가져올 때 해당 헤더만 포함합니다. |
excludeFilter | 라이브러리를 가져올 때 특정 헤더를 제외하며, headerFilter보다 우선순위가 높습니다. |
strictEnums | Kotlin 열거형(enum)으로 생성되어야 하는 열거형의 공백 구분 목록입니다. |
nonStrictEnums | 정수 값으로 생성되어야 하는 열거형의 공백 구분 목록입니다. |
noStringConversion | const char* 매개변수가 Kotlin String으로 자동 변환되지 않아야 하는 함수의 공백 구분 목록입니다. |
allowedOverloadsForCFunctions | 기본적으로 C 함수는 고유한 이름을 가진다고 가정합니다. 여러 함수가 동일한 이름을 가진 경우 하나만 선택됩니다. 그러나 allowedOverloadsForCFunctions에 해당 함수들을 지정하여 이를 변경할 수 있습니다. |
disableDesignatedInitializerChecks | 지정되지 않은(non-designated) Objective-C 초기화 메서드를 super() 생성자로 호출하는 것을 허용하지 않는 컴파일러 검사를 비활성화합니다. |
foreignExceptionMode | Objective-C 코드의 예외를 ForeignException 유형의 Kotlin 예외로 래핑합니다. |
userSetupHint | 사용자가 링커 오류를 해결하는 데 도움이 되는 사용자 정의 메시지를 추가합니다. |
속성 목록 외에도 정의 파일에 사용자 정의 선언(custom declarations)을 포함할 수 있습니다.
헤더 가져오기(Import headers)
C 라이브러리에 Clang 모듈이 없고 대신 일련의 헤더로 구성된 경우, headers 속성을 사용하여 가져올 헤더를 지정합니다:
headers = curl/curl.h글로브로 헤더 필터링(Filter headers by globs)
.def 파일의 필터 속성을 사용하여 글로브(glob)로 헤더를 필터링할 수 있습니다. 헤더의 선언을 포함하려면 headerFilter 속성을 사용합니다. 헤더가 글로브 중 하나와 일치하면 해당 선언이 바인딩에 포함됩니다.
글로브는 time.h 또는 curl/curl.h와 같이 적절한 include 경로 요소를 기준으로 한 헤더 경로에 적용됩니다. 따라서 라이브러리가 일반적으로 #include <SomeLibrary/Header.h>와 같이 포함된다면 다음과 같은 필터로 헤더를 필터링할 수 있습니다:
headerFilter = SomeLibrary/**headerFilter가 제공되지 않으면 모든 헤더가 포함됩니다. 그러나 가능한 한 정확하게 글로브를 지정하여 headerFilter를 사용하는 것이 좋습니다. 이 경우 생성된 라이브러리에는 필요한 선언만 포함됩니다. 이는 개발 환경에서 Kotlin이나 도구를 업그레이드할 때 발생할 수 있는 다양한 문제를 방지하는 데 도움이 될 수 있습니다.
헤더 제외(Exclude headers)
특정 헤더를 제외하려면 excludeFilter 속성을 사용합니다. 지정된 헤더의 선언은 바인딩에 포함되지 않으므로, 불필요하거나 문제가 되는 헤더를 제거하고 컴파일을 최적화하는 데 유용할 수 있습니다:
excludeFilter = SomeLibrary/time.h동일한 헤더가
headerFilter에 포함되고excludeFilter에서 제외되는 경우, 해당 헤더는 바인딩에 포함되지 않습니다.
모듈 가져오기(Import modules)
Objective-C 라이브러리에 Clang 모듈이 있는 경우, modules 속성을 사용하여 가져올 모듈을 지정합니다:
modules = UIKit컴파일러 및 링커 옵션 전달
내부적으로 헤더를 분석하는 데 사용되는 C 컴파일러에 옵션을 전달하려면 compilerOpts 속성을 사용합니다. 최종 실행 파일을 링크하는 데 사용되는 링커에 옵션을 전달하려면 linkerOpts를 사용합니다. 예를 들어:
compilerOpts = -DFOO=bar
linkerOpts = -lpng특정 타겟에만 적용되는 타겟별 옵션을 지정할 수도 있습니다:
compilerOpts = -DBAR=bar
compilerOpts.linux_x64 = -DFOO=foo1
compilerOpts.macos_x64 = -DFOO=foo2이 구성에서 헤더는 Linux에서는 -DBAR=bar -DFOO=foo1, macOS에서는 -DBAR=bar -DFOO=foo2를 사용하여 분석됩니다. 모든 정의 파일 옵션은 공통 부분과 플랫폼별 부분을 모두 가질 수 있음에 유의하세요.
특정 함수 무시(Ignore specific functions)
무시해야 할 함수 이름 목록을 지정하려면 excludedFunctions 속성을 사용합니다. 이는 헤더에 선언된 함수가 호출 가능하다고 보장되지 않으며 이를 자동으로 판단하기 어렵거나 불가능한 경우에 유용할 수 있습니다. 상호운용성(interop) 자체의 버그를 우회하기 위해 이 속성을 사용할 수도 있습니다.
정적 라이브러리 포함(Include a static library)
사용자의 환경에 라이브러리가 있다고 가정하는 대신 정적 라이브러리를 제품과 함께 배포하는 것이 더 편리할 때가 있습니다. 정적 라이브러리를 .klib에 포함하려면 staticLibrary 및 libraryPaths 속성을 사용합니다:
headers = foo.h
staticLibraries = libfoo.a
libraryPaths = /opt/local/lib /usr/local/opt/curl/lib위의 스니펫이 주어지면 cinterop 도구는 /opt/local/lib 및 /usr/local/opt/curl/lib에서 libfoo.a를 검색하고, 발견되면 라이브러리 바이너리를 klib에 포함합니다.
프로그램에서 이와 같은 klib을 사용하면 라이브러리가 자동으로 링크됩니다.
열거형 생성 구성(Configure enums generation)
열거형을 Kotlin 열거형으로 생성하려면 strictEnums 속성을 사용하고, 정수 값으로 생성하려면 nonStrictEnums를 사용합니다. 열거형이 이 두 목록에 모두 포함되지 않은 경우 휴리스틱(heuristics)에 따라 생성됩니다.
문자열 변환 설정(Set up string conversion)
const char* 함수 매개변수를 Kotlin String으로 자동 변환하는 기능을 비활성화하려면 noStringConversion 속성을 사용합니다.
지정되지 않은 초기화 메서드 호출 허용(Allow calling a non-designated initializer)
기본적으로 Kotlin/Native 컴파일러는 지정되지 않은(non-designated) Objective-C 초기화 메서드를 super() 생성자로 호출하는 것을 허용하지 않습니다. 라이브러리에서 지정된 Objective-C 초기화 메서드가 제대로 표시되지 않은 경우 이 동작이 불편할 수 있습니다. 이러한 컴파일러 검사를 비활성화하려면 disableDesignatedInitializerChecks 속성을 사용합니다.
Objective-C 예외 처리(Handle Objective-C exceptions)
기본적으로 Objective-C 예외가 Objective-C와 Kotlin의 상호운용 경계에 도달하여 Kotlin 코드에 전달되면 프로그램이 중단됩니다.
Objective-C 예외를 Kotlin으로 전파하려면 foreignExceptionMode = objc-wrap 속성을 사용하여 래핑을 활성화하세요. 이 경우 Objective-C 예외는 ForeignException 유형을 갖는 Kotlin 예외로 변환됩니다.
링커 오류 해결 도움(Help resolve linker errors)
Kotlin 라이브러리가 C 또는 Objective-C 라이브러리에 종속된 경우(예: CocoaPods 통합 사용 시), 링커 오류가 발생할 수 있습니다. 종속 라이브러리가 로컬 머신에 설치되어 있지 않거나 프로젝트 빌드 스크립트에 명시적으로 구성되어 있지 않으면 "Framework not found" 오류가 발생합니다.
라이브러리 작성자라면 사용자 정의 메시지를 통해 사용자가 링커 오류를 해결하도록 도울 수 있습니다. 이를 위해 .def 파일에 userSetupHint=message 속성을 추가하거나 cinterop에 -Xuser-setup-hint 컴파일러 옵션을 전달하세요.
사용자 정의 선언 추가(Add custom declarations)
바인딩을 생성하기 전에 라이브러리에 사용자 정의 C 선언을 추가해야 할 때가 있습니다(예: 매크로의 경우). 이러한 선언을 위해 추가 헤더 파일을 만드는 대신, 구분선인 --- 시퀀스 뒤에 .def 파일 끝에 직접 포함할 수 있습니다.
headers = errno.h
---
static inline int getErrno() {
return errno;
}.def 파일의 이 부분은 헤더 파일의 일부로 취급되므로, 본문이 있는 함수는 static으로 선언해야 합니다. 선언은 headers 목록의 파일을 포함한 후에 파싱됩니다.
명령줄을 사용하여 바인딩 생성
정의 파일 외에도 cinterop 호출 시 해당 속성을 옵션으로 전달하여 바인딩에 포함할 내용을 지정할 수 있습니다.
다음은 컴파일된 라이브러리인 png.klib을 생성하는 명령의 예입니다:
cinterop -def png.def -compiler-option -I/usr/local/include -o png생성된 바인딩은 일반적으로 플랫폼별로 다르므로 여러 타겟을 대상으로 개발하는 경우 바인딩을 다시 생성해야 합니다.
- sysroot 검색 경로에 포함되지 않은 호스트 라이브러리의 경우 헤더가 필요할 수 있습니다.
- 구성 스크립트가 있는 일반적인 UNIX 라이브러리의 경우,
compilerOpts에는--cflags옵션이 있는 구성 스크립트의 출력(정확한 경로 제외)이 포함될 가능성이 높습니다. --libs가 있는 구성 스크립트의 출력은linkerOpts속성에 전달될 수 있습니다.
