Sejauh Course ini kata crate sudah berkali-kali kita sebut tanpa dibedah maknanya, karena semua contoh kita berbentuk program yang langsung dieksekusi. Kenyataannya, kata crate punya dua wajah: binary crate yang menjadi program berdiri sendiri, dan library crate yang berisi kode untuk dipakai program lain lewat use. Cargo mengemas keduanya dalam satu wadah bernama package. Pada Chapter ini kita membedah perbedaan kedua jenis crate tersebut, mempraktikkan satu package yang memuat keduanya sekaligus, lalu membuktikan lewat artifak hasil build bahwa package seperti itu benar-benar menghasilkan crate yang terpisah.
Crate: Satuan Kompilasi Rust #
Ketika rustc bekerja, kompilator tidak memproses berkas satu per satu secara lepas — kompilator memproses satu crate sebagai satu kesatuan. Crate adalah pohon module utuh yang diawali satu berkas akar: src/main.rs atau src/lib.rs, berikut seluruh module turunannya yang sudah kita kenal pada Section Modul dan Visibilitas. Hasil kompilasi satu crate adalah satu artifak, dan jenis artifak itulah yang membedakan dua rasa crate.
Binary crate adalah crate yang memiliki fungsi main. Kompilator menerjemahkan crate jenis ini menjadi program yang dapat dieksekusi langsung dari terminal — berkas kasir-warung di Linux atau kasir-warung.exe di Windows. Program yang selama ini kita tulis semuanya adalah binary crate.
Satu crate dikompilasi dalam satu panggilan rustc: berkas akar dibaca, seluruh pohon module di bawahnya digabungkan, type checking berjalan menyeluruh, lalu keluar satu artifak. Ketika sebuah program memakai banyak crate — seperti proyek undian-acak yang akan kita bangun di Chapter Dependensi — cargo memanggil rustc berkali-kali, sekali untuk tiap crate, dengan urutan yang menghormati ketergantungan. Pemahaman ini menjelaskan mengapa galat pada satu crate cukup menghentikan seluruh proses: rustc tidak melanjutkan ke crate pemakai sebelum penyedia selesai dengan sukses.
Library crate adalah crate yang tidak memiliki fungsi main. Crate jenis ini tidak dijalankan, melainkan menyimpan fungsi, struct, dan item pub lain sebagai layanan bagi crate pemakainya. Artifaknya berupa berkas .rlib yang di-link oleh rustc ketika binary crate lain menuliskan use terhadap library tersebut. Dengan kata lain: binary crate yang dieksekusi, library crate yang diimpor.
Package: Wadah Berisi Crate #
Package adalah folder proyek yang memiliki berkas Cargo.toml — manifest yang akan kita bedah tuntas pada Chapter berikutnya. Cargo memberlakukan tiga aturan tegas tentang isi sebuah package:
- Sebuah package minimal berisi satu crate.
- Sebuah package boleh memiliki paling banyak satu library crate.
- Sebuah package boleh memiliki sebanyak apapun binary crate.
Kombinasi yang paling sering dipakai proyek nyata adalah satu library crate plus satu atau beberapa binary crate. Skenarionya nyata: warung Budi ingin fungsi hitung belanja dipakai dua program — aplikasi kasir untuk transaksi dan alat laporan untuk rekap harian. Logika hitung cukup ditulis sekali di library, lalu kedua program tinggal memanggil fungsi yang sama.
Membangun Satu Package dengan Dua Crate #
Kita wujudkan skenario warung tersebut sebagai package kasir-warung. Struktur foldernya mengikuti konvensi cargo:
kasir-warung/
├── Cargo.toml
└── src
├── main.rs
├── lib.rs
└── bin
└── laporan.rsManifest package ini masih minimal karena belum ada dependency:
[package]
name = "kasir-warung"
version = "0.1.0"
edition = "2024"
[dependencies]Seluruh logika bersama kita taruh di src/lib.rs:
pub fn hitung_total(harga: u32, jumlah: u32) -> u32 {
harga * jumlah
}
pub fn format_rupiah(nilai: u32) -> String {
format!("Rp{}", nilai)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn total_sesuai_harga_kali_jumlah() {
assert_eq!(hitung_total(5000, 3), 15000);
}
}Program kasir di src/main.rs meminjam fungsi tersebut lewat use:
use kasir_warung::{format_rupiah, hitung_total};
fn main() {
let total = hitung_total(5000, 3);
println!("Total belanja: {}", format_rupiah(total));
}Program laporan di src/bin/laporan.rs memakai fungsi yang sama untuk keperluan berbeda:
use kasir_warung::hitung_total;
fn main() {
let omzet = hitung_total(25000, 4);
println!("Omzet hari ini: Rp{}", omzet);
}Jalankan kedua program dengan opsi --bin:
cargo run --bin kasir-warung
cargo run --bin laporanOutput yang Dihasilkan:
Running `target/debug/kasir-warung`
Total belanja: Rp15000 Running `target/debug/laporan`
Omzet hari ini: Rp100000Mari kita bedah kode di atas:
- Baris 1 (
use kasir_warung::{format_rupiah, hitung_total};pada main.rs): kedua fungsi diimpor dari library crate. Perhatikan nama modulnya memakai garis bawah — cargo mengubah tanda hubung nama package (kasir-warung) menjadi underscore nama crate (kasir_warung). - Baris 1 (
pub fn hitung_total(harga: u32, jumlah: u32) -> u32pada lib.rs): keywordpubwajib karena binary crate adalah pemakai luar; tanpapub, aturan privacy dari Section Modul menyembunyikan fungsi ini dari binary crate. - Baris 2 (
harga * jumlah): logika hitung hanya hidup satu kali di library — tidak disalin ke kedua binary. - Baris 9 (
#[cfg(test)]): test modul melekat pada library crate, sehinggacargo testmenguji logika bersama satu kali untuk semua pemakainya.
Cara Cargo Menemukan Target Crate #
Cargo tidak membaca daftar crate dari manifest — cargo mengenali target lewat letak berkasnya:
src/main.rsmenjadi binary crate bernama sama dengan nama package.src/lib.rsmenjadi satu-satunya library crate, juga bernama sama dengan nama package.- Setiap berkas di
src/bin/menjadi binary crate tambahan yang bernama sesuai nama berkasnya —laporan.rsmenjadi binarylaporan.
Relasi package, kedua jenis crate, dan arah use dapat digambarkan sebagai berikut:
Diagram di atas menegaskan arah bergantungnya: kedua binary crate berdiri di sisi pemakai, library crate berdiri di sisi penyedia, dan package sekadar menjadi wadah administratif yang membungkus ketiganya.
Bukti Dua Crate dari Sisi Artifak #
Klaim “dua crate terpisah” dapat kita buktikan dari isi folder target/debug setelah cargo build:
target/debug/kasir-warung
target/debug/laporan
target/debug/libkasir_warung.rlibTiga artifak muncul dari satu package: dua program siap eksekusi dan satu berkas .rlib milik library. Berkas .rlib berisi kode terkompilasi beserta metadata tipe dari lib.rs — ketika rustc mengompilasi main.rs dan menemukan use kasir_warung::..., kompilator membaca .rlib tersebut untuk memastikan tanda tangan fungsi cocok, lalu menautkan kode mesinnya ke binary akhir. Perintah cargo test memperlihatkan pemisahan yang sama dari sisi target test, karena setiap crate diuji sebagai unit tersendiri:
Running unittests src/lib.rs (target/debug/deps/kasir_warung-586f1282c88d0e09)
running 1 test
test tests::total_sesuai_harga_kali_jumlah ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/main.rs (target/debug/deps/kasir_warung-d62c48d6acde0c16)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sTest kita hanya ditulis di lib.rs, sehingga target unittests milik library melaporkan satu test sedangkan target milik main.rs melaporkan nol test. Perbedaan laporan tersebut bukan keanehan — keduanya memang crate yang berbeda dengan berkas akar yang berbeda pula.
Ketika library Crate Hilang #
Kesalahan umum pemula: menghapus atau mengganti nama lib.rs sambil membiarkan use kasir_warung::... di main.rs. Cargo mengompilasi package tanpa library, lalu kompilator menolak import yang kini tidak beralamat:
error[E0432]: unresolved import `kasir_warung`
--> src/main.rs:1:5
|
1 | use kasir_warung::{format_rupiah, hitung_total};
| ^^^^^^^^^^^^ use of unresolved module or unlinked crate `kasir_warung`
For more information about this error, try `rustc --explain E0432`.
error: could not compile `kasir-warung` (bin "kasir-warung") due to 1 previous errorPesan E0432 menyebut dua kemungkinan: modul tidak ditemukan, atau crate tidak ter-link. Pada kasus kita, src/lib.rs yang hilang membuat library crate tidak pernah dikompilasi, sehingga nama kasir_warung tidak pernah ada. Kembalikan berkas lib.rs ke tempatnya, dan error lenyap.
Ringkasan #
Crate adalah satuan kompilasi: binary crate memiliki main dan menghasilkan program yang dieksekusi, sedangkan library crate hanya menawarkan item pub yang diimpor lewat use dan menghasilkan berkas .rlib. Package menjadi wadahnya — satu library crate paling banyak, binary crate boleh banyak, dan semuanya ditemukan cargo lewat konvensi src/main.rs, src/lib.rs, serta src/bin/. Kedua jenis crate berbagi satu manifest, dan manifest itulah yang kita bedah baris demi baris pada Chapter berikutnya.