본문으로 건너뛰기

KSP를 사용하는 이유

컴파일러 플러그인은 코드 작성 방식을 크게 향상시킬 수 있는 강력한 메타프로그래밍 도구입니다. 컴파일러 플러그인은 입력 프로그램을 분석하고 편집하기 위해 컴파일러를 라이브러리로서 직접 호출합니다. 이러한 플러그인은 다양한 용도로 출력을 생성할 수도 있습니다. 예를 들어, 상용구 코드를 생성할 수 있으며, Parcelable과 같이 특별히 표시된 프로그램 요소에 대한 전체 구현을 생성할 수도 있습니다. 플러그인은 다양한 다른 용도로 사용될 수 있으며, 언어에서 직접 제공되지 않는 기능을 구현하고 미세 조정하는 데에도 사용될 수 있습니다.

컴파일러 플러그인은 강력하지만, 이러한 강력함에는 대가가 따릅니다. 가장 간단한 플러그인을 작성하는 데에도 특정 컴파일러의 구현 세부 사항에 대한 친숙함뿐만 아니라 컴파일러 배경 지식이 필요합니다. 또 다른 실제적인 문제는 플러그인이 특정 컴파일러 버전에 밀접하게 연결되어 있는 경우가 많으므로 컴파일러의 최신 버전을 지원할 때마다 플러그인을 업데이트해야 할 수도 있다는 것입니다.

KSP는 가벼운 컴파일러 플러그인을 더 쉽게 만들 수 있도록 지원합니다.

KSP는 컴파일러 변경 사항을 숨기도록 설계되어 이를 사용하는 프로세서의 유지 관리 노력을 최소화합니다. KSP는 JVM에 연결되지 않도록 설계되어 향후 다른 플랫폼에 더 쉽게 적용할 수 있습니다. 또한 KSP는 빌드 시간을 최소화하도록 설계되었습니다. Glide와 같은 일부 프로세서의 경우 KSP는 kapt에 비해 전체 컴파일 시간을 최대 25%까지 단축합니다.

KSP 자체는 컴파일러 플러그인으로 구현됩니다. Google의 Maven 저장소에는 프로젝트를 직접 빌드하지 않고도 다운로드하여 사용할 수 있는 사전 빌드된 패키지가 있습니다.

kotlinc 컴파일러 플러그인과의 비교

kotlinc 컴파일러 플러그인은 컴파일러의 거의 모든 것에 액세스할 수 있으므로 최대한의 성능과 유연성을 제공합니다. 반면에 이러한 플러그인은 컴파일러의 모든 것에 잠재적으로 의존할 수 있으므로 컴파일러 변경에 민감하고 자주 유지 관리해야 합니다. 또한 이러한 플러그인은 kotlinc의 구현에 대한 깊은 이해가 필요하므로 학습 곡선이 가파를 수 있습니다.

KSP는 잘 정의된 API를 통해 대부분의 컴파일러 변경 사항을 숨기는 것을 목표로 하지만 컴파일러 또는 Kotlin 언어의 주요 변경 사항은 API 사용자에게 노출되어야 할 수도 있습니다.

KSP는 단순성을 위해 성능을 절충하는 API를 제공하여 일반적인 사용 사례를 충족하려고 합니다. 해당 기능은 일반적인 kotlinc 플러그인의 엄격한 하위 집합입니다. 예를 들어, kotlinc는 표현식과 문을 검사하고 코드를 수정할 수도 있지만 KSP는 불가능합니다.

kotlinc 플러그인을 작성하는 것은 매우 재미있을 수 있지만 많은 시간이 걸릴 수도 있습니다. kotlinc의 구현을 학습할 입장이 아니고 소스 코드를 수정하거나 표현식을 읽을 필요가 없는 경우 KSP가 적합할 수 있습니다.

리플렉션과의 비교

KSP의 API는 kotlin.reflect와 유사해 보입니다. 둘 사이의 주요 차이점은 KSP의 형식 참조를 명시적으로 확인해야 한다는 것입니다. 이것이 인터페이스가 공유되지 않는 이유 중 하나입니다.

kapt와의 비교

kapt는 많은 Java 어노테이션 프로세서를 Kotlin 프로그램에서 즉시 사용할 수 있도록 하는 놀라운 솔루션입니다. KSP가 kapt보다 유리한 주요 장점은 빌드 성능 향상, JVM에 연결되지 않음, 더 관용적인 Kotlin API 및 Kotlin 전용 기호를 이해하는 기능입니다.

수정되지 않은 Java 어노테이션 프로세서를 실행하기 위해 kapt는 Java 어노테이션 프로세서가 중요하게 생각하는 정보를 유지하는 Java 스텁으로 Kotlin 코드를 컴파일합니다. 이러한 스텁을 생성하기 위해 kapt는 Kotlin 프로그램의 모든 기호를 확인해야 합니다. 스텁 생성 비용은 전체 kotlinc 분석의 약 1/3과 동일한 순서의 kotlinc 코드 생성입니다. 많은 어노테이션 프로세서의 경우 이는 프로세서 자체에서 소비되는 시간보다 훨씬 깁니다. 예를 들어, Glide는 미리 정의된 어노테이션이 있는 매우 제한된 수의 클래스를 확인하고 해당 코드 생성은 상당히 빠릅니다. 거의 모든 빌드 오버헤드는 스텁 생성 단계에 있습니다. KSP로 전환하면 컴파일러에서 소비되는 시간이 즉시 25% 단축됩니다.

성능 평가를 위해 KSP에서 Glide간소화된 버전을 구현하여 Tachiyomi 프로젝트에 대한 코드를 생성하도록 했습니다. 프로젝트의 총 Kotlin 컴파일 시간이 테스트 장치에서 21.55초인 반면 kapt가 코드를 생성하는 데 8.67초가 걸렸고 KSP 구현이 코드를 생성하는 데 1.15초가 걸렸습니다.

kapt와 달리 KSP의 프로세서는 Java 관점에서 입력 프로그램을 보지 않습니다. API는 특히 최상위 함수와 같은 Kotlin 특정 기능에 대해 Kotlin에 더 자연스럽습니다. KSP는 kapt와 같이 javac에 위임하지 않기 때문에 JVM 특정 동작을 가정하지 않으며 잠재적으로 다른 플랫폼과 함께 사용할 수 있습니다.

제한 사항

KSP는 대부분의 일반적인 사용 사례에 대한 간단한 솔루션이 되려고 노력하지만 다른 플러그인 솔루션에 비해 몇 가지 절충안을 만들었습니다. 다음은 KSP의 목표가 아닙니다.

  • 소스 코드의 표현식 수준 정보 검사.
  • 소스 코드 수정.
  • Java 어노테이션 처리 API와의 100% 호환성.