Topik ini membahas crate sebagai unit kompilasi Rust, cara berbagi kode antar beberapa crate lewat workspace, serta struktur yang diperlukan untuk mempublikasikan paket ke crates.io. Setelah membacanya, pembaca dapat membagi proyek besar menjadi beberapa paket yang saling terhubung, menjaga metadata tetap seragam di seluruh anggota workspace, dan menyiapkan manifest yang siap diunggah.
Crate sebagai unit kompilasi#
Crate adalah unit terkecil yang dikompilasi compiler: satu kumpulan kode yang dijadikan sebuah biner atau sebuah pustaka. Crate biner menghasilkan program yang dapat dijalankan, sedangkan crate pustaka menghasilkan artefak yang dapat ditautkan oleh crate lain. Paket (package) berbeda dari crate: paket adalah kemasan berkas yang dikelola Cargo lewat satu Cargo.toml. Satu paket dapat memuat crate pustaka serta satu atau beberapa crate biner sekaligus, sebagaimana src/lib.rs dan src/main.rs pada satu proyek.
Pemisahan kode ke beberapa crate dilakukan ketika batas modul tidak lagi memadai. Modul berada di dalam satu crate sehingga seluruh isinya dikompilasi bersama, sedangkan crate memisahkan batas kompilasi sekaligus batas visibilitas: hanya item pub yang dapat dilintasi antar crate. Registri crates.io menampung crate pustaka publik, sehingga proyek lain cukup menuliskan nama dan versi crate tersebut pada bagian [dependencies] tanpa menyalin kode sumbernya.
Workspace multi-crate#
Workspace menyatukan beberapa paket yang berkerabat ke dalam satu area kerja berbagi. Berkas Cargo.toml di akar berfungsi sebagai manifest maya (virtual manifest) karena tidak memuat seksi [package], melainkan hanya daftar anggota pada members. Seluruh anggota juga menulis hasil pembangunan ke satu direktori target/ bersama, sehingga pembangunan ulang tidak mengulangi kerja antar anggota. Workspace berikut memuat dua anggota: crates/inti sebagai pustaka penyimpan fungsi inti dan crates/cli sebagai program utama yang memakai pustaka itu.
[workspace]
resolver = "2"
members = ["crates/inti", "crates/cli"]
[workspace.package]
version = "0.1.0"
edition = "2021"[package]
name = "catatan-inti"
version.workspace = true
edition.workspace = true// tidak-dijalankan sendirian oleh rustc karena berkas ini bagian pustaka tanpa fungsi main.
//! Inti catatan harian laboratorium.
/// Satu catatan suhu dengan nama sensornya.
pub struct Catatan {
pub sensor: String,
pub suhu: f64,
}
/// Membuat catatan baru dari nama sensor dan suhunya.
pub fn baru(sensor: &str, suhu: f64) -> Catatan {
Catatan {
sensor: sensor.to_string(),
suhu,
}
}
/// Menformat catatan menjadi satu baris teks.
pub fn format(catatan: &Catatan) -> String {
format!("{}: {:.1} C", catatan.sensor, catatan.suhu)
}[package]
name = "catatan-cli"
version.workspace = true
edition.workspace = true
[dependencies]
catatan-inti = { path = "../inti" }// tidak-dijalankan sendirian oleh rustc karena memakai crate catatan_inti lewat dependensi path.
fn main() {
let pagi = catatan_inti::baru("ruang-1", 24.5);
let siang = catatan_inti::baru("ruang-2", 26.3);
println!("{}", catatan_inti::format(&pagi));
println!("{}", catatan_inti::format(&siang));
}Seksi [workspace.package] menampung metadata yang diwarisi anggota, sehingga version.workspace = true mengambil versi dari akar dan cukup diubah di satu tempat ketika seluruh anggota naik versi bersama. Dependensi antar anggota memakai jalur relatif path = "../inti", dan nama paket bertanda hubung kembali menjadi garis bawah pada kode, yakni catatan_inti. Baris resolver = "2" memilih resolusi fitur versi dua yang menjadi perilaku baku pada edisi 2021 dan mencegah peringatan pada manifest maya.
# siapkan area kerja workspace yang bersih di luar pohon konten
rm -rf /tmp/ws-catatan
mkdir -p /tmp/ws-catatan/crates/inti/src
mkdir -p /tmp/ws-catatan/crates/cli/src
# salin berkas setiap anggota dari bundle ke posisinya
cp Cargo.toml /tmp/ws-catatan/Cargo.toml
cp crates/inti/Cargo.toml /tmp/ws-catatan/crates/inti/Cargo.toml
cp crates/inti/src/lib.rs /tmp/ws-catatan/crates/inti/src/lib.rs
cp crates/cli/Cargo.toml /tmp/ws-catatan/crates/cli/Cargo.toml
cp crates/cli/src/main.rs /tmp/ws-catatan/crates/cli/src/main.rs
# bangun seluruh workspace lalu jalankan anggota cli
cargo run --manifest-path /tmp/ws-catatan/Cargo.toml -p catatan-cli -qruang-1: 24.5 C
ruang-2: 26.3 CDiagram berikut memetakan hubungan seluruh anggota: manifest maya di akar mengatur dua anggota di bawah crates/, keduanya menulis hasil pembangunan ke satu target/, dan cli bergantung pada inti lewat jalur relatif. Opsi -p catatan-cli pada perintah cargo run memilih anggota yang dijalankan karena workspace tidak memiliki satu program utama.
Pembagian seperti ini bermanfaat ketika satu karya memuat beberapa program yang berbagi fungsi inti. Pustaka inti dapat diberi pengujian sendiri tanpa menyentuh program, versinya dapat naik terpisah, dan setiap anggota tetap dapat dipublikasikan sebagai paket tersendiri. Sebaliknya, workspace tidak menambah atau mengurangi aturan bahasa: pembagian murni perkara organisasi berkas dan pembangunan, sehingga kode yang sama dapat pula ditata sebagai satu paket besar tanpa perombakan.
Berbagi dependensi lintas anggota#
Selain metadata, workspace dapat menampung daftar dependensi bersama pada seksi [workspace.dependencies]. Setiap anggota kemudian mengambil dependensi itu dengan workspace = true sehingga seluruh anggota memakai versi yang sama dan Cargo hanya mengompilasinya sekali. Bentuk berikut adalah pola baku untuk pustaka yang dipakai lintas anggota. Bagian dependensi pada manifest anggota tetap menuliskan nama yang sama agar pewarisan dari daftar di akar berlaku.
[workspace.dependencies]
serde = "1"
# pada Cargo.toml anggota:
[dependencies]
serde = { workspace = true }Tanpa seksi tersebut, dua anggota yang sama-sama menulis serde = "1" tetap dapat berdampingan. Resolusi dependensi menyatukan rentang versi yang cocok, tetapi apabila rentang yang ditulis berbeda, kedua anggota tidak dijamin memakai versi yang identik. Pemusatan daftar juga membuat penambahan dependensi baru terlihat dari satu tempat. Untuk dependensi lokal, jalur path tetap ditulis pada masing-masing anggota, dan Cargo memperlakukan dependensi path dalam satu workspace sebagai satu paket yang sama, bukan salinan terpisah.
Publikasi ke crates.io#
Paket yang akan dibagikan kepada publik diunggah ke crates.io melalui perintah cargo publish. Manifest perlu dilengkapi metadata yang ditampilkan pada halaman paket, yaitu deskripsi singkat, kategori, dan lisensi. Nama paket harus belum dipakai pengguna lain di registri. Nomor versi mengikuti penomoran semantik (semantic versioning, semver): perubahan yang membatalkan kompatibilitas ditandai dengan menaikkan angka pertama, yang disebut versi mayor.
[package]
name = "catatan-inti"
version = "0.1.0"
edition = "2021"
description = "Catatan harian laboratorium dengan format satu baris"
license = "MIT OR Apache-2.0"
[dependencies]Perintah publikasi memerlukan akun crates.io beserta token API, sehingga tidak dapat dijalankan pada lingkungan ini dan hanya ditampilkan sebagai referensi. Urutan penerbitan yang lazim dimulai dari pemeriksaan kemasan, lalu login sekali, lalu unggah.
# tidak-dijalankan
# periksa isi paket tanpa mengunggahnya
cargo publish --dry-run
# simpan token API dari crates.io (sekali saja per mesin)
cargo login
# unggah versi ini ke registri
cargo publishUnggahan bersifat permanen: versi yang telah diterima registri tidak dapat ditimpa atau dihapus, dan penarikan lewat cargo yank hanya menyembunyikan versi dari dependensi baru tanpa menghapusnya dari pengguna yang sudah memakainya. Karena itu jalankan pengujian lengkap sebelum mengunggah, dan naikkan angka versi untuk setiap perubahan yang dipublikasikan.
Kesalahan umum#
Menjalankan program tanpa memilih anggota. Perintah cargo run pada akar workspace yang memiliki beberapa biner berhenti dengan error karena Cargo tidak dapat menentukan program yang dimaksud. Tambahkan opsi -p nama-paket, atau jalankan perintah dari direktori anggota yang dituju.
Memberi nama sama pada dua anggota. Workspace menolak dua paket dengan nama identik karena keduanya akan menghasilkan nama crate yang sama saat dikompilasi. Beri nama yang berbeda sejak awal, misalnya akhiran -cli untuk program dan -inti untuk pustaka inti.
Menganggap metadata workspace diwarisi otomatis. Anggota yang tidak menulis version.workspace = true tetap memakai versi pada manifestnya sendiri, sehingga versi antar anggota dapat berbeda diam-diam. Tuliskan pewarisan secara eksplisit pada setiap anggota yang ingin mengikuti akar.
Ringkasan#
- Crate adalah unit kompilasi berupa biner atau pustaka, sedangkan paket adalah kemasan yang dikelola satu
Cargo.toml. - Workspace menyatukan beberapa paket dengan manifest maya, satu
target/bersama, dan dependensi antar anggota lewat jalur relatif. - Seksi
[workspace.package]dan[workspace.dependencies]memusatkan metadata dan versi dependensi yang diwarisi anggota secara eksplisit. - Publikasi ke crates.io memerlukan metadata lengkap, nama yang belum dipakai, dan bersifat permanen untuk setiap versi.
Referensi#
- Cargo Workspaces — The Rust Book — Pembuatan workspace beserta pembagian anggotanya.
- Workspaces — The Cargo Book — Rujukan lengkap manifest maya dan pewarisan metadata.
- Publishing a Crate to Crates.io — The Rust Book — Langkah publikasi paket beserta metadata yang diperlukan.
- cargo publish — The Cargo Book — Rincian opsi perintah unggah dan pemeriksaan sebelum unggah.