Kotlin 1.9.20의 새로운 기능(What's new in Kotlin 1.9.20)
Kotlin 1.9.20의 새로운 기능(What's new in Kotlin 1.9.20)
Kotlin 1.9.20이 나왔어요. 이제 모든 타깃의 K2 컴파일러가 Beta 단계이고, Kotlin Multiplatform은 Stable이 됐어요. 그 외 주요 변경점들도 함께 소개할게요.
본문
출시일: 2023년 11월 1일
- multiplatform 프로젝트 설정을 위한 새로운 기본 계층 구조 템플릿
- Kotlin Multiplatform의 Gradle 설정 캐시 완전 지원
- Kotlin/Native의 기본 활성화된 커스텀 메모리 할당기
- Kotlin/Native 가비지 컬렉터 성능 개선
- Kotlin/Wasm의 새 타깃과 이름 변경된 타깃
- Kotlin/Wasm 표준 라이브러리의 WASI API 지원
이 업데이트에 대한 짧은 개요는 다음 동영상에서도 확인할 수 있어요.
Kotlin의 릴리스 주기에 대한 자세한 내용은 Kotlin 릴리스 과정에서 확인할 수 있어요.
IDE 지원
1.9.20을 지원하는 Kotlin 플러그인은 다음 환경에서 사용할 수 있어요.
| IDE | 지원 버전 |
|---|---|
| IntelliJ IDEA | 2023.1.x, 2023.2.x, 2023.x |
| Android Studio | Hedgehog (2023.1.1), Iguana (2023.2.1) |
IntelliJ IDEA 2023.3.x와 Android Studio Iguana (2023.2.1) Canary 15부터 Kotlin 플러그인이 자동으로 포함되고 업데이트돼요. 프로젝트에서 Kotlin 버전만 업데이트하면 돼요.
새로운 Kotlin K2 컴파일러 업데이트
JetBrains의 Kotlin 팀은 새 K2 컴파일러를 계속 안정화하고 있어요. K2 컴파일러는 큰 성능 개선을 가져오고, 새 언어 기능 개발을 빠르게 하며, Kotlin이 지원하는 모든 플랫폼을 통합하고, multiplatform 프로젝트를 위한 더 나은 아키텍처를 제공할 거예요.
K2는 현재 모든 타깃에서 Beta 단계예요. 릴리스 블로그 게시물에서 더 읽어보세요.
Kotlin/Wasm 지원
이 릴리스부터 Kotlin/Wasm이 새 K2 컴파일러를 지원해요. 프로젝트에서 활성화하는 방법을 알아보세요.
K2와 함께 kapt 컴파일러 플러그인 프리뷰
kapt 컴파일러 플러그인의 K2 지원은 Experimental이에요. Opt-in이 필요하며(아래 세부사항 참고) 평가 목적으로만 사용해야 해요.
1.9.20에서 kapt 컴파일러 플러그인을 K2 컴파일러와 함께 사용해 볼 수 있어요. 프로젝트에서 K2 컴파일러를 사용하려면 gradle.properties 파일에 다음 옵션을 추가하면 돼요.
kotlin.experimental.tryK2=true
kapt.use.k2=true
또는 다음 단계를 완료해서 kapt에 K2를 활성화할 수 있어요.
build.gradle.kts파일에서 언어 버전을 설정해서2.0으로 만들어요.gradle.properties파일에kapt.use.k2=true를 추가해요.
K2 컴파일러와 함께 kapt를 사용할 때 문제가 생기면 이슈 트래커에 보고해 주세요.
Kotlin K2 컴파일러를 활성화하는 방법
Gradle에서 K2 활성화
Kotlin K2 컴파일러를 활성화하고 테스트하려면 다음 컴파일러 옵션으로 새 언어 버전을 사용하면 돼요.
-language-version 2.0
build.gradle.kts 파일에서 지정할 수 있어요.
kotlin {
sourceSets.all {
languageSettings {
languageVersion = "2.0"
}
}
}
Maven에서 K2 활성화
Kotlin K2 컴파일러를 활성화하고 테스트하려면 pom.xml 파일의 <project/> 섹션을 업데이트하면 돼요.
<properties>
<kotlin.compiler.languageVersion>2.0</kotlin.compiler.languageVersion>
</properties>
IntelliJ IDEA에서 K2 활성화
IntelliJ IDEA에서 Kotlin K2 컴파일러를 활성화하고 테스트하려면 Settings | Build, Execution, Deployment | Compiler | Kotlin Compiler로 이동해서 Language Version 필드를 2.0 (experimental)로 업데이트하면 돼요.
새 K2 컴파일러에 대한 피드백 남기기
여러분의 피드백을 정말 환영해요!
- Kotlin Slack의 K2 개발자에게 직접 피드백을 주세요 – 초대받기 후 #k2-early-adopters 채널에 참여하세요.
- 새 K2 컴파일러에서 겪은 문제는 이슈 트래커에 보고해 주세요.
- Send usage statistics 옵션을 켜서 JetBrains가 K2 사용에 관한 익명 데이터를 수집하도록 허용해 주세요.
Kotlin/JVM
1.9.20부터 컴파일러가 Java 21 바이트코드를 포함한 클래스를 생성할 수 있어요.
Kotlin/Native
Kotlin 1.9.20은 새 메모리 할당기가 기본으로 활성화된 Stable 메모리 매니저, 가비지 컬렉터 성능 개선, 그리고 다른 업데이트를 포함해요.
- 커스텀 메모리 할당기 기본 활성화
- 가비지 컬렉터 성능 개선
klib아티팩트의 증분 컴파일- 라이브러리 링키지 문제 관리
- 클래스 생성자 호출 시 동반 객체 초기화
- 모든 cinterop 선언에 대한 opt-in 요구
- 링커 오류용 커스텀 메시지
- 레거시 메모리 매니저 제거
- 타깃 계층 정책 변경
기본 활성화된 커스텀 메모리 할당기
Kotlin 1.9.20은 새 메모리 할당기가 기본으로 활성화된 채 출시돼요. 이는 이전 기본 할당기인 mimalloc을 대체해 가비지 컬렉션을 더 효율적으로 만들고 Kotlin/Native 메모리 매니저의 런타임 성능을 개선하도록 설계됐어요.
새 커스텀 할당기는 시스템 메모리를 페이지로 나누어 연속된 순서로 독립적인 스위핑을 할 수 있게 해요. 각 할당은 페이지 안의 메모리 블록이 되고, 페이지는 블록 크기를 추적해요. 서로 다른 페이지 타입이 다양한 할당 크기에 최적화돼 있어요. 메모리 블록의 연속적인 배치 덕분에 모든 할당 블록을 효율적으로 반복할 수 있어요.
스레드가 메모리를 할당하면 할당 크기에 따라 적합한 페이지를 찾아요. 스레드는 서로 다른 크기 범주별 페이지 집합을 유지해요. 보통 주어진 크기의 현재 페이지가 할당을 수용할 수 있어요. 그렇지 않으면 스레드가 공유 할당 공간에서 다른 페이지를 요청해요. 이 페이지는 이미 사용 가능하거나, 스위핑이 필요하거나, 먼저 생성해야 할 수도 있어요.
새 할당기는 동시에 여러 독립적인 할당 공간을 허용해서, Kotlin 팀이 성능을 더 개선하기 위해 다양한 페이지 레이아웃을 실험할 수 있게 해줘요.
커스텀 메모리 할당기를 활성화하는 방법
Kotlin 1.9.20부터 새 메모리 할당기가 기본값이에요. 추가 설정이 필요 없어요.
메모리 소비가 높다면 Gradle 빌드 스크립트에서 -Xallocator=mimalloc 또는 -Xallocator=std로 mimalloc이나 시스템 할당기로 되돌아갈 수 있어요. 새 메모리 할당기를 개선하는 데 도움이 되도록 그런 문제를 YouTrack에 보고해 주세요.
새 할당기 설계의 기술적 세부사항은 이 README를 참고하세요.
가비지 컬렉터 성능 개선
Kotlin 팀은 새 Kotlin/Native 메모리 매니저의 성능과 안정성을 계속 개선하고 있어요. 이 릴리스는 다음 1.9.20 하이라이트를 포함해 가비지 컬렉터(GC)에 여러 중요한 변경을 가져와요.
- GC의 일시 정지 시간을 줄이기 위한 완전 병렬 마크(full parallel mark)
- 할당 성능을 개선하기 위한 큰 덩어리 단위 메모리 추적
GC의 일시 정지 시간을 줄이기 위한 완전 병렬 마크
이전에는 기본 가비지 컬렉터가 부분 병렬 마크만 수행했어요. 뮤테이터 스레드가 일시 정지되면, 스레드-로컬 변수와 호출 스택 같은 자체 루트에서 GC 시작을 표시했어요. 한편 별도의 GC 스레드가 전역 루트뿐만 아니라 네이티브 코드를 적극적으로 실행 중이라 일시 정지되지 않은 모든 뮤테이터의 루트에서 시작을 표시하는 일을 담당했어요.
이 접근 방식은 전역 객체가 제한적이고 뮤테이터 스레드가 runnable 상태에서 Kotlin 코드를 실행하며 상당한 시간을 보내는 경우에 잘 동작했어요. 하지만 일반적인 iOS 애플리케이션에서는 그렇지 않아요.
이제 GC는 일시 정지된 뮤테이터, GC 스레드, 선택적인 마커 스레드를 결합해서 마크 큐를 처리하는 완전 병렬 마크를 사용해요. 기본적으로 마킹 과정은 다음에 의해 수행돼요.
- 일시 정지된 뮤테이터. 자체 루트를 처리한 뒤 코드를 활발히 실행하지 않는 동안 유휴 상태로 있는 대신, 전체 마킹 과정에 기여해요.
- GC 스레드. 이는 적어도 하나의 스레드가 마킹을 수행하도록 보장해요.
이 새 접근 방식은 마킹 과정을 더 효율적으로 만들어 GC의 일시 정지 시간을 줄여요.
할당 성능을 개선하기 위한 큰 덩어리 단위 메모리 추적
이전에는 GC 스케줄러가 각 객체의 할당을 개별적으로 추적했어요. 하지만 새 기본 커스텀 할당기나 mimalloc 메모리 할당기 모두 객체별로 별도 저장소를 할당하지 않아요. 한 번에 여러 객체를 위해 큰 영역을 할당하죠.
Kotlin 1.9.20에서 GC는 개별 객체 대신 영역을 추적해요. 이는 각 할당에 수행되는 작업 수를 줄여 작은 객체 할당을 빠르게 하고, 따라서 가비지 컬렉터의 메모리 사용을 최소화하는 데 도움이 돼요.
klib 아티팩트의 증분 컴파일
이 기능은 Experimental이에요. 언제든 제거되거나 변경될 수 있어요. Opt-in이 필요하며(아래 세부사항 참고) 평가 목적으로만 사용해 주세요. YouTrack에서 피드백을 기다릴게요.
Kotlin 1.9.20은 Kotlin/Native의 새 컴파일 시간 최적화를 소개해요. klib 아티팩트를 네이티브 코드로 컴파일하는 것이 이제 부분적으로 증분 방식이 돼요.
디버그 모드에서 Kotlin 소스 코드를 네이티브 바이너리로 컴파일할 때 컴파일은 두 단계를 거쳐요.
- 소스 코드가
klib아티팩트로 컴파일돼요. klib아티팩트가 의존성과 함께 바이너리로 컴파일돼요.
두 번째 단계의 컴파일 시간을 최적화하기 위해 팀은 이미 의존성용 컴파일러 캐시를 구현했어요. 이들은 네이티브 코드로 한 번만 컴파일되고, 바이너리가 컴파일될 때마다 결과가 재사용돼요. 하지만 프로젝트 소스에서 빌드된 klib 아티팩트는 프로젝트가 변경될 때마다 항상 네이티브 코드로 완전히 재컴파일됐어요.
새 증분 컴파일을 사용하면 프로젝트 모듈 변경이 소스 코드를 klib 아티팩트로 부분 재컴파일만 일으키는 경우, klib의 일부만 바이너리로 추가 재컴파일돼요.
증분 컴파일을 활성화하려면 gradle.properties 파일에 다음 옵션을 추가하면 돼요.
kotlin.incremental.native=true
문제가 생기면 그런 경우를 YouTrack에 보고해 주세요.
라이브러리 링키지 문제 관리
이 릴리스는 Kotlin/Native 컴파일러가 Kotlin 라이브러리의 링키지 문제를 처리하는 방식을 개선해요. 오류 메시지에 이제 해시 대신 시그니처 이름을 사용하므로 더 읽기 쉬운 선언이 포함돼서 문제를 더 쉽게 찾고 고칠 수 있어요. 예시는 다음과 같아요.
No function found for symbol 'org.samples/MyClass.removedFunction|removedFunction(kotlin.Int;kotlin.String){}[0]'
Kotlin/Native 컴파일러는 써드파티 Kotlin 라이브러리 사이의 링키지 문제를 감지하고 런타임에 오류를 보고해요. 이런 문제는 써드파티 Kotlin 라이브러리 하나의 작성자가 다른 써드파티 Kotlin 라이브러리가 사용하는 실험용 API에 호환되지 않는 변경을 할 때 겪을 수 있어요.
Kotlin 1.9.20부터 컴파일러가 기본적으로 무음(silent) 모드로 링키지 문제를 감지해요. 프로젝트에서 이 설정을 조정할 수 있어요.
- 컴파일 로그에 이 문제를 기록하려면
-Xpartial-linkage-loglevel=WARNING컴파일러 옵션으로 경고를 활성화해요. - 보고된 경고의 심각도를
-Xpartial-linkage-loglevel=ERROR로 컴파일 오류까지 올릴 수도 있어요. 이 경우 컴파일이 실패하고 컴파일 로그에서 모든 오류를 보게 돼요. 링키지 문제를 더 자세히 조사하려면 이 옵션을 사용하세요.
// An example of passing compiler options in a Gradle build file:
kotlin {
macosX64("native") {
binaries.executable()
compilations.configureEach {
compilerOptions.configure {
// To report linkage issues as warnings:
freeCompilerArgs.add("-Xpartial-linkage-loglevel=WARNING")
// To raise linkage warnings to errors:
freeCompilerArgs.add("-Xpartial-linkage-loglevel=ERROR")
}
}
}
}
이 기능에서 예상치 못한 문제가 생기면 -Xpartial-linkage=disable 컴파일러 옵션으로 언제든 opt-out할 수 있어요. 그런 경우 이슈 트래커에 보고해 주세요.
클래스 생성자 호출 시 동반 객체 초기화
Kotlin 1.9.20부터 Kotlin/Native 백엔드는 클래스 생성자에서 동반 객체의 정적 초기화자(static initializer)를 호출해요.
class Greeting {
companion object {
init {
print("Hello, Kotlin!")
}
}
}
fun main() {
val start = Greeting() // Prints "Hello, Kotlin!"
}
이 동작은 이제 Kotlin/JVM과 통일됐어요. Kotlin/JVM에서는 Java 정적 초기화자 의미와 일치하는 해당 클래스가 로드(해석)될 때 동반 객체가 초기화돼요.
이제 이 기능의 구현이 플랫폼 간에 더 일관되므로 Kotlin Multiplatform 프로젝트에서 코드를 공유하기 더 쉬워졌어요.
모든 cinterop 선언에 대한 opt-in 요구
Kotlin 1.9.20부터 libcurl과 libxml 같은 C와 Objective-C 라이브러리에서 cinterop 도구가 생성한 모든 Kotlin 선언이 @ExperimentalForeignApi로 표시돼요. opt-in 애너테이션이 없으면 코드가 컴파일되지 않아요.
이 요구는 C와 Objective-C 라이브러리 가져오기의 Experimental 상태를 반영해요. 프로젝트의 특정 영역으로 사용을 한정할 것을 권장해요. 이렇게 하면 가져오기 안정화를 시작할 때 마이그레이션이 더 쉬워져요.
Kotlin/Native와 함께 제공되는 네이티브 플랫폼 라이브러리(Foundation, UIKit, POSIX 같은)의 경우, 그 API 중 일부만 @ExperimentalForeignApi opt-in이 필요해요. 그런 경우 opt-in 요구와 함께 경고가 뜨게 돼요.
링커 오류용 커스텀 메시지
라이브러리 작성자라면 이제 커스텀 메시지로 사용자가 링커 오류를 해결하도록 도울 수 있어요.
Kotlin 라이브러리가 C나 Objective-C 라이브러리에 의존하는 경우, 예를 들어 CocoaPods 통합을 사용한다면, 그 사용자는 이 의존 라이브러리를 로컬 머신에 갖고 있거나 프로젝트 빌드 스크립트에 명시적으로 구성해야 해요. 그렇지 않으면 사용자는 예전에 헷갈리는 "Framework not found" 메시지를 받았어요.
이제 컴파일 실패 메시지에 특정 지침이나 링크를 제공할 수 있어요. 이렇게 하려면 cinterop에 -Xuser-setup-hint 컴파일러 옵션을 전달하거나 .def 파일에 userSetupHint=message 프로퍼티를 추가하면 돼요.
레거시 메모리 매니저 제거
새 메모리 매니저는 Kotlin 1.6.20에서 도입되었고 1.7.20에서 기본값이 됐어요. 그 이후로 계속 업데이트와 성능 개선을 받아 Stable이 됐어요.
이제 deprecation 주기를 마치고 레거시 메모리 매니저를 제거할 때가 됐어요. 여전히 사용하고 있다면 gradle.properties에서 kotlin.native.binary.memoryModel=strict 옵션을 제거하고 마이그레이션 가이드에 따라 필요한 변경을 해 주세요.
타깃 계층 정책 변경
tier 1 지원에 대한 요구 사항을 상향하기로 결정했어요. Kotlin 팀은 이제 tier 1 대상 타깃에 대해 컴파일러 릴리스 간 소스 및 바이너리 호환성을 제공하기로 약속했어요. 또한 컴파일되고 실행될 수 있도록 CI 도구로 정기적으로 테스트해야 해요. 현재 tier 1에는 macOS 호스트를 위한 다음 타깃이 포함돼요.
macosX64macosArm64iosSimulatorArm64iosX64
Kotlin 1.9.20에서는 이전에 deprecated된 여러 타깃도 제거했어요. 구체적으로는:
iosArm32watchosX86wasm32mingwX86linuxMips32linuxMipsel32
현재 지원되는 타깃의 전체 목록을 확인하세요.
Kotlin Multiplatform
Kotlin 1.9.20은 Kotlin Multiplatform의 안정화에 집중하고, 새 프로젝트 위저드(wizard)와 다른 주목할 만한 기능으로 개발자 경험 개선에 새로운 발걸음을 내디뎌요.
- Kotlin Multiplatform Stable
- multiplatform 프로젝트 구성을 위한 템플릿
- 새 프로젝트 위저드
- Gradle 설정 캐시 완전 지원
- Gradle에서 새 표준 라이브러리 버전 구성 간소화
- 써드파티 cinterop 라이브러리 기본 지원
- Compose Multiplatform 프로젝트의 Kotlin/Native 컴파일 캐시 지원
- 호환성 가이드라인
Kotlin Multiplatform Stable
1.9.20 릴리스는 Kotlin 진화의 중요한 이정표를 표시해요. Kotlin Multiplatform이 마침내 Stable이 됐어요. 이는 이 기술을 프로젝트에서 안전하게 사용할 수 있고 프로덕션에 100% 준비됐다는 뜻이에요. 또한 Kotlin Multiplatform의 추가 개발이 우리의 엄격한 하위 호환성 규칙에 따라 계속된다는 뜻이기도 해요.
Kotlin Multiplatform의 일부 고급 기능은 여전히 진화 중이라는 점을 유의하세요. 그것들을 사용하면 사용 중인 기능의 현재 안정성 상태를 설명하는 경고를 받게 돼요. IntelliJ IDEA에서 실험 기능을 사용하기 전에 Settings | Advanced Settings | Kotlin | Experimental Multiplatform에서 명시적으로 활성화해야 해요.
- Kotlin Multiplatform 안정화와 향후 계획에 대해 더 알아보려면 Kotlin 블로그를 방문하세요.
- 안정화 과정에서 어떤 중요한 변경이 있었는지 보려면 Multiplatform 호환성 가이드를 확인하세요.
- 이 릴리스에서 일부 안정화된 Kotlin Multiplatform의 중요한 부분인 expected/actual 선언 메커니즘에 대해 읽어보세요.
multiplatform 프로젝트 구성을 위한 템플릿
Kotlin 1.9.20부터 Kotlin Gradle 플러그인이 인기 있는 multiplatform 시나리오에 대해 공유 소스 세트를 자동으로 생성해요. 프로젝트 설정이 그 중 하나라면 소스 세트 계층 구조를 수동으로 구성할 필요가 없어요. 프로젝트에 필요한 타깃만 명시적으로 지정하면 돼요.
기본 계층 구조 템플릿(default hierarchy template) 덕분에 이제 설정이 더 쉬워졌어요. 이는 Kotlin Gradle 플러그인의 새 기능이에요. 플러그인에 내장된 소스 세트 계층 구조의 미리 정의된 템플릿이에요. 여기에는 선언한 타깃에 대해 Kotlin이 자동으로 생성하는 중간 소스 세트가 포함돼요. 전체 템플릿을 확인하세요.
프로젝트를 더 쉽게 만들기
Android와 iPhone 기기 모두를 타깃으로 하고 Apple silicon MacBook에서 개발하는 multiplatform 프로젝트를 생각해 보세요. 이 프로젝트가 서로 다른 Kotlin 버전에서 어떻게 설정되는지 비교해 보세요.
kotlin {
androidTarget()
iosArm64()
iosSimulatorArm64()
sourceSets {
val commonMain by getting
val iosMain by creating {
dependsOn(commonMain)
}
val iosArm64Main by getting {
dependsOn(iosMain)
}
val iosSimulatorArm64Main by getting {
dependsOn(iosMain)
}
}
}
kotlin {
androidTarget()
iosArm64()
iosSimulatorArm64()
// The iosMain source set is created automatically
}
| Kotlin 1.9.0 이하 (표준 설정) | Kotlin 1.9.20 |
|---|---|
기본 계층 구조 템플릿을 사용하면 프로젝트 설정에 필요한 보일러플레이트 코드가 크게 줄어드는 것을 볼 수 있어요.
코드에서 androidTarget, iosArm64, iosSimulatorArm64 타깃을 선언하면 Kotlin Gradle 플러그인이 템플릿에서 적합한 공유 소스 세트를 찾아서 생성해줘요. 결과 계층 구조는 다음과 같아요.
초록색 소스 세트는 실제로 생성되어 프로젝트에 포함되는 것이고, 기본 템플릿의 회색 것은 무시돼요.
소스 세트에 자동 완성 사용
만들어진 프로젝트 구조로 작업하기 쉽도록 IntelliJ IDEA가 이제 기본 계층 구조 템플릿으로 만들어진 소스 세트에 대한 자동 완성을 제공해요.
Kotlin은 또한 해당 타깃을 선언하지 않아 존재하지 않는 소스 세트에 접근하려 하면 경고를 해요. 아래 예시에는 JVM 타깃이 없어요(androidTarget만 있고, 이는 같지 않아요). jvmMain 소스 세트를 사용해 보면 어떻게 되는지 봅시다.
kotlin {
androidTarget()
iosArm64()
iosSimulatorArm64()
sourceSets {
jvmMain {
}
}
}
이 경우 Kotlin이 빌드 로그에 경고를 보고해요.
w: Accessed 'source set jvmMain' without registering the jvm target:
kotlin {
jvm() /* <- register the 'jvm' target */
sourceSets.jvmMain.dependencies {
}
}
타깃 계층 구조 설정
Kotlin 1.9.20부터 기본 계층 구조 템플릿이 자동으로 활성화돼요. 대부분의 경우 추가 설정이 필요 없어요.
하지만 1.9.20 이전에 만든 기존 프로젝트를 마이그레이션한다면, 이전에 dependsOn() 호출로 중간 소스를 수동으로 도입했다면 경고를 만날 수 있어요. 이 문제를 해결하려면 다음을 하세요.
- 중간 소스 세트가 현재 기본 계층 구조 템플릿으로 덮이는 경우, 모든 수동
dependsOn()호출과by creating구조로 만든 소스 세트를 제거해요. 모든 기본 소스 세트 목록을 확인하려면 전체 계층 구조 템플릿을 보세요. - 기본 계층 구조 템플릿이 제공하지 않는 추가 소스 세트, 예를 들어 macOS와 JVM 타깃 사이에 코드를 공유하는 소스 세트를 원한다면,
applyDefaultHierarchyTemplate()으로 템플릿을 명시적으로 다시 적용하고 보통처럼dependsOn()으로 추가 소스 세트를 수동 구성해서 계층 구조를 조정하면 돼요.
kotlin {
jvm()
macosArm64()
iosArm64()
iosSimulatorArm64()
// Apply the default hierarchy explicitly. It'll create, for example, the iosMain source set:
applyDefaultHierarchyTemplate()
sourceSets {
// Create an additional jvmAndMacos source set
val jvmAndMacos by creating {
dependsOn(commonMain.get())
}
macosArm64Main.get().dependsOn(jvmAndMacos)
jvmMain.get().dependsOn(jvmAndMacos)
}
}
- 프로젝트에 이미 템플릿이 생성한 것과 정확히 같은 이름을 가진 소스 세트가 있지만 서로 다른 타깃 집합 간에 공유되는 경우, 현재 템플릿 소스 세트 사이의 기본
dependsOn관계를 수정할 방법이 없어요. 여기서 선택할 수 있는 옵션 하나는 기본 계층 구조 템플릿이나 수동으로 만든 것 중, 목적에 맞는 다른 소스 세트를 찾는 거예요. 다른 옵션은 템플릿을 완전히 opt-out하는 거예요. opt-out하려면gradle.properties에kotlin.mpp.applyDefaultHierarchyTemplate=false를 추가하고 다른 모든 소스 세트를 수동으로 구성하면 돼요. 현재 이런 경우 설정 과정을 단순화하기 위해 자신만의 계층 구조 템플릿을 만드는 API를 작업 중이에요.
전체 계층 구조 템플릿 보기
프로젝트가 컴파일되는 타깃을 선언하면 플러그인이 템플릿에서 공유 소스 세트를 그에 맞게 골라서 프로젝트에 생성해요.
이 예시는 Main 접미사를 생략한(예: commonMain 대신 common 사용) 프로젝트의 프로덕션 부분만 보여줘요. 하지만 *Test 소스에도 모든 것이 동일해요.
새 프로젝트 위저드
JetBrains 팀은 크로스 플랫폼 프로젝트를 만드는 새로운 방식을 소개하고 있어요 – Kotlin Multiplatform 웹 위저드.
새 Kotlin Multiplatform 위저드의 이 첫 구현은 가장 인기 있는 Kotlin Multiplatform 사용 사례를 다뤄요. 이전 프로젝트 템플릿에 대한 모든 피드백을 통합했고 아키텍처를 가능한 한 견고하고 안정적으로 만들었어요.
새 위저드는 분산 아키텍처를 가져서 통합 백엔드와 다양한 프런트엔드를 가질 수 있으며, 웹 버전이 첫 단계예요. 미래에는 IDE 버전 구현과 커맨드라인 도구 생성 모두를 고려하고 있어요. 웹에서는 항상 최신 버전의 위저드를 얻는 반면, IDE에서는 다음 릴리스를 기다려야 해요.
새 위저드로 프로젝트 설정이 그 어느 때보다 쉬워졌어요. 모바일, 서버, 데스크톱 개발용 타깃 플랫폼을 선택해서 프로젝트를 필요에 맞게 조정할 수 있어요. 미래 릴리스에는 웹 개발도 추가할 계획이에요.
새 프로젝트 위저드는 이제 Kotlin으로 크로스 플랫폼 프로젝트를 만드는 선호 방식이에요. 1.9.20부터 Kotlin 플러그인은 더 이상 IntelliJ IDEA에서 Kotlin Multiplatform 프로젝트 위저드를 제공하지 않아요.
새 위저드가 초기 설정을 쉽게 안내해서 온보딩 과정을 훨씬 부드럽게 만들어줘요. 문제가 있으면 위저드 경험 개선을 위해 YouTrack에 보고해 주세요.
Kotlin Multiplatform의 Gradle 설정 캐시 완전 지원
이전에 Gradle 설정 캐시 프리뷰를 소개했는데, Kotlin multiplatform 라이브러리에서 사용 가능했어요. 1.9.20에서 Kotlin Multiplatform 플러그인은 한 발 더 나아가요.
이제 Kotlin CocoaPods Gradle 플러그인과 Xcode 빌드에 필요한 embedAndSignAppleFrameworkForXcode 같은 통합 태스크에서도 Gradle 설정 캐시를 지원해요.
이제 모든 multiplatform 프로젝트가 개선된 빌드 시간을 이용할 수 있어요. Gradle 설정 캐시는 이후 빌드에 구성 단계의 결과를 재사용해 빌드 과정을 빠르게 해요. 자세한 내용과 설정 지침은 Gradle 문서를 참고하세요.
Gradle에서 새 표준 라이브러리 버전 구성 간소화
multiplatform 프로젝트를 만들면 각 소스 세트에 표준 라이브러리(stdlib) 의존성이 자동으로 추가돼요. 이는 multiplatform 프로젝트를 시작하는 가장 쉬운 방법이에요.
이전에 표준 라이브러리 의존성을 수동으로 구성하려면 각 소스 세트별로 개별 구성해야 했어요. kotlin-stdlib:1.9.20부터는 commonMain 루트 소스 세트에서 한 번만 구성하면 돼요.
kotlin {
sourceSets {
// For the common source set
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common:1.9.10")
}
}
// For the JVM source set
val jvmMain by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.10")
}
}
// For the JS source set
val jsMain by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-js:1.9.10")
}
}
}
}
kotlin {
sourceSets {
commonMain {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
}
}
}
}
| 표준 라이브러리 버전 1.9.10 이하 | 표준 라이브러리 버전 1.9.20 |
|---|---|
이 변경은 표준 라이브러리의 Gradle 메타데이터에 새 정보를 포함하면서 가능해졌어요. 덕분에 Gradle이 다른 소스 세트에 대한 올바른 표준 라이브러리 아티팩트를 자동으로 해석할 수 있어요.
써드파티 cinterop 라이브러리 기본 지원
Kotlin 1.9.20은 Kotlin CocoaPods Gradle 플러그인이 적용된 프로젝트의 모든 cinterop 의존성에 대해 opt-in이 아닌 기본 지원을 추가해요.
이제 플랫폼 특정 의존성에 제한받지 않고 더 많은 네이티브 코드를 공유할 수 있다는 뜻이에요. 예를 들어 iosMain 공유 소스 세트에 Pod 라이브러리에 대한 의존성을 추가할 수 있어요.
이전에는 Kotlin/Native 배포와 함께 제공되는 플랫폼 특정 라이브러리(Foundation, UIKit, POSIX 같은)에서만 동작했어요. 이제 모든 써드파티 Pod 라이브러리가 공유 소스 세트에서 기본적으로 사용 가능해요. 그것들을 지원하기 위해 별도의 Gradle 프로퍼티를 지정할 필요가 없어요.
Compose Multiplatform 프로젝트의 Kotlin/Native 컴파일 캐시 지원
이 릴리스는 주로 iOS용 Compose Multiplatform 프로젝트에 영향을 주던 Compose Multiplatform 컴파일러 플러그인과의 호환성 문제를 해결해요.
이 문제를 우회하려면 kotlin.native.cacheKind=none Gradle 프로퍼티를 사용해 캐싱을 비활성화해야 했어요. 하지만 이 우회 방법에는 성능 비용이 있었어요. Kotlin/Native 컴파일러에서 캐싱이 동작하지 않아 컴파일 시간이 느려졌거든요.
이제 문제가 해결됐으므로 gradle.properties 파일에서 kotlin.native.cacheKind=none을 제거하고 Compose Multiplatform 프로젝트에서 개선된 컴파일 시간을 누릴 수 있어요.
컴파일 시간 개선에 대한 더 많은 팁은 Kotlin/Native 문서를 참고하세요.
호환성 가이드라인
프로젝트를 구성할 때 사용 가능한 Gradle, Xcode, Android Gradle 플러그인(AGP) 버전과 Kotlin Multiplatform Gradle 플러그인의 호환성을 확인하세요.
| Kotlin Multiplatform Gradle 플러그인 | Gradle | Android Gradle 플러그인 | Xcode |
|---|---|---|---|
| 1.9.20 | 7.5 이상 | 7.4.2–8.2 | 15.0. 아래 세부사항 참고 |
이 릴리스 기준으로 권장 Xcode 버전은 15.0이에요. Xcode 15.0과 함께 제공되는 라이브러리는 완전히 지원되며 Kotlin 코드 어디에서든 접근할 수 있어요.
하지만 XCode 14.3도 대부분의 경우에는 여전히 동작해야 해요. 로컬 머신에서 14.3을 사용하면 Xcode 15가 제공하는 라이브러리가 보이기는 하지만 접근할 수는 없다는 점을 유의하세요.
Kotlin/Wasm
1.9.20에서 Kotlin Wasm은 Alpha 수준의 안정성에 도달했어요.
- Wasm GC phase 4 및 최종 opcode와의 호환성
- 새
wasm-wasi타깃과wasm타깃의wasm-js로의 이름 변경 - 표준 라이브러리의 WASI API 지원
- Kotlin/Wasm API 개선
Kotlin Wasm은 Alpha예요. 언제든 변경될 수 있어요. 평가 목적으로만 사용해 주세요.
YouTrack에서 피드백을 기다릴게요.
Wasm GC phase 4 및 최종 opcode와의 호환성
Wasm GC가 최종 단계로 이동하면서 바이너리 표현에 사용되는 상수 숫자인 opcode의 업데이트가 필요해요. Kotlin 1.9.20은 최신 opcode를 지원하므로 Wasm 프로젝트를 최신 Kotlin 버전으로 업데이트할 것을 강력히 권장해요. 또한 Wasm 환경과 함께 최신 브라우저 버전을 사용할 것을 권장해요.
- Chrome 및 Chromium 기반 브라우저는 버전 119 이상.
- Firefox는 버전 119 이상. Firefox 119에서는 Wasm GC를 수동으로 켜야 한다는 점에 유의하세요.
새 wasm-wasi 타깃과 wasm 타깃의 wasm-js로의 이름 변경
이 릴리스에서 Kotlin/Wasm용 새 타깃 wasm-wasi를 소개해요. 또한 wasm 타깃을 wasm-js로 이름을 바꿔요. Gradle DSL에서 이 타깃들은 각각 wasmWasi {}와 wasmJs {}로 사용할 수 있어요.
프로젝트에서 이 타깃들을 사용하려면 build.gradle.kts 파일을 업데이트하면 돼요.
kotlin {
wasmWasi {
// ...
}
wasmJs {
// ...
}
}
이전에 도입된 wasm {} 블록은 wasmJs {}를 선호하는 방향으로 deprecated됐어요.
기존 Kotlin/Wasm 프로젝트를 마이그레이션하려면 다음을 하세요.
build.gradle.kts파일에서wasm {}블록 이름을wasmJs {}로 바꿔요.- 프로젝트 구조에서
wasmMain디렉터리 이름을wasmJsMain으로 바꿔요.
표준 라이브러리의 WASI API 지원
이 릴리스에서 Wasm 플랫폼용 시스템 인터페이스인 WASI 지원을 포함했어요. WASI 지원은 시스템 리소스에 접근하는 표준화된 API 집합을 제공해서 브라우저 밖에서, 예를 들어 서버 측 애플리케이션에서 Kotlin/Wasm을 사용하는 것을 더 쉽게 만들어줘요. 또한 WASI는 기능 기반 보안(capability-based security)을 제공하는데, 외부 리소스에 접근할 때 또 다른 보안 계층이에요.
Kotlin/Wasm 애플리케이션을 실행하려면 Wasm Garbage Collection(GC)을 지원하는 VM, 예를 들어 Node.js나 Deno가 필요해요. Wasmtime, WasmEdge 등은 아직 완전한 Wasm GC 지원을 향해 작업 중이에요.
WASI 함수를 가져오려면 @WasmImport 애너테이션을 사용하면 돼요.
import kotlin.wasm.WasmImport
@WasmImport("wasi_snapshot_preview1", "clock_time_get")
private external fun wasiRawClockTimeGet(clockId: Int, precision: Long, resultPtr: Int): Int
wasmWasi를 타깃하는 동안에는 JavaScript와의 상호 운용성을 사용할 수 없어요.
Kotlin/Wasm API 개선
이 릴리스는 Kotlin/Wasm API에 여러 편의 개선을 제공해요. 예를 들어 이제 DOM 이벤트 리스너에 값을 반환하지 않아도 됩니다.
fun main() {
window.onload = {
document.body?.sayHello()
null
}
}
fun main() {
window.onload = { document.body?.sayHello() }
}
| 1.9.20 이전 | 1.9.20에서 |
|---|---|
Gradle
Kotlin 1.9.20은 Gradle 6.8.3부터 8.1까지 완전히 호환돼요. 최신 Gradle 릴리스까지의 Gradle 버전도 사용할 수 있지만, 그 경우 deprecation 경고를 만날 수 있고 일부 새 Gradle 기능이 동작하지 않을 수 있다는 점을 유의하세요.
이 버전은 다음 변경을 가져와요.
- 내부 선언에 접근하기 위한 테스트 픽스처(fixture) 지원
- Konan 디렉터리 경로를 구성하는 새 프로퍼티
- Kotlin/Native 태스크용 새 빌드 리포트 메트릭
내부 선언에 접근하기 위한 테스트 픽스처 지원
Kotlin 1.9.20에서 Gradle의 java-test-fixtures 플러그인을 사용하면 테스트 픽스처가 이제 main 소스 세트 클래스 내의 internal 선언에 접근할 수 있어요. 또한 테스트 픽스처 클래스 내의 internal 선언도 어떤 테스트 소스에서든 볼 수 있어요.
Konan 디렉터리 경로를 구성하는 새 프로퍼티
Kotlin 1.9.20에서 konan.data.dir Gradle 프로퍼티를 사용해 ~/.konan 디렉터리 경로를 커스터마이징할 수 있어요. 환경 변수 KONAN_DATA_DIR으로 구성하지 않아도 되요.
또는 -Xkonan-data-dir 컴파일러 옵션을 사용해 cinterop과 konanc 도구를 통해 ~/.konan 디렉터리로의 커스텀 경로를 구성할 수도 있어요.
Kotlin/Native 태스크용 새 빌드 리포트 메트릭
Kotlin 1.9.20에서 Gradle 빌드 리포트에 Kotlin/Native 태스크 메트릭이 포함돼요. 이 메트릭이 포함된 빌드 리포트 예시는 다음과 같아요.
Total time for Kotlin tasks: 20.81 s (93.1 % of all tasks time)
Time |% of Kotlin time|Task
15.24 s|73.2 % |:compileCommonMainKotlinMetadata
5.57 s |26.8 % |:compileNativeMainKotlinMetadata
Task ':compileCommonMainKotlinMetadata' finished in 15.24 s
Task info:
Kotlin language version: 2.0
Time metrics:
Total Gradle task time: 15.24 s
Spent time before task action: 0.16 s
Task action before worker execution: 0.21 s
Run native in process: 2.70 s
Run entry point: 2.64 s
Size metrics:
Start time of task action: 2023-07-27T11:04:17
Task ':compileNativeMainKotlinMetadata' finished in 5.57 s
Task info:
Kotlin language version: 2.0
Time metrics:
Total Gradle task time: 5.57 s
Spent time before task action: 0.04 s
Task action before worker execution: 0.02 s
Run native in process: 1.48 s
Run entry point: 1.47 s
Size metrics:
Start time of task action: 2023-07-27T11:04:32
또한 kotlin.experimental.tryK2 빌드 리포트는 이제 컴파일된 모든 Kotlin/Native 태스크를 포함하고 사용된 언어 버전을 나열해요.
##### 'kotlin.experimental.tryK2' results #####
:lib:compileCommonMainKotlinMetadata: 2.0 language version
:lib:compileKotlinJvm: 2.0 language version
:lib:compileKotlinIosArm64: 2.0 language version
:lib:compileKotlinIosSimulatorArm64: 2.0 language version
:lib:compileKotlinLinuxX64: 2.0 language version
:lib:compileTestKotlinJvm: 2.0 language version
:lib:compileTestKotlinIosSimulatorArm64: 2.0 language version
:lib:compileTestKotlinLinuxX64: 2.0 language version
##### 100% (8/8) tasks have been compiled with Kotlin 2.0 #####
Gradle 8.0을 사용한다면, 특히 Gradle 설정 캐시가 활성화된 경우 빌드 리포트에 몇 가지 문제가 생길 수 있어요. 이는 알려진 문제이며 Gradle 8.1 이상에서 수정됐어요.
표준 라이브러리
Kotlin 1.9.20에서 Kotlin/Native 표준 라이브러리가 Stable이 되고, 몇 가지 새 기능이 있어요.
- Enum class values 제네릭 함수의 대체
- Kotlin/JS의 HashMap 성능 개선
Enum class values 제네릭 함수의 대체
이 기능은 Experimental이에요. 언제든 제거되거나 변경될 수 있어요. Opt-in이 필요하며(아래 세부사항 참고) 평가 목적으로만 사용해 주세요. YouTrack에서 피드백을 기다릴게요.
Kotlin 1.9.0에서 enum 클래스의 entries 프로퍼티가 Stable이 됐어요. entries 프로퍼티는 합성 values() 함수의 현대적이고 성능 좋은 대체품이에요. Kotlin 1.9.20의 일환으로 제네릭 enumValues<T>() 함수의 대체품인 enumEntries<T>()가 있어요.
enumValues<T>() 함수는 계속 지원되지만, 성능 영향이 더 적으므로 enumEntries<T>() 함수를 사용할 것을 권장해요. enumValues<T>()를 호출할 때마다 새 배열이 만들어지는 반면, enumEntries<T>()를 호출하면 매번 같은 리스트가 반환돼서 훨씬 효율적이에요.
예를 들어:
enum class RGB { RED, GREEN, BLUE }
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T : Enum<T>> printAllValues() {
print(enumEntries<T>().joinToString { it.name })
}
printAllValues<RGB>()
// RED, GREEN, BLUE
enumEntries 함수를 활성화하는 방법
이 기능을 시험해 보려면 @OptIn(ExperimentalStdlibApi)으로 opt-in하고 언어 버전 1.9 이상을 사용하면 돼요. 최신 버전의 Kotlin Gradle 플러그인을 사용한다면 기능을 테스트하기 위해 언어 버전을 지정할 필요가 없어요.
Kotlin/Native 표준 라이브러리가 Stable이 됨
Kotlin 1.9.0에서 Kotlin/Native 표준 라이브러리를 안정화 목표에 더 가깝게 만들기 위해 취한 조치를 설명했어요. Kotlin 1.9.20에서 마침내 이 작업을 마무리하고 Kotlin/Native 표준 라이브러리를 Stable로 만들어요. 이 릴리스의 하이라이트 몇 가지는 다음과 같아요.
Vector128클래스가kotlin.native패키지에서kotlinx.cinterop패키지로 옮겨졌어요.- Kotlin 1.9.0의 일환으로 도입된
ExperimentalNativeApi와NativeRuntimeApi애너테이션의 opt-in 요구 수준이WARNING에서ERROR로 올라갔어요. - Kotlin/Native 컬렉션이 이제 동시 수정(concurrent modification)을 감지해요. 예를 들어
ArrayList와HashMap컬렉션에서요. Throwable클래스의printStackTrace()함수가 이제STDOUT대신STDERR로 출력해요.printStackTrace()의 출력 형식은 Stable이 아니며 변경될 수 있어요.
Atomics API 개선
Kotlin 1.9.0에서 Kotlin/Native 표준 라이브러리가 Stable이 될 때 Atomics API가 Stable이 될 준비가 되었다고 말했어요. Kotlin 1.9.20은 다음 추가 변경을 포함해요.
- 실험용
AtomicIntArray,AtomicLongArray,AtomicArray<T>클래스가 도입됐어요. 이 새 클래스들은 Java의 원자 배열과 일관되도록 특별히 설계되어서, 미래에 공통 표준 라이브러리에 포함될 수 있게 해요.AtomicIntArray,AtomicLongArray,AtomicArray<T>클래스는 Experimental이에요. 언제든 제거되거나 변경될 수 있어요. 시험해 보려면@OptIn(ExperimentalStdlibApi)으로 opt-in하세요. 평가 목적으로만 사용하세요. YouTrack에서 피드백을 기다릴게요. kotlin.native.concurrent패키지에서 Kotlin 1.9.0에 deprecation 수준WARNING으로 deprecated된 Atomics API의 deprecation 수준이ERROR로 올라갔어요.kotlin.concurrent패키지에서 deprecation 수준이ERROR였던AtomicInt와AtomicLong클래스의 멤버 함수들이 제거됐어요.AtomicReference클래스의 모든 멤버 함수가 이제 원자 내장 함수(atomic intrinsic)를 사용해요.
Kotlin 1.9.20의 모든 변경에 대한 자세한 내용은 YouTrack 티켓을 참고하세요.
Kotlin/JS의 HashMap 성능 개선
Kotlin 1.9.20은 Kotlin/JS에서 HashMap 연산의 성능을 개선하고 메모리 풋프린트를 줄여요. 내부적으로 Kotlin/JS는 내부 구현을 개방 주소법(open addressing)으로 바꿨어요. 이는 다음 경우 성능 개선을 볼 수 있다는 뜻이에요.
HashMap에 새 요소를 삽입할 때.HashMap에서 기존 요소를 검색할 때.HashMap에서 키나 값을 반복할 때.
문서 업데이트
Kotlin 문서에 주목할 만한 변경이 몇 가지 있었어요.
- JVM Metadata API 참고 문서 – Kotlin/JVM으로 메타데이터를 파싱하는 방법을 살펴볼 수 있어요.
- 시간 측정 가이드 – Kotlin에서 시간을 계산하고 측정하는 방법을 배울 수 있어요.
- Kotlin 둘러보기의 개선된 Collections 챕터 – 이론과 실습을 모두 담은 챕터로 Kotlin 프로그래밍 언어의 기초를 배울 수 있어요.
- 확실히 널이 아닌 타입(Definitely non-nullable types) – 확실히 널이 아닌 제네릭 타입에 대해 배울 수 있어요.
- 개선된 Arrays 페이지 – 배열과 언제 배열을 사용해야 하는지 배울 수 있어요.
- Kotlin Multiplatform의 expected/actual 선언 – Kotlin Multiplatform에서 expected/actual 선언 메커니즘에 대해 배울 수 있어요.
Kotlin 1.9.20 설치
IDE 버전 확인
IntelliJ IDEA 2023.1.x와 2023.2.x는 Kotlin 플러그인을 1.9.20으로 업데이트하도록 자동으로 제안해요. IntelliJ IDEA 2023.3에 Kotlin 1.9.20 플러그인이 포함될 예정이에요.
Android Studio Hedgehog (231)과 Iguana (232)는 다가오는 릴리스에서 Kotlin 1.9.20을 지원할 예정이에요.
새 커맨드라인 컴파일러는 GitHub 릴리스 페이지에서 다운로드할 수 있어요.
Gradle 설정 구성
Kotlin 아티팩트와 의존성을 다운로드하려면 Maven Central 저장소를 사용하도록 settings.gradle(.kts) 파일을 업데이트하면 돼요.
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
저장소가 지정되지 않으면 Gradle이 폐기된 JCenter 저장소를 사용해서 Kotlin 아티팩트에 문제가 생길 수 있어요.