Compose Compiler는 일반적인 어노테이션 프로세서와는 다르게 작동합니다. 새로운 파일을 생성하는 대신, 기존 코드를 직접 변형해서 Compose Runtime이 필요로 하는 형태로 바꿔버립니다. 이게 어떻게 가능한 걸까요?
이 궁금증을 해결하기 위해 컴파일러가 어떻게 작동하는지, 그리고 Kotlin에서 어노테이션을 처리하는 방법들이 어떻게 발전해왔는지 알아봤습니다. Java 어노테이션 프로세서부터 시작해서 KAPT, KSP, 그리고 Kotlin Compiler Plugin까지 각각의 특징과 차이점을 정리해보려고 합니다.
컴파일러는 특정 프로그래밍 언어로 작성된 소스 코드를 다른 형태의 코드로 변환하는 도구입니다. 일반적으로 프론트엔드와 백엔드 두 단계로 구성됩니다.
프론트엔드는 소스 코드를 분석하여 중간 표현(Intermediate Representation, IR)으로 변환하는 역할을 담당합니다. 주요 과정은 다음과 같습니다:
백엔드는 프론트엔드에서 생성된 중간 표현을 특정 하드웨어나 가상 머신이 실행할 수 있는 기계어 코드 또는 바이트코드로 변환합니다. Java의 경우 JVM이 실행할 수 있는 바이트코드(.class 파일)가 최종 결과물입니다.
순수 Java 프로젝트에서 어노테이션 프로세서는 의미 분석 단계 이후에 실행됩니다. 어노테이션을 분석하여 새로운 Java 소스 코드를 생성하면, 컴파일러는 생성된 파일을 포함하여 새로운 컴파일 라운드를 시작합니다.
KAPT는 Kotlin에서 Java 어노테이션 프로세서를 사용하기 위한 도구입니다. Kotlin 코드를 Java 어노테이션 프로세서가 이해할 수 있도록 Java Stub 파일을 생성하는 전처리 과정이 추가됩니다.
+----------------+
| Kotlin Source |
| Code (.kt) |
+----------------+
|
v
+----------------+
| Kotlin KAPT | <--- KAPT 플러그인 개입
| Compiler | (1단계: Stub 파일 생성)
| (Stub Gen) |
+----------------+
|
v
+----------------+
| Java Stubs |
| Files (.java)|
+----------------+
|
v
+----------------+
| Java Annotation | <--- Java Annotation Processor 실행
| Processor | (2단계: Stub 파일 분석 및 코드 생성)
| (Dagger, Room etc.)|
+----------------+
|
v
+------------------+ +----------------+
| Generated Java | | Original Kotlin|
| Source Code (.java)| | Source Code (.kt)|
+------------------+ +----------------+
| |
v v
+--------------------------------+
| Kotlin Compiler | <--- (3단계: 최종 컴파일)
| (Frontend + Backend) |
+--------------------------------+
|
v
+----------------+
| JVM Bytecode |
| (.class) |
+----------------+
KSP는 Kotlin Compiler 플러그인으로, JVM에 종속되지 않아 Java 어노테이션 프로세서를 사용하지 않고 Kotlin 컴파일러의 심볼 처리 과정에 직접 개입합니다. Java 스텁 생성 단계를 건너뛸 수 있어 KAPT보다 약 2배 빠른 성능을 제공합니다.
+----------------+
| Kotlin Source |
| Code (.kt) |
+----------------+
|
v
+-----------------------------------+
| Kotlin Compiler Frontend |
| (Parsing, AST, Semantic Analysis)|
+-----------------------------------+
| (Symbol Information available)
v
+-----------------------------------+
| KSP (Kotlin Symbol Processing) | <--- KSP 플러그인 개입
| (Directly processes Kotlin/Java | (심볼 정보 기반 코드 생성)
| Symbols & Annotations) |
+-----------------------------------+
|
v
+------------------+ +----------------+
| Generated Kotlin/Java| | Original Kotlin/Java|
| Source Code (.kt/.java)| | Source Code (.kt/.java)|
+------------------+ +----------------+
| |
v v
+-----------------------------------+
| Kotlin Compiler Backend |
| (IR Generation, Optimization, |
| Bytecode Generation) |
+-----------------------------------+
|
v
+----------------+
| JVM Bytecode |
| (.class) |
+----------------+
Kotlin Compiler Plugin은 컴파일 과정에서 소스 코드를 직접 분석하고 수정할 수 있는 강력한 도구입니다. 대표적인 예로 Compose Compiler가 있습니다.
Compose Compiler는 IR 단계에서 코드를 변형하여 Composable 함수를 Compose Runtime이 요구하는 형태로 변환합니다. 이는 기존 어노테이션 프로세서와 중요한 차이점을 보입니다:
이러한 특성으로 인해 Compose는 선언적 UI 프로그래밍 모델을 효율적으로 구현할 수 있습니다.
https://junstar92.tistory.com/499
https://kotlinlang.org/docs/ksp-why-ksp.html