시작하기
크레이트 더하기, 그리고 이 저장소 빌드하기
크레이트를 쓰는 데는 Cargo.toml 한 줄이면 됩니다. 필요한 렌더러는 빌드가 내려받기
때문입니다. compose-rust 자체를 고치는 길은 아래에 이어지는 더 긴 길입니다.
0.0.1에는 경계, 프로토콜, 스키마, Runtime 트레이트, 렌더러 다운로드가 있습니다.
작성 API는 아직 없으므로 부를 launch(app) 도, 쓸 화면도 없습니다. 작성 API는
2026-10-20의 1.0.0에 들어옵니다(#23, #64).
그때까지 이 크레이트는 Runtime 을 구현해서 트리를 만드는 층을 위한 것입니다.
프로젝트에 더하기
렌더러는 crates.io에 올리기에는 너무 크므로, 릴리스마다 체크섬이 붙은 아티팩트로 실립니다. 받아 오는 일은 빌드 스크립트가 합니다.
cargo add compose-rust@0.0.1
[dependencies]
compose-rust = "0.0.1"
cargo build 가 대상에 필요한 렌더러를 알아냅니다. 크레이트의 정확한 버전에 맞는
릴리스 아티팩트를 내려받아 함께 게시된 .sha256 으로 확인하고, target/
바깥의 캐시에 풀어 링크합니다. 설정할 환경 변수도, 실행할 스크립트도 없습니다. 캐시는 버전과
대상으로 구분되므로 cargo clean 뒤에도 남고 프로젝트끼리 공유됩니다.
| 변수 | 효과 |
|---|---|
COMPOSE_RUST_RENDERER_DIR | 이 디렉터리의 렌더러를 씁니다. 가장 먼저 확인하고, 설정되어 있으면 아무것도 내려받지 않습니다. 직접 빌드한 렌더러, 벤더링한 사본, 오프라인 빌드가 모두 이것으로 됩니다. |
COMPOSE_RUST_CACHE_DIR | 캐시 위치를 $HOME/.cache/compose-rust(Windows는 %LOCALAPPDATA%\compose-rust)에서 옮깁니다. |
네트워크 없이 빌드하면 어떤 파일을 어디에 둘지 알려 줍니다. 거기에 두기만 하면 됩니다.
default-features = false 로 빌드하면 렌더러 없이 빌드되며, 헤드리스나 문서용
빌드에 씁니다. 그렇게 빌드한 바이너리는 무엇이 빠졌는지 알리고 0이 아닌 값으로 끝납니다. 창
없이 0 을 돌려주지 않는 것은, 아무것도 그리지 않은 프로그램과 일을 마친
프로그램을 구별할 수 있어야 하기 때문입니다. mock-renderer 기능은 일부러 렌더러
없이 경계를 구동하며, 테스트와 스스로 그리는 무언가에 Host를 넣을 때 씁니다.
지금 이 위에 만들 수 있는 것
0.0.1의 공개 표면은 모든 작성 층이 함께 쓰는 부분입니다. 층은 Runtime 을
구현합니다. rebuild 에서 트리의 레코드를 Batch 에 쓰고,
render 에서 바뀐 것을 쓰고, handle_event 에서 핸들러를 실행해
경계가 돌려줄 값을 반환합니다. 그다음 launch_runtime 이나
LaunchBuilder 로 자신을 등록합니다. 나머지, 곧 진입점, 배치, 테마, 에셋, 메시지,
프레임 요청은 Host 의 것이고, 무엇이 트리를 만들든 똑같이 동작합니다.
디자인 시스템의 Theme, DesignSystem,
Palette 값은 지금 컴파일됩니다. 전체 API 레퍼런스는
docs.rs에 있습니다.
이 저장소에서 작업하기
아래는 compose-rust 자체를 고칠 때의 이야기이고, 렌더러 툴체인도 필요합니다. 설정 점검부터 합니다. 빌드에 필요한 도구를 모두 확인하고, 빠진 것을 말하고, 고치는 명령을 출력합니다.
./scripts/setup-check.sh # every tool the build needs, with the fix for anything missing
./scripts/check.sh # fmt, clippy, tests, quick benchmarks, Kotlin build and tests
워크스페이스는 Rust 1.85+(edition 2024)를 대상으로 하며, rustfmt
와 clippy 가 필요합니다. Kotlin은 따로 설치할 것이 없습니다.
renderer/kotlin(Windows는 kotlin.bat)이 처음 쓸 때 고정된 툴체인을
내려받습니다. ./scripts/check.sh --no-kotlin 은 Kotlin 검사를 건너뛰고,
--full 은 벤치마크를 전체 표본으로 돌립니다.
렌더러 빌드
렌더러는
thisisthepy/compose-multiplatform-core-extended
의 고정된 커밋을 씁니다. 게시된 빌드에 없는 것, 곧 Linux 타깃, 텍스트 선택 메뉴, 복사 키를
더한 Compose 포크입니다. 포크를 한 번 빌드한 다음 렌더러를 빌드합니다.
# macOS
./renderer/scripts/build-compose.sh
cd renderer && ./desktop/scripts/build-macos.sh --release # build/macos/<target>/
# Linux
./renderer/scripts/build-compose.sh --target linuxX64
cd renderer && ./desktop/scripts/build-linux.sh --release # build/linux/<target>/
각각 Compose, Skia, 인터프리터가 들어간 정적 라이브러리 하나,
libcompose_rust_renderer.a 를 만듭니다. DXC_MACOS_NATIVE_LIB 나
DXC_LINUX_NATIVE_LIB 가 그 디렉터리를 가리키면 Rust 빌드가 이것을 링크합니다.
둘 다 없으면 체크아웃은 renderer/build/native-image/dist/lib 의 GraalVM
네이티브 이미지를 링크하며, 0.0.1이 배포하는 것이 이것입니다.
Windows는 아직 renderer/desktop/scripts/build-native-windows.ps1 로 GraalVM
네이티브 이미지를 빌드합니다. macOS에서 네이티브 이미지를 빌드하려면 Liberica NIK 25 Full이
필요합니다. 업스트림 GraalVM은 Darwin에서 AWT를 빼기 때문입니다
(oracle/graal#13272).
./scripts/install-nik.sh 가 설치합니다. 잘못된 JDK가 어떻게 드러나는지는
문제 해결에 있습니다.
Compose와 Skia를 미리 컴파일하므로 첫 빌드는 느립니다. Kotlin 쪽이 바뀔 때만 다시 하면 되고, 평소의 Rust 작업은 만들어 둔 라이브러리를 그대로 씁니다.
라이브러리 스모크 테스트
Rust를 끌어들이기 전에, 네이티브 이미지 라이브러리 혼자 창을 열 수 있는지 확인합니다. 스모크
테스트는 작은 C 호스트를 라이브러리에 링크해 compose_rust_renderer_run 을
부릅니다.
./renderer/desktop/scripts/build-native.sh
./renderer/desktop/scripts/smoke-test.sh
창이 떠야 합니다. 창을 닫으면 run 이 0 을 돌려주고 프로세스가 정상
종료합니다.
JVM 개발 셸
렌더러 자체를 고칠 때는 개발 셸이 가장 빠른 루프이며, 핫 리로드와 @Preview 가
됩니다. JVM은 여기서만 허용되고, 배포물에는 들어가지 않습니다.
cd renderer && ./kotlin run -m desktop
샘플
samples/ 에는 계산기, 메모장, 할 일 목록, 채팅 클라이언트처럼 실제
애플리케이션을 본뜬 샘플 12개가 있습니다. 작성 API로 다시 쓰는 중이라 지금은 빌드되지 않습니다
계획(#85). 다시 쓴 것이 공개 샘플이 됩니다(#2).
생성 코드 검사
테스트 하나가 체크인된 Kotlin 프로토콜 파일과 Rust 스키마가 생성하는 내용을 비교합니다.
스키마를 바꾸고 다시 생성하지 않으면 이 테스트가 실패합니다. 의도한 경보입니다. 스키마가
유일한 원천이고, 갱신되지 않은 Kotlin 쪽은 런타임에 엇나가기보다 빌드에서 실패해야 합니다.
codegen 바이너리로 다시 생성합니다.
cargo run -p compose-rust --bin codegen