본문 바로가기
Kotlin/What's new

[Kotlin 번역] What's new in Kotlin 1.6.20

by 노력남자 2023. 9. 17.
반응형

2022년 4월 4일

 
Kotlin 1.6.20은 미래 언어 기능의 미리보기를 제공하며, 멀티플랫폼 프로젝트의 계층 구조를 기본값으로 설정하고 다른 구성 요소에 대한 진화적인 개선을 가져옵니다.

또한 이러한 변경 사항에 대한 간략한 개요를 이 비디오에서 찾을 수 있습니다:
 


언어


Kotlin 1.6.20에서 두 가지 새로운 언어 기능을 시도해 볼 수 있습니다:

  • Kotlin/JVM용 컨텍스트 리시버 프로토타입
  • 절대로 널이 아닌 타입


Kotlin/JVM용 컨텍스트 리시버 프로토타입


이 기능은 Kotlin/JVM 전용의 프로토타입입니다. -Xcontext-receivers를 활성화하면 컴파일러가 프리릴리스 바이너리를 생성하며, 이는 프로덕션 코드에서 사용할 수 없습니다. 컨텍스트 리시버는 장난감 프로젝트에서만 사용하세요. YouTrack에서의 피드백을 환영합니다.

Kotlin 1.6.20에서는 이제 하나의 리시버에 제한되지 않습니다. 더 필요한 경우 함수, 프로퍼티 및 클래스를 컨텍스트 종속적 또는 컨텍스트로 만들어서 선언에 컨텍스트 리시버를 추가할 수 있습니다. 컨텍스트 리시버가 선언한 내용은 다음과 같습니다:

  • 모든 선언된 컨텍스트 리시버가 호출자의 스코프에 암시적 리시버로 존재해야 합니다.
  • 선언된 컨텍스트 리시버를 몸체 스코프로 가져옵니다.

 

interface LoggingContext {
    val log: Logger // 이 컨텍스트는 로거에 대한 참조를 제공합니다.
}

context(LoggingContext)
fun startBusinessOperation() {
    // LoggingContext가 암시적 리시버로 있는 경우 log 프로퍼티에 액세스할 수 있습니다.
    log.info("Operation has started")
}

fun test(loggingContext: LoggingContext) {
    with(loggingContext) {
        // 암시적 리시버로 LoggingContext를 스코프에 가지고 있어야 startBusinessOperation()을 호출할 수 있습니다.
        startBusinessOperation()
    }
}


프로젝트에서 컨텍스트 리시버를 활성화하려면 -Xcontext-receivers 컴파일러 옵션을 사용하십시오. 이 기능과 그 문법에 대한 자세한 내용은 KEEP에서 확인할 수 있습니다.

이 구현이 프로토타입임을 유의하십시오:

  • -Xcontext-receivers를 활성화하면 컴파일러가 프리릴리스 바이너리를 생성하며, 이는 프로덕션 코드에서 사용할 수 없습니다.
  • 현재 IDE에서 컨텍스트 리시버 지원이 아직 최소한입니다.


이 기능을 장난감 프로젝트에서 사용하고 생각과 경험을 이 YouTrack 이슈에서 공유해 주세요. 문제가 발생하면 새 이슈를 제기해 주세요.


절대로 널이 아닌 타입


절대로 널이 아닌 타입은 베타입니다. 거의 안정적이지만 앞으로 변경 사항이 필요할 수 있습니다. 변경 사항을 최소화하기 위해 최선을 다하겠습니다.

제네릭 Java 클래스 및 인터페이스를 확장할 때 더 나은 상호 운용성을 제공하기 위해 Kotlin 1.6.20에서는 새로운 구문 T & Any를 사용하여 사용 사이트에서 제네릭 타입 매개변수를 절대로 널이 아닌 것으로 표시할 수 있습니다. 이 구문 형태는 교차 형식의 표기법에서 나온 것이며, 현재는 왼쪽에 널 가능한 상한을 가진 타입 매개변수에 & 오른쪽에 절대로 널이 아닌 Any를 가질 수 있는 타입 매개변수에만 제한되어 있습니다.
 

fun <T> elvisLike(x: T, y: T & Any): T & Any = x ?: y

fun main() {
    // OK
    elvisLike<String>("", "").length
    // 오류: 'null'은 널이 아닌 타입의 값이 될 수 없습니다.
    elvisLike<String>("", null).length

    // OK
    elvisLike<String?>(null, "").length
    // 오류: 'null'은 널이 아닌 타입의 값이 될 수 없습니다.
    elvisLike<String?>(null, null).length
}

 
이 기능을 활성화하려면 언어 버전을 1.7로 설정하십시오:

kotlin {
    sourceSets.all {
        languageSettings.apply {
            languageVersion = "1.7"
        }
    }
}


절대로 널이 아닌 타입에 대해 더 자세히 알아보려면 KEEP에서 확인하세요.
 

Kotlin/JVM

 
Kotlin 1.6.20은 다음과 같은 개선 사항을 제공합니다.

새로운 @JvmDefaultWithCompatibility 어노테이션을 통한 인터페이스의 기본 메서드 호환성 개선


Kotlin 1.6.20에서는 새로운 @JvmDefaultWithCompatibility 어노테이션을 소개합니다. 이 어노테이션을 -Xjvm-default=all 컴파일러 옵션과 함께 사용하여 Kotlin 인터페이스의 모든 비-추상 멤버에 대한 JVM 인터페이스의 기본 메서드를 생성할 수 있습니다.

이전에는 -Xjvm-default=all 옵션을 사용하지 않고 Kotlin 인터페이스를 컴파일하는 클라이언트가 있으면 이 옵션을 사용하여 컴파일된 코드와 이 옵션을 사용하지 않고 컴파일된 코드가 이진 호환성이 없을 수 있었습니다. Kotlin 1.6.20 이전에는 이러한 호환성 문제를 피하기 위해 권장되는 방법은 -Xjvm-default=all-compatibility 모드를 사용하고, 또한 이러한 유형의 호환성이 필요하지 않은 인터페이스에 대해 @JvmDefaultWithoutCompatibility 어노테이션을 사용하는 것이었습니다.

그러나 이 방법은 몇 가지 단점이 있었습니다:

  • 새로운 인터페이스가 추가될 때 어노테이션을 추가하는 것을 잊을 수 있습니다.
  • 일반적으로 공개 API가 아닌 부분에는 일반적으로 공개 API보다 많은 인터페이스가 있으므로 코드의 여러 곳에서 이 어노테이션을 사용해야 합니다.


이제 -Xjvm-default=all 모드를 사용하고 인터페이스에 @JvmDefaultWithCompatibility 어노테이션을 추가할 수 있습니다. 이렇게 하면 공개 API의 모든 인터페이스에 이 어노테이션을 한 번 추가할 수 있으며 새로운 비공개 코드에 대한 어노테이션을 사용할 필요가 없게 됩니다.

이 새로운 어노테이션에 대한 피드백은 YouTrack 티켓에서 남겨주십시오.


-Xjvm-default 모드의 호환성 변경 사항


Kotlin 1.6.20은 모듈을 기본 모드(컴파일러 옵션 -Xjvm-default=disable)로 컴파일하여 -Xjvm-default=all 또는 -Xjvm-default=all-compatibility 모드로 컴파일된 모듈과 호환성을 유지할 수 있도록 합니다. 또한 모든 모듈이 -Xjvm-default=all 또는 -Xjvm-default=all-compatibility 모드로 컴파일되면 컴파일이 성공합니다. 이에 관한 피드백은 YouTrack 이슈에서 남겨주십시오.

Kotlin 1.6.20은 컴파일러 옵션 -Xjvm-default의 호환성 및 활성 모드를 폐지합니다. 호환성과 다른 모드의 설명에는 호환성과 관련된 변경 사항이 있지만 전반적인 논리는 동일합니다. 업데이트된 설명을 확인할 수 있습니다.

Java 인터옵에서 기본 메서드에 대한 자세한 정보는 상호 운용성 문서와 이 블로그 포스트를 참조하십시오.

JVM 백엔드의 단일 모듈 병렬 컴파일 지원


단일 모듈의 JVM 백엔드 병렬 컴파일 지원은 실험적입니다. 언제든지 중단되거나 변경될 수 있습니다. 이를 사용하려면 Opt-in이 필요하며 평가 목적으로만 사용해야 합니다. 이에 대한 피드백은 YouTrack에서 환영합니다.

Kotlin은 새로운 JVM IR 백엔드 컴파일 시간을 개선하기 위한 작업을 계속 진행하고 있습니다. Kotlin 1.6.20에서는 모듈의 모든 파일을 병렬로 컴파일하는 실험적인 JVM IR 백엔드 모드를 추가했습니다. 병렬 컴파일은 총 컴파일 시간을 최대 15%까지 줄일 수 있습니다.

실험적 병렬 백엔드 모드를 사용하려면 컴파일러 옵션 -Xbackend-threads를 사용하세요. 이 옵션에는 다음과 같은 인수를 사용하십시오.

  • N은 사용하려는 스레드 수입니다. CPU 코어 수보다 크지 않아야 합니다. 그렇지 않으면 스레드 간의 컨텍스트 전환으로 인해 병렬화의 효과가 떨어질 수 있습니다.
  • 0은 각 CPU 코어에 대한 별도의 스레드를 사용합니다.


Gradle은 작업을 병렬로 실행할 수 있지만 프로젝트(또는 프로젝트의 주요 부분)가 Gradle의 관점에서는 하나의 큰 작업일 때 병렬화가 큰 도움이 되지 않을 수 있습니다. 매우 큰 단일 모듈이 있는 경우 병렬 컴파일을 사용하여 더 빨리 컴파일하세요. 프로젝트가 많은 작은 모듈로 구성되어 있고 Gradle에서 병렬로 빌드되는 경우, 추가적인 병렬

화 계층을 추가하면 컨텍스트 전환으로 인해 성능에 오히려 해를 끼칠 수 있습니다.

병렬 컴파일에는 몇 가지 제한 사항이 있습니다.

  • kapt와 함께 작동하지 않습니다. kapt는 IR 백엔드를 비활성화합니다.
  • 디자인상 더 많은 JVM 힙이 필요합니다. 힙의 양은 스레드 수에 비례합니다.


함수형 인터페이스 생성자에 대한 호출 가능 참조 지원


함수형 인터페이스 생성자에 대한 호출 가능 참조 지원은 실험적입니다. 언제든지 중단되거나 변경될 수 있습니다. 이를 사용하려면 Opt-in이 필요하며 평가 목적으로만 사용해야 합니다. 이에 대한 피드백은 YouTrack에서 환영합니다.

함수형 인터페이스 생성자에 대한 호출 가능 참조 지원은 생성자 함수가 포함된 인터페이스에서 함수형 인터페이스로의 마이그레이션을 위한 소스 호환 방법을 추가합니다.

다음 코드를 고려해보세요.

interface Printer {
    fun print()
}

fun Printer(block: () -> Unit): Printer = object : Printer { override fun print() = block() }


호출 가능 참조를 함수형 인터페이스 생성자에 대한 호출 가능 참조를 사용하여 다음과 같이 간단히 바꿀 수 있습니다.

fun interface Printer {
    fun print()
}


생성자는 암시적으로 생성되며 ::Printer 함수 참조를 사용하는 모든 코드가 컴파일됩니다.

이러한 이진 호환성을 유지하기 위해 레거시 함수 Printer에 @Deprecated 어노테이션과 DeprecationLevel.HIDDEN으로 표시하세요.

@Deprecated(message = "Your message about the deprecation", level = DeprecationLevel.HIDDEN)
fun Printer(...) {...}


이 기능을 활성화하려면 컴파일러 옵션 -XXLanguage:+KotlinFunInterfaceConstructorReference를 사용하세요.
 

Kotlin/Native

 
Kotlin/Native 1.6.20은 새로운 구성 요소의 지속적인 개발을 표시합니다. 이제 Kotlin이 다른 플랫폼에서 일관된 경험을 제공하기 위한 노력을 계속하고 있습니다. 다음은 주요 업데이트입니다:

새로운 메모리 매니저에 대한 업데이트


Kotlin/Native의 새로운 메모리 매니저는 아직 알파 상태입니다. 나중에 호환되지 않게 변경될 수 있으며 수동으로 마이그레이션을 요구할 수 있습니다. 이에 대한 피드백을 YouTrack에서 환영합니다.

Kotlin 1.6.20에서는 새로운 Kotlin/Native 메모리 매니저의 알파 버전을 시도해볼 수 있습니다. 이 메모리 매니저는 JVM 및 Native 플랫폼 간의 차이를 제거하여 멀티플랫폼 프로젝트에서 일관된 개발자 경험을 제공합니다. 예를 들어, Android와 iOS에서 모두 작동하는 새로운 크로스 플랫폼 모바일 애플리케이션을 만드는 데 훨씬 쉽게 접근할 수 있습니다.

새로운 Kotlin/Native 메모리 매니저는 스레드 간 객체 공유에 대한 제한을 해제합니다. 또한 특별한 관리나 어노테이션 없이 안전하고 누수가 없는 동시 프로그래밍 기본 요소를 제공합니다.

새로운 메모리 매니저는 향후 버전에서 기본값이 될 예정이므로 지금 사용해 보기를 권장합니다. 새로운 메모리 매니저에 대한 자세한 내용과 데모 프로젝트를 살펴보거나 직접 시도하려면 마이그레이션 지침을 확인하세요.

새로운 메모리 매니저를 사용하여 프로젝트를 테스트하고 YouTrack 이슈 트래커에서 피드백을 공유하세요.


새 메모리 매니저에서 스위프트와 함께 작동하는 병렬 구현


이미 Kotlin 1.6에서 발표된 새로운 메모리 매니저로 전환한 경우, 평균적으로 35%의 개선이 있는 것을 확인할 수 있을 것입니다. Kotlin 1.6.20부터는 새 메모리 매니저의 스위프트와 함께 사용하는 병렬 구현도 제공됩니다. 이를 통해 가비지 컬렉터 일시 중단의 성능을 개선하고 실행 시간을 줄일 수 있습니다.

새로운 Kotlin/Native 메모리 매니저에 대한 이러한 기능을 활성화하려면 다음 컴파일러 옵션을 사용하십시오:

-Xgc=cms


새 메모리 매니저의 성능에 대한 피드백을 아래 YouTrack 이슈에서 공유해주십시오.


어노테이션 클래스의 인스턴스화


Kotlin 1.6.0에서 어노테이션 클래스의 인스턴스화는 Kotlin/JVM 및 Kotlin/JS에서 안정화되었습니다. 1.6.20 버전에서는 Kotlin/Native에서도 지원이 추가되었습니다.

어노테이션 클래스의 인스턴스화에 대한 자세한 내용은 해당 문서를 참조하세요.


Swift async/await과의 상호 운용성: KotlinUnit 대신 Swift의 Void 반환


Swift async/await과의 동시성 상호 운용성은 실험적입니다. 언제든지 중단되거나 변경될 수 있으며 평가 목적으로만 사용해야 합니다. 이에 대한 피드백은 YouTrack에서 환영합니다.

Kotlin 1.6.20에서는 Swift 5.5부터 사용 가능한 Swift async/await과의 실험적 상호 운용성을 계속 개선하고 있습니다. Kotlin 1.6.20은 이전 버전과 다르게 Unit 반환 형식을 가진 중단 함수를 처리하는 방식에서 차이가 있습니다.

이전에는 이러한 함수가 Swift에서 KotlinUnit을 반환하는 async 함수로 표시되었습니다. 그러나 이러한 함수의 올바른 반환 형식은 비동기가 아닌 함수와 유사한 Void입니다.

기존 코드를 깨뜨리지 않으려고 하며, Unit 반환 중단 함수를 Swift에서 Void 반환 형식으로 변환하는 컴파일러를 사용하기 위해 다음 Gradle 속성을 소개하고 있습니다:
 

# gradle.properties
kotlin.native.binary.unitSuspendFunctionObjCExport=proper


향후 Kotlin 릴리스에서 이 동작을 기본값으로 만들 계획입니다.


libbacktrace를 사용한 개선된 스택 트레이스


소스 위치를 해결하기 위해 libbacktrace를 사용하는 것은 실험적입니다. 언제든지 중단되거나 변경될 수 있으며 평가 목적으로만 사용해야 합니다. 이에 대한 피드백은 YouTrack에서 환영합니다.

Kotlin/Native은 이제 리눅스 (linuxMips32 및 linuxMipsel32 제

외) 및 Android Native* 대상의 디버깅을 위해 파일 위치 및 라인 번호를 포함한 자세한 스택 트레이스를 생성할 수 있습니다.

이 기능은 libbacktrace 라이브러리를 내부적으로 사용합니다. 차이를 확인하기 위해 다음 코드를 살펴보세요:
 

fun main() = bar()
fun bar() = baz()
inline fun baz() {
    error("")
}


- 1.6.20 이전:

Uncaught Kotlin exception: kotlin.IllegalStateException:
 {...}
Uncaught Kotlin exception: kotlin.IllegalStateException:
   at 0   example.kexe        0x227190       kfun:kotlin.Throwable#<init>(kotlin.String?){} + 96
   at 1   example.kexe        0x221e4c       kfun:kotlin.Exception#<init>(kotlin.String?){} + 92
   at 2   example.kexe        0x221f4c       kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 92
   at 3   example.kexe        0x22234c       kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 92
   at 4   example.kexe        0x25d708       kfun:#bar(){} + 104
   at 5   example.kexe        0x25d68c       kfun:#main(){} + 12


- 1.6.20에서 libbacktrace 사용:

Uncaught Kotlin exception: kotlin.IllegalStateException:
 {...}
Uncaught Kotlin exception: kotlin.IllegalStateException:
   at 0   example.kexe        0x229550    kfun:kotlin.Throwable#<init>(kotlin.String?){} + 96 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Throwable.kt:24:37)
   at 1   example.kexe        0x22420c    kfun:kotlin.Exception#<init>(kotlin.String?){} + 92 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:44)
   at 2   example.kexe        0x22430c    kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 92 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:44)
   at 3   example.kexe        0x22470c    kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 92 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:70:44)
   at 4   example.kexe        0x25fac8    kfun:#bar(){} + 104 [inlined] (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/libraries/stdlib/src/kotlin/util/Preconditions.kt:143:56)
   at 5   example.kexe        0x25fac8    kfun:#bar(){} + 104 [inlined] (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:4:5)
   at 6   example.kexe        0x25fac8    kfun:#bar(){} + 104 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:2:13)
   at 7   example.kexe        0x25fa4c    kfun:#main(){} + 12 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:1:14)


Apple 대상에서는 이미 스택 트레이스에 파일 위치와 라인 번호가 포함되어 있었지만 libbacktrace는 인라인 함수 호출에 대한 자세한 정보를 제공합니다.


스탠드얼론 Android 실행 파일 지원


이전에는 Kotlin/Native의 Android Native 실행 파일이 실제 실행 파일이 아니라 NativeActivity로 사용할 수 있는 공유 라이브러리였습니다. 이제 Android Native 대상에 대한 표준 실행 파일을 생성하는 옵션이 있습니다.

프로젝트의 build.gradle(.kts) 부분에서 androidNative 대상의 실행 파일 블록을 구성하세요. 다음 바이너리 옵션을 추가하세요:

kotlin {
    androidNativeX64("android") {
        binaries {
            executable {
                binaryOptions["androidProgramType"] = "standalone"
            }
        }
    }
}


이 기능은 Kotlin 1.7.0에서 기본값이 될 예정입니다. 현재 동작을 유지하려면 다음 설정을 사용하세요:

binaryOptions["androidProgramType"] = "nativeActivity"


이 기능의 구현에 기여한 Mattia Iavarone에게 감사드립니다!


성능 개선


Kotlin/Native 컴파일 프로세스를 가속화하고 개발 경험을 향상시키기 위해 노력하고 있습니다.

Kotlin 1.6.20은 Kotlin이 생성하는 LLVM IR에 영향을 미치는 성능 업데이트 및 버그 수정을 제공합니다. 내부 프로젝트의 벤치마크에 따르면 다음과 같은 평균 성능 향상을 달성했습니다:

  • 실행 시간 감소: 15%
  • 릴리스 및 디버그 이진 파일의 코드 크기 감소: 20%
  • 릴리스 이진 파일의 컴파일 시간 감소: 26%


이러한 변경 사항은 큰 내부 프로젝트의 디버그 이진 파일의 컴파일 시간을 10% 감소시킵니다.

이를 위해 몇 가지 컴파일러에서 생성한 합성 객체의 정적 초기화를 구현하고, 각 함수에 대한 LLVM IR 구조를 개선했으며, 컴파일러 캐시를 최적화했습니다.


cinterop 모듈 가져오기 중에 개선된 오류 처리


이 릴리스에서는 cinterop 도구를 사용하여 Objective-C 모듈 (일반적으로 CocoaPods 팟과 관련이 있음)을 가져올 때 개선된 오류 처리가 도입되었습니다. 이전에 Objective-C 모듈을 사용할 때 오류가 발생하면 "fatal error: could not build module $name"과 같은 정보가 제공되었으나 이제 확장된 설명을 포함한 오류 메시지를 받게 됩니다.


Xcode 13 라이브러리 지원


Xcode 13으로 제공되는 라이브러리는 이 릴리스를 통해 완전한 지원을 받습니다. Kotlin 코드에서 어디서든 액세스할 수 있습니다.
 

Kotlin Multiplatform


Kotlin 1.6.20에서 Kotlin Multiplatform에 다음과 같은 주요 업데이트가 제공됩니다:

  • 계층 구조 지원이 이제 모든 새로운 멀티플랫폼 프로젝트의 기본값입니다.
  • Kotlin CocoaPods Gradle 플러그인은 CocoaPods 통합을 위한 여러 유용한 기능을 추가했습니다.


멀티플랫폼 프로젝트의 계층 구조 지원


Kotlin 1.6.20은 계층 구조 지원을 기본으로 제공합니다. Kotlin 1.4.0에서 처음 소개한 이후에 프런트 엔드를 크게 개선했으며 IDE에서의 가져오기(import)도 안정적으로 지원합니다.

이전에 멀티플랫폼 프로젝트에 코드를 추가하는 두 가지 방법이 있었습니다. 첫 번째 방법은 플랫폼별 소스 세트에 삽입하는 것이었는데, 이는 하나의 대상(target)에 대해서만 사용 가능하며 다른 플랫폼에서 재사용할 수 없습니다. 두 번째 방법은 Kotlin이 현재 지원하는 모든 플랫폼 간에 공유되는 공통 소스 세트를 사용하는 것이었습니다.

이제 공통 로직과 서드파티 API를 많이 재사용하는 여러 유사한 네이티브 대상 간에 소스 코드를 공유할 수 있습니다. 이 기술은 올바른 기본 종속성을 제공하고 공유 코드에서 사용 가능한 정확한 API를 찾아줍니다. 이로써 복잡한 빌드 설정 및 다른 대상을 위한 사용되지 않는 API 사용을 방지하며 공유 소스 세트를 네이티브 대상 간에 공유하기 위한 IDE 지원을 위한 해결책 사용을 피할 수 있습니다.

이 기술은 라이브러리 작성자에게도 유용합니다. 계층적 프로젝트 구조를 사용하면 특정 대상을 위해 공통 API를 포함한 라이브러리를 게시하고 사용할 수 있습니다.

기본적으로 계층 구조 프로젝트로 게시된 라이브러리는 계층 구조 프로젝트와만 호환됩니다.


프로젝트 내에서 더 나은 코드 공유


계층 구조 지원이 없으면 특정 Kotlin 대상을 기준으로 코드를 공유하는 간단한 방법이 없습니다. 가장 일반적인 예는 iOS 모든 대상 간에 코드를 공유하고 Foundation과 같은 iOS 특정 종속성에 액세스하는 것입니다.

계층 구조 프로젝트 지원 덕분에 이제 이를 기본으로 구현할 수 있습니다. 새로운 구조에서 소스 세트는 계층 구조를 형성합니다. 각 소스 세트가 컴파일되는 해당 대상에 대해 사용 가능한 플랫폼별 언어 기능 및 종속성을 사용할 수 있습니다.

예를 들어 iOS 장치와 시뮬레이터를 위한 두 개의 대상 (iosArm64 및 iosX64)이 있는 전형적인 멀티플랫폼 프로젝트를 고려해 보겠습니다. Kotlin 도구는 두 대상이 동일한 기능을 가지고 있음을 이해하고 중간 소스 세트 iosMain에서 해당 기능에 액세스할 수 있게 해줍니다.
 


라이브러리 작성자에게 더 많은 기회 제공


멀티플랫폼 라이브러리가 게시되면 중간 소스 세트의 API가 올바르게 게시되어 소비자에게 사용 가능합니다. 또한 Kotlin 도구 체인은 자동으로 소비자 소스 세트에서 사용 가능한 API를 찾아줄 것이며, 다른 대상을 위한 API를 잘못 사용하는 경우와 같은 안전하지 않은 사용을 주의 깊게 검사합니다.


구성 및 설정


Kotlin 1.6.20부터 모든 새 멀티플랫폼 프로젝트에는 계층 구조 프로젝트 구조가 있습니다. 추가 설정이 필요하지 않습니다.

- 이미 수동으로 활성화한 경우 gradle.properties에서 사용되지 않는 옵션을 제거할 수 있습니다:

# gradle.properties
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false // 이전 설정에 따라 'true' 또는 'false'


- Kotlin 1.6.20을 사용할 경우 최상의 경험을 얻으려면 Android Studio 2021.1.1 (Bumblebee) 이상을 사용하는 것이 좋습니다.

- 계층 구조 지원을 비활성화하려면 gradle.properties에서 다음 옵션을 설정하세요:

# gradle.properties
kotlin.mpp.hierarchicalStructureSupport=false


피드백 제공


이것은 전체 생태계에 대한 중요한 변경 사항입니다. 이것을 더 나아지게 만들기 위해 여러분의 피드백을 환영합니다.

지금 시도하고 만난 어려움을 issue tracker에 보고해 주시기를 부탁드립니다.


Kotlin CocoaPods Gradle 플러그인


CocoaPods 통합을 간소화하기 위해 Kotlin 1.6.20은 다음과 같은 기능을 제공합니다:

- CocoaPods 플러그인은 이제 모든 등록된 대상으로 XCFramework를 빌드하고 Podspec 파일을 생성하는 작업을 수행하는 태스크를 가지고 있습니다. 이는 직접적으로 Xcode와 통합하지 않고 로컬 CocoaPods 저장소에 아티팩트를 빌드하고 배포하려는 경우 유용합니다.

XCFramework 빌드에 대해 자세히 알아보세요.

- 프로젝트에서 CocoaPods 통합을 사용하는 경우 Gradle 프로젝트 전체에 필요한 Pod 버전을 지정하는 것이 일반적입니다. 이제 여러 옵션을 사용할 수 있습니다:

   - cocoapods 블록에서 직접 Pod 버전을 지정
   - 기존 Gradle 프로젝트 버전 사용 계속
   - 이러한 속성 중 어느 것도 구성되지 않은 경우 오류가 발생합니다.

- cocoapods 블록에서 CocoaPod 이름을 구성할 수 있으며 전체 Gradle 프로젝트 이름을 변경할 필요가 없습니다.

- CocoaPods 플러그인은 libraries 또는 vendored_frameworks와 같이 이전에 하드 코딩되었던 Podspec 파일의 속성을 구성하는 데 사용할 수 있는 extraSpecAttributes 속성을 도입합니다.

kotlin {
    cocoapods {
        version = "1.0"
        name = "MyCocoaPod"
        extraSpecAttributes["social_media_url"] = 'https://twitter.com/kotlin'
        extraSpecAttributes["vendored_frameworks"] = 'CustomFramework.xcframework'
        extraSpecAttributes["libraries"] = 'xml'
    }
}


Kotlin CocoaPods Gradle 플러그인 DSL 참조에서 전체 Kotlin CocoaPods Gradle 플러그인 DSL 참조를 확인하세요.
 

Kotlin/JS


Kotlin 1.6.20에서 Kotlin/JS의 개선 사항은 주로 IR(Intermediate Representation) 컴파일러에 영향을 미칩니다:


IR 컴파일러를 사용한 개발용 이진 파일의 증분 컴파일


Kotlin/JS 개발을 IR 컴파일러와 함께 더 효율적으로 만들기 위해 우리는 새로운 증분 컴파일 모드를 도입하고 있습니다.

이 모드에서는 compileDevelopmentExecutableKotlinJs Gradle 작업을 사용하여 개발용 이진 파일을 빌드할 때 컴파일러가 모듈 수준에서 이전 컴파일의 결과를 캐시합니다. 이전 컴파일에서 변경되지 않은 소스 파일에 대해서는 캐시된 컴파일 결과를 사용하여 다음 컴파일에서 빠르게 완료됩니다. 이 개선 사항은 개발 과정에만 적용되며(편집-빌드-디버그 사이클 단축), 제품 아티팩트 빌드에는 영향을 미치지 않습니다.

개발용 이진 파일의 증분 컴파일을 활성화하려면 프로젝트의 gradle.properties에 다음 줄을 추가하세요:

# gradle.properties
kotlin.incremental.js.ir=true // 기본값은 false


저희의 테스트 프로젝트에서는 이 새로운 모드로 인해 증분 컴파일이 최대 30% 빨라졌습니다. 그러나 이 모드에서는 캐시를 만들고 채우는 필요 때문에 클린 빌드가 느려질 수 있음을 유의해 주세요.


Kotlin/JS IR 컴파일러에서 기본적으로 최상위 속성의 지연 초기화


Kotlin 1.4.30에서는 JS IR 컴파일러에서 최상위 속성의 지연 초기화 프로토타입을 제시했습니다. 모든 속성을 애플리케이션이 시작될 때 초기화할 필요를 제거하고, 지연 초기화는 시작 시간을 줄입니다. 저희의 측정에 따르면 실제 Kotlin/JS 애플리케이션에서 약 10%의 속도 향상이 나타났습니다.

이 메커니즘을 정교하게 테스트하고 검증한 결과, 우리는 IR 컴파일러에서 최상위 속성의 지연 초기화를 기본값으로 설정하고 있습니다.

// 지연 초기화
val a = run {
    val result = // intensive computations
        println(result)
    result
} // 변수를 처음 사용할 때 run이 실행됩니다.


어떤 이유로든 속성을 즉시(애플리케이션 시작 시) 초기화해야 하는 경우 @EagerInitialization 어노테이션으로 표시하세요.


IR 컴파일러를 사용한 프로젝트 모듈용 별도의 JS 파일


이전에는 JS IR 컴파일러에서 프로젝트 모듈용 별도의 .js 파일을 생성하는 기능이 있었습니다. 이것은 기본 옵션인 전체 프로젝트용 단일 .js 파일의 대안이었습니다. 이 파일은 너무 크고 사용하기 불편할 수 있었습니다. 프로젝트에서 함수를 사용하려면 해당 JS 파일 전체를 종속성으로 포함해야 했기 때문입니다. 여러 파일을 사용하면 이러한 종속성의 크기가 줄어들고 유연성이 높아집니다. 이 기능은 -Xir-per-module 컴파일러 옵션으로 사용할 수 있었습니다.

1.6.20부터 JS IR 컴파일러는 프로젝트 모듈용 별도의 .js 파일을 기본으로 생성합니다.

프로젝트를 단일 .js 파일로 컴파일하는 것은 다음 Gradle 속성으로 가능합니다:

# gradle.properties
kotlin.js.ir.output.granularity=whole-program // 기본값은 `per-module`


이전 릴리스에서 실험적으로 사용 가능한 per-module 모드 (-Xir-per-module=true 플래그로 활성화)는 각 모듈에서 main() 함수를 호출했습니다. 이는 일반적인 단일 .js 모드와 일관성이 없습니다. 1.6.20부터는 main() 함수가 두 경우 모두 메인 모듈에서만 호출됩니다. 모듈을 로드할 때 일부 코드를 실행해야 하는 경우 @EagerInitialization 어노테이션으로 표시된 최상위 속성을 사용할 수 있습니다.


Char 클래스 최적화


Char 클래스는 이제 Kotlin/JS 컴파일러에서 박싱을 도입하지 않고 처리됩니다(인라인 클래스와 유사). 이로 인해 Kotlin/JS 코드에서 Char에 대한 작업이 더 빨라집니다.

성능 향상 외에도 Char는 이제 JavaScript로 내보내지는 방식이 변경되어 Number로 변환됩니다.


내보내기 및 TypeScript 선언 생성 개선 사항


Kotlin 1.6.20은 내보내기 메커니즘(@JsExport 어노테이션)에 대한 여러 수정 및 개선 사항을 가져옵니다. 이는 TypeScript 선언(.d.ts)을 생성하는 것을 포함합니다. 인터페이스 및 열거형을 내보내는 능력을 추가했으며, 이전에 보고된 일부 경계 상황에서 내보내기 동작을 수정했습니다. 자세한 내용은 YouTrack의 내보내기 개선 사항 목록을 참조하세요.

JavaScript에서 Kotlin 코드를 사용하는 방법에 대한 자세한 내용은 Kotlin 코드를 JavaScript에서 사용하기를 참조하세요.


비동기 테스트에 대한 @AfterTest 보장


Kotlin 1.6.20은 Kotlin/JS에서 비동기 테스트에 대한 @AfterTest 함수가 올바르게 작동하도록 합니다. 테스트 함수의 반환 유형이 정적으로 Promise로 해결되면 컴파일러는 @AfterTest 함수의 실행을 해당 then() 콜백에 예약합니다.
 

보안

 
Kotlin 1.6.20에서는 코드 보안을 향상시키기 위한 몇 가지 기능을 소개합니다:
 

klibs에서 상대 경로 사용


klib 형식의 라이브러리에는 소스 파일의 직렬화된 IR 표현이 포함되며, 이는 올바른 디버그 정보를 생성하기 위한 경로를 포함합니다. Kotlin 1.6.20 이전에는 저장된 파일 경로가 절대 경로였습니다. 라이브러리 저자는 절대 경로를 공유하고 싶지 않을 수 있으므로 1.6.20 버전에는 대안 옵션이 함께 제공됩니다.

klib을 게시하고 아티팩트에서 소스 파일의 상대 경로만 사용하려면 한 개 이상의 소스 파일의 기본 경로를 사용하여 -Xklib-relative-path-base 컴파일러 옵션을 전달할 수 있습니다:

Kotlin:
 

tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinCompile::class).configureEach {
    // $base는 소스 파일의 기본 경로입니다.
    kotlinOptions.freeCompilerArgs += "-Xklib-relative-path-base=$base"
}

 

Kotlin/JS Gradle 프로젝트용 yarn.lock 파일 지속성


이 기능은 Kotlin 1.6.10으로 다시 포팅되었습니다.

Kotlin/JS Gradle 플러그인은 이제 yarn.lock 파일을 유지하고 프로젝트의 npm 종속성 버전을 잠금 처리할 수 있는 기능을 제공합니다. 이 기능은 프로젝트 구조를 기본값으로 변경하여 자동 생성된 kotlin-js-store 디렉토리를 프로젝트 루트에 추가합니다. 이 디렉토리에는 yarn.lock 파일이 포함되어 있습니다.

kotlin-js-store 디렉토리와 해당 내용을 버전 관리 시스템에 커밋하는 것을 강력하게 권장합니다. 락 파일을 버전 관리 시스템에 커밋하는 것은 모든 기계에서 개발 환경 또는 CI/CD 서비스인지에 관계없이 정확히 동일한 종속성 트리로 응용 프로그램을 빌드하도록 보장하기 때문에 권장되는 관행입니다. 락 파일은 또한 새로운 기계에서 프로젝트가 체크아웃될 때 npm 종속성이 묻히지 않도록 하므로 보안 문제입니다.

Dependabot와 같은 도구는 Kotlin/JS 프로젝트의 yarn.lock 파일을 구문 분석하고 의존하는 npm 패키지가 위협받은 경우 경고를 제공할 수 있습니다.

필요한 경우 빌드 스크립트에서 디렉토리 및 락 파일 이름을 변경할 수 있습니다:

Kotlin:
 

rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
    rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().lockFileDirectory =
        project.rootDir.resolve("my-kotlin-js-store")
    rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().lockFileName = "my-yarn.lock"
}


락 파일 이름을 변경하면 종속성 검사 도구가 파일을 더 이상 인식하지 못할 수 있습니다.


npm 종속성을 --ignore-scripts 옵션을 기본으로 사용하여 설치


이 기능은 Kotlin 1.6.10으로 다시 포팅되었습니다.

Kotlin/JS Gradle 플러그인은 이제 기본적으로 npm 종속성을 설치하는 동안 라이프사이클 스크립트 실행을 방지합니다. 이 변경 사항은 kompromissed npm 패키지에서 악성 코드를 실행하는 가능성을 줄이기 위한 것입니다.

이전 구성으로 롤백하려면 다음 라인을 build.gradle(.kts)에 명시적으로 추가하여 라이프사이클 스크립트 실행을 활성화할 수 있습니다:

Kotlin:
 

rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
    rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().ignoreScripts = false
}


Kotlin/JS Gradle 프로젝트의 npm 종속성에 대해 더 알아보세요.
 

Gradle

 
Kotlin 1.6.20에서 Kotlin Gradle 플러그인에 대한 다음 변경 사항을 가져옵니다:

  • Kotlin 컴파일러 실행 전략을 정의하는 데 사용되는 새로운 속성 kotlin.compiler.execution.strategy 및 compilerExecutionStrategy
  • kapt.use.worker.api, kotlin.experimental.coroutines 및 kotlin.coroutines 옵션의 사용 중단
  • kotlin.parallel.tasks.in.project 빌드 옵션의 제거


Kotlin 컴파일러 실행 전략을 정의하는 속성


Kotlin 1.6.20 이전에는 Kotlin 컴파일러 실행 전략을 정의하기 위해 시스템 속성 -Dkotlin.compiler.execution.strategy를 사용했습니다. 이 속성은 경우에 따라 불편할 수 있었습니다. Kotlin 1.6.20에서는 동일한 이름을 가진 Gradle 속성 kotlin.compiler.execution.strategy 및 compile 작업 속성 compilerExecutionStrategy를 도입합니다.

시스템 속성은 여전히 작동하지만 향후 릴리스에서 제거될 예정입니다.

현재 속성의 우선 순위는 다음과 같습니다:

  • 작업 속성 compilerExecutionStrategy는 시스템 속성과 Gradle 속성 kotlin.compiler.execution.strategy보다 우선합니다. Gradle 속성은 시스템 속성보다 우선합니다.
  • 이 속성에 할당할 수 있는 세 가지 컴파일러 실행 전략이 있습니다:

 


따라서 kotlin.compiler.execution.strategy 속성 (시스템 및 Gradle의 모두)에 사용할 수 있는 값은 다음과 같습니다:

  1. 데몬 (기본값)
  2. 프로세스 내
  3. 프로세스 외부

 
gradle.properties에서 Gradle 속성 kotlin.compiler.execution.strategy를 사용하세요:
 

# gradle.properties
kotlin.compiler.execution.strategy=out-of-process


compilerExecutionStrategy 작업 속성에 사용할 수 있는 값은 다음과 같습니다:

  1. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.DAEMON (기본값)
  2. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.IN_PROCESS
  3. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.OUT_OF_PROCESS

 
build.gradle.kts 빌드 스크립트에서 compilerExecutionStrategy 작업 속성을 사용하세요:
 

import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy

// ...

tasks.withType<KotlinCompile>().configureEach {
    compilerExecutionStrategy.set(KotlinCompilerExecutionStrategy.IN_PROCESS)
}


이 YouTrack 작업에서 의견을 남겨 주세요.


kapt 및 코루틴 빌드 옵션의 사용 중단


Kotlin 1.6.20에서는 다음과 같은 속성의 사용 중단 수준을 변경했습니다:

  • kapt.use.worker.api를 통해 Kotlin 데몬을 사용하여 kapt를 실행하는 기능을 사용 중단했습니다. 이제 Gradle 출력에 경고가 표시됩니다. 기본적으로 kapt는 1.3.70 릴리스 이후로 Gradle 워커를 사용하고 있으며 이 방법을 사용하는 것을 권장합니다. kapt.use.worker.api 옵션은 향후 릴리스에서 제거할 예정입니다.
  • kotlin.experimental.coroutines Gradle DSL 옵션과 gradle.properties에서 사용되는 kotlin.coroutines 속성을 사용 중단했습니다. 대신 중단 함수를 사용하거나 build.gradle(.kts) 파일에 kotlinx.coroutines 종속성을 추가하세요. 코루틴에 대한 자세한 내용은 코루틴 가이드에서 알아보세요.

 

kotlin.parallel.tasks.in.project 빌드 옵션의 제거


Kotlin 1.5.20에서 build 옵션 kotlin.parallel.tasks.in.project의 사용 중단을 발표했습니다. 이 옵션은 Kotlin 1.6.20에서 제거되었습니다.

Kotlin 데몬에서 병렬 컴파일을 사용하려면 프로젝트에 따라 더 많은 메모리가 필요할 수 있습니다. Kotlin 데몬의 힙 크기를 늘려 메모리 소비를 줄이세요.

Kotlin Gradle 플러그인에서 현재 지원되는 컴파일러 옵션에 대해 자세히 알아보세요.
 

원문

 
https://kotlinlang.org/docs/whatsnew1620.html
 

반응형

댓글