Biner yang sudah ramping dari chapter sebelumnya tetap terikat pada sistem tempat biner itu dibangun: biner Linux x86_64 tidak akan berjalan di Windows, dan biner yang menaut glibc dari mesin baru bisa menolak dijalankan di distro lama. Kebutuhan membangun di satu tempat untuk dijalankan di tempat lain inilah yang dijawab cross compilation — mengompilasi biner untuk platform lain tanpa berpindah mesin. Rust menjadikan aktivitas ini terasa dekat karena pustaka standarnya dikompilasi ulang untuk setiap platform resmi, dan pengelolaannya ditangani rustup lewat konsep target. Pada chapter ini kita akan membongkar penamaan target triple, memasang target x86_64-unknown-linux-musl, membangun biner static linking, dan jujur menghadapi momen ketika proses build berhenti di tahap linking karena toolchain lintas arsitektur belum tersedia.

Target Triple: Alamat Platform #

Setiap platform yang didukung Rust punya nama baku yang disebut target triple dengan format arsitektur-vendor-sistem-operasi-lingkungan. Nama target yang kita pakai sepanjang course ini adalah x86_64-unknown-linux-gnu, dan setiap potongannya bermakna: x86_64 adalah arsitektur prosesor, unknown adalah vendor yang tidak relevan untuk Linux, linux adalah sistem operasinya, dan gnu adalah C library yang dipakai saat menaut biner — glibc. Tiga contoh lain memperlihatkan keragamannya:

Target tripleArti singkat
x86_64-pc-windows-msvcWindows 64-bit dengan toolchain Microsoft
aarch64-apple-darwinMac berprosesor Apple Silicon
x86_64-unknown-linux-muslLinux 64-bit yang menaut musl libc

Perbedaan gnu dan musl pada dua varian Linux adalah kunci chapter ini. Biner gnu melakukan dynamic linking terhadap glibc milik mesin target: saat dijalankan, loader dinamis membaca interpreter /lib64/ld-linux-x86-64.so.2 dan mencari libc.so.6 di sistem. Biner musl bisa menaut seluruh pustaka ke dalam dirinya sendiri (static linking) sehingga tidak menagih apa pun dari sistem target — file biner tunggal yang berjalan di hampir semua Linux x86_64 modern.

Memasang Target Baru dengan rustup #

Toolchain Rust yang terpasang di komputer kita sebenarnya hanya membawa pustaka standar untuk target host, yaitu mesin tempat compiler berjalan. Daftar seluruh target yang didukung bisa kita lihat kapan saja:

bash
rustup target list | wc -l
rustup target list | grep -E "^x86_64-unknown-linux|^aarch64-unknown-linux"

Output yang Dihasilkan:

text
118
aarch64-unknown-linux-gnu
aarch64-unknown-linux-musl
aarch64-unknown-linux-ohos
x86_64-unknown-linux-gnu (installed)
x86_64-unknown-linux-gnuasan
x86_64-unknown-linux-gnumsan

Ada 118 target terdaftar saat chapter ini ditulis, dan tanda (installed) menunjukkan target yang pustaka standarnya sudah ada di mesin kita. Untuk menambah target baru, kita cukup meminta rustup mengunduh pustaka standarnya:

bash
rustup target add x86_64-unknown-linux-musl

Output yang Dihasilkan:

text
info: downloading component rust-std

Perintah ini mengunduh komponen rust-std khusus musl — kode pustaka standar yang sudah dikompilasi untuk target tersebut — tanpa mengganti compiler atau Cargo. Setelah selesai, rustup target list --installed menampilkan dua target: x86_64-unknown-linux-gnu dan x86_64-unknown-linux-musl. Ukuran unduhannya beberapa puluh megabyte dan memakan waktu tergantung koneksi; bila perintah dijalankan ulang, rustup hanya menjawab bahwa komponen sudah mutakhir.

Membangun untuk Musl dan Menguji Hasilnya #

Membangun untuk target lain semudah menambahkan flag --target:

bash
cargo build --release --target x86_64-unknown-linux-musl

Cargo menempatkan hasilnya di folder tersendiri agar tidak menimpa biner host: target/x86_64-unknown-linux-musl/release/penghitung-prima. Sekarang kita periksa kedua biner dan daftar dependensi dinamisnya:

bash
file target/release/penghitung-prima target/x86_64-unknown-linux-musl/release/penghitung-prima
ldd target/x86_64-unknown-linux-musl/release/penghitung-prima
ldd target/release/penghitung-prima

Output yang Dihasilkan:

text
target/release/penghitung-prima:                           ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=8a5dc4e28e8dc224e986e2c03115b7e1f49fb0a2, not stripped
target/x86_64-unknown-linux-musl/release/penghitung-prima: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, BuildID[sha1]=998bd7471b6184104a547d734d871fed3c221b35, not stripped
        statically linked
        linux-vdso.so.1 (0x00007fffeb1db000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f20eb60b000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f20eb417000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f20eb6a0000)

Perintah file membedakan keduanya dengan gamblang: biner gnu dynamically linked dengan interpreter loader, biner musl static-pie linked tanpa interpreter. Perintah ldd mempertegasnya — biner musl dinyatakan statically linked dan tidak punya daftar pustaka, sedangkan biner gnu menagih libc.so.6 dan libgcc_s.so.1 dari sistem. Alamat memori pada keluaran ldd berbeda pada setiap eksekusi karena ASLR. Biner musl tersebut bisa langsung dijalankan di mesin kita:

bash
./target/x86_64-unknown-linux-musl/release/penghitung-prima
ls -lh target/release/penghitung-prima target/x86_64-unknown-linux-musl/release/penghitung-prima

Output yang Dihasilkan:

text
Jumlah prima sampai 1000000: 78498
Waktu eksekusi: 116.732968ms
444K target/release/penghitung-prima
547K target/x86_64-unknown-linux-musl/release/penghitung-prima

Dua fakta menarik dari pengukuran ini. Pertama, biner musl justru lebih besar — 547 KB berbanding 444 KB — karena seluruh implementasi libc ikut tertanam di dalam biner; ukuran yang kita bayar sebagai tiket portabilitas. Kedua, waktu eksekusinya di mesin kami praktis sama dengan versi gnu pada beban kerja integer murni ini. Kesetaraan itu tidak berlaku untuk semua beban: program yang banyak mengalokasikan memori atau memproses teks sering terasa lebih lambat di musl karena allocator-nya lebih sederhana, jadi selalu ukur program Anda sendiri sebelum berkomitmen ke satu target.

Mengapa build musl bisa selesai tanpa toolchain C? Target ini dikirim rustc dalam mode self-contained: objek CRT dan pustaka C dari musl dibundel bersama komponen rust-std, dan penautan dikerjakan rust-lld bawaan. Untuk program Rust murni tanpa build script C, tidak ada yang perlu dipasang lagi.

Saat Linker Menjadi Penghalang #

Kisah kita berubah bila target yang diinginkan menuntut linker arsitektur lain. Mari kita pasang target aarch64-unknown-linux-gnu — pustaka standarnya terpasang tanpa masalah — lalu coba membangun:

bash
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnu

Output yang Dihasilkan:

text
info: downloading component rust-std
   Compiling penghitung-prima v0.1.0 (penghitung-prima)
error: linking with `cc` failed: exit status: 1
  |
  = note: some arguments are omitted. use `--verbose` to show all linker arguments
  = note: rust-lld: error: --fix-cortex-a53-843419 is only supported on AArch64
          collect2: error: ld returned 1 exit status

error: could not compile `penghitung-prima` (bin "penghitung-prima") due to 1 previous error

Kompilasi kode Rust-nya sukses — pesan galat muncul justru di tahap penautan. Mesin kita tidak punya linker yang sanggup menghasilkan biner AArch64, sehingga Cargo memaksa cc milik host mengerjakan pekerjaan lintas arsitektur dan penaut menolak. Inilah batas yang perlu dipahami: rustup target add hanya menyediakan pustaka standar, bukan toolchain C lintas arsitektur.

Ada dua jalan keluarnya. Jalan pertama adalah memasang cross toolchain sistem, misalnya gcc-aarch64-linux-gnu pada distro Debian/Ubuntu, lalu memberi tahu Cargo pemakainya lewat variabel lingkungan CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc. Jalan kedua adalah perkakas komunitas bernama cross, yang membungkus seluruh toolchain lintas arsitektur ke dalam image Docker sehingga satu perintah cross build --target aarch64-unknown-linux-gnu mengurus semuanya. Perlu kita akui jujur bahwa perkakas berbasis Docker tersebut tidak bisa kita uji pada lingkungan penulisan chapter ini karena Docker tidak terpasang di mesin ini; dokumentasinya dapat diikuti di repositori resmi cross-rs/cross.

Ringkasan #

Cross compilation di Rust berdiri di atas tiga tiang: target triple sebagai alamat platform, rustup target add sebagai pengunduh pustaka standar per target, dan flag cargo build --target sebagai pemicunya. Kita berhasil membangun biner static-pie musl yang berjalan tanpa menagih pustaka sistem apa pun, dengan harga ukuran 547 KB dan kecepatan yang perlu diukur ulang untuk beban kerja non-integer. Percobaan AArch64 memperlihatkan batasnya secara jujur: tanpa linker lintas arsitektur, proses berhenti di tahap linking hingga kita memasang cross toolchain atau beralih ke perkakas cross. Biner portabel di tangan, kini saatnya mengemasnya menjadi image yang bisa dijalankan di mana saja — lanjut ke chapter Docker untuk Aplikasi Rust.