Android 개발/Jetpack Compose

1.9.24 vs 1.9.25, 숫자 하나로 빌드 터지던 Compose 컴파일러 버전 청소법

stackD 2026. 10. 6. 18:00
반응형

얼마 전에 코틀린(Kotlin) 패치만 슬쩍 올렸다가 'requires Kotlin version 1.9.25 but you appear to be using 1.9.24' 빨간 줄에 빌드가 통째로 막혔습니다. 숫자 딱 한 자리 차이였어요.

 

패치 버전 하나 어긋났다고 컴파일이 멈춰버리니까 진짜 황당하더라고요. 근데 이게 코틀린 2.0으로 넘어오면서 구조 자체가 바뀌었습니다. 지금은 코틀린 버전 한 줄만 갱신하면 Compose 컴파일러가 알아서 따라와요. 왜 그런지, 기존 설정을 어떻게 걷어내는지 순서대로 풀어볼게요.

 

Compose 컴파일러 버전을 Kotlin에 손으로 맞추던 시절

코틀린 1.9.x 이하에서는 이렇게 직접 못 박아줬어야 했습니다.

 

android {
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.14"
    }
}

 

여기서 1.5.14가 아무 코틀린이나 받아주는 게 아니었어요. 특정 코틀린 버전 하나랑 1:1로 묶여 있었습니다. 그러니까 코틀린을 1.9.24에서 1.9.25로 살짝 올리는 순간, 짝이 안 맞아서 빌드가 멈춰버리는 거죠.

 

왜 마이너도 아니고 패치 한 자리까지 걸렸냐면, 당시 Compose 컴파일러가 코틀린 내부의 컴파일러 구조(IR이나 내부 API)에 아주 밀착해 있었기 때문입니다. 이 부분은 패치 단위로도 자주 바뀌던 자리라, 컴파일러가 패치 번호까지 딱 맞는지 검사했던 거예요.

 

그래서 급할 때 이런 우회를 넣어본 분들도 계실 겁니다.

 

-P plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=1.9.22

 

이 인자로 버전 검사를 그냥 무시해버리는 방식인데요. 검사만 끈 거지 실제 궁합이 맞는 건 아니라서, 런타임에 엉뚱하게 크래시가 날 위험이 있었습니다. 저도 데드라인 급할 때 한 번 써봤는데, 마음이 영 불편하더라고요.

 

Kotlin 2.0부터 Compose 컴파일러가 저장소로 통합된 배경

2024년 코틀린 2.0.0부터 판이 바뀌었습니다. Compose 컴파일러가 코틀린 저장소 안으로 병합됐거든요.

 

쉽게 말하면, 이제 코틀린이랑 Compose 컴파일러가 같은 날 같은 버전으로 함께 나옵니다. 코틀린 2.0.21을 쓰면 컴파일러도 2.0.21이에요. 애초에 한 집에서 같이 나오니까 버전이 어긋날 수가 없는 구조가 된 겁니다.

 

코틀린 올릴 때마다 'Compose 컴파일러 호환 표'를 열어서 이 코틀린엔 어떤 컴파일러가 짝인지 찾아보던 습관, 이제 안 해도 돼요. 이 지점 하나만으로도 옮겨갈 이유는 충분하다고 봅니다.

 

다만 맞바꿔야 하는 부분도 있어요. 컴파일러가 코틀린과 완전히 한 몸이 됐다는 건, 최신 코틀린에 버그가 있으면 그게 곧바로 Compose 빌드 버그로 직결된다는 뜻이기도 합니다. 예전처럼 컴파일러만 따로 낮은 버전으로 고정해서 피해가는 우회는 이제 어려워졌지요.

 

org.jetbrains.kotlin.plugin.compose 플러그인으로 갈아타기

새 방식은 컴파일러를 composeOptions가 아니라 그래들(Gradle) 플러그인으로 붙입니다. 버전 카탈로그 기준으로 정리해볼게요.

 

먼저 libs.versions.toml에 플러그인을 등록합니다. 핵심은 version.ref = "kotlin"이에요.

 

[versions]
kotlin = "2.0.21"

[plugins]
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

 

여기 적은 2.0.21은 예시일 뿐이고, 실제로는 발행 시점 기준 최신 안정 버전을 확인해서 맞추시면 됩니다. (2026년 7월 현재 최신 안정 버전은 2.4.0)

 

 

이렇게 코틀린 버전을 참조하게 걸어두면, 다음부터는 kotlin = "2.0.21" 이 한 줄만 바꾸면 컴파일러가 그대로 따라옵니다. 제목 그대로 코틀린만 올리면 되는 거죠.

 

루트 build.gradle.kts에는 플러그인을 선언만 해두고,

 

plugins {
    alias(libs.plugins.compose.compiler) apply false
}

 

Compose를 쓰는 모듈마다 실제로 적용합니다.

 

plugins {
    alias(libs.plugins.compose.compiler)
}

 

플러그인 좌표는 org.jetbrains.kotlin.plugin.compose, 아티팩트는 org.jetbrains.kotlin:compose-compiler-gradle-plugin 이고 코틀린 2.0 이상 전용입니다.

 

그리고 이제부터가 청소 구간이에요. 옮기고 나서 다음 세 가지를 꼭 정리하셔야 합니다.

 

  1. composeOptions { kotlinCompilerExtensionVersion = ... } 블록 제거. 새 플러그인이 버전을 챙기니 필요 없습니다.
  2. 예전에 넣어둔 suppressKotlinVersionCompatibilityCheck 인자 삭제. 안 지우면 새 플러그인과 충돌할 수 있어요.
  3. 덤으로, composeCompiler {} 블록에서 reportsDestination이나 strong skipping, metrics 리포트를 한곳에서 관리할 수 있게 됐습니다.

 

특히 2번은 옮기면서 잊고 넘어가기 쉬운 자리라 한 번 더 훑어보시길 권합니다.

 

Compose BOM과 컴파일러 버전은 다른 얘기입니다

여기서 오해하기 쉬운 지점이 하나 있어요. 자동으로 정렬되는 건 어디까지나 "컴파일러" 뿐입니다.

 

compose-bom이나 androidx.compose.* 라이브러리는 여전히 손으로 챙기셔야 해요. UI 런타임, 머티리얼, 파운데이션 같은 라이브러리 버전은 코틀린이 데려가 주지 않습니다. "이제 다 자동"이라고 믿고 BOM을 방치하면 엉뚱한 데서 막힐 수 있어요.

 

그리고 코틀린 2.0은 K2 컴파일러가 기본입니다. 이게 또 변수인데요. KAPT나 어노테이션 프로세서, 서드파티 컴파일러 플러그인이 K2랑 궁합이 안 맞으면 빌드가 통과해도 그쪽에서 터지는 일이 생길 수 있습니다. 그래서 올린 뒤엔 로컬 빌드만 보지 마시고 CI가 초록불인지까지 확인하시는 게 안전해요.

 

롤백 기준도 미리 정해두시면 좋습니다. 2.0을 아직 지원 안 하는 라이브러리가 프로젝트에 물려 있거나 사내 툴체인이 특정 버전에 고정돼 있다면, 무리하게 넘어가지 말고 기존 kotlinCompilerExtensionVersion 방식을 유지하는 게 낫습니다. 프로덕션 코드라면 Beta나 EAP 말고 안정 버전으로만 붙이시고요. Compose Multiplatform도 원리는 똑같으니 KMP 프로젝트라면 그대로 적용하시면 됩니다.

 

이 마이그레이션의 요점은 딱 하나예요. 컴파일러는 이제 코틀린이 데려가고, 라이브러리는 여전히 내가 챙긴다는 것. 이 경계만 헷갈리지 않으면 됩니다.

 

결국 숫자 한 자리였어요. 1.9.24와 1.9.25 사이에서 빌드가 빨갛게 물들던 그 자리는, 컴파일러를 코틀린에 넘기는 순간 통째로 사라졌던 셈입니다.

 

반응형
LIST