- Wild adalah linker yang menargetkan proses linking yang sangat cepat dalam pengembangan berulang; incremental linking belum diimplementasikan, tetapi linking non-incremental pun sudah cepat
- Linker cepat yang sudah ada, mold, tidak melakukan incremental linking dan juga tidak berencana menambahkannya; inilah titik awal Wild, yang ditulis dalam Rust dengan tujuan menangani kompleksitas incremental linking
- Platform yang saat ini didukung adalah x86-64, ARM64, RISC-V, LoongArch64, PPC64LE di Linux; mendukung binary statis, static-PIE, binary dynamic linking, shared object, Rust proc-macro, informasi debug, dan lainnya
- Dapat digunakan sebagai drop-in replacement yang dipanggil seperti linker biasa dari GCC·Clang, dan bisa dihubungkan dengan Cargo, sistem build C/C++, serta wild-action untuk CI
- Incremental linking, linker script yang lebih kompleks, dukungan Mach-O, dan Windows masih belum diimplementasikan; untuk memastikan binary benar-benar di-link dengan Wild, perlu memeriksa string
Linker: Wild version... di binary lewat readelf atau strings
Tujuan dan posisi Wild
- Wild adalah linker yang menargetkan proses linking yang sangat cepat dalam pengembangan berulang
- Rencana jangka panjangnya adalah mengimplementasikan incremental linking, tetapi saat ini belum tersedia
- Disebutkan bahwa bahkan tanpa incremental linking pun, performa linking non-incremental sudah cepat
- mold memang sudah sangat cepat, tetapi karena tidak melakukan incremental linking dan penulisnya juga menyatakan tidak berencana menambahkannya, Wild dibuat sebagai linker terpisah
- Wild ditulis dalam Rust, dengan harapan kompleksitas incremental linking bisa ditangani menggunakan Rust
Cara instalasi
- Tarball rilis bisa diunduh dari releases page; setelah diekstrak, cukup salin binary
wild ke lokasi yang ada di PATH
- Jika memiliki
cargo-binstall, instalasi bisa dilakukan dengan perintah berikut
cargo binstall wild-linker
- Perintah instalasi Homebrew adalah sebagai berikut
brew install wild-linker/wild/wild
- Untuk membangun rilis terbaru dari crates.io, gunakan perintah berikut
cargo install --locked wild-linker
- Untuk memasang kode terbaru yang belum dirilis dari Git, gunakan perintah berikut
cargo install --locked --bin wild --git https://github.com/wild-linker/wild.git wild-linker
- Versi stabil Wild di Nixpkgs dapat digunakan melalui
pkgs.useWildLinker pkgs.stdenv
- Untuk revisi Git terbaru yang tidak stabil, lihat dokumen
nix/nix.md
Cara menggunakan sebagai linker default
- Wild dirancang sebagai drop-in replacement sehingga bisa digunakan seperti linker yang dipanggil oleh GCC atau Clang
- Pilihannya sebagai berikut
- Opsi khusus Clang
--ld-path=wild
-fuse-ld=wild pada GCC 16.1 ke atas dan Clang
- Clang memerlukan binary
ld.wild atau symbolic link-nya
-B <path> yang didukung secara umum
<path> adalah direktori yang berisi ld yang menunjuk ke wild
-
Rust dan Cargo
- Di
~/.cargo/config.toml, Clang dapat digunakan bersama --ld-path=wild
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-Clink-arg=--ld-path=wild"]
- Atau bisa juga menggunakan
-fuse-ld=wild
[target.x86_64-unknown-linux-gnu]
# linker = "clang" # Uncomment this line if your GCC is older than version 16.
rustflags = ["-Clink-arg=-fuse-ld=wild"]
-
Sistem build C/C++
- Pada autotools, CMake, meson, dan sejenisnya, biasanya cukup dengan mengatur
LDFLAGS
export LDFLAGS="${LDFLAGS} -fuse-ld=wild"
- Pada versi GCC lama, Anda bisa membuat symbolic link
ld yang menunjuk ke wild, lalu meneruskan direktori tersebut lewat -B
ln -s /usr/bin/wild /tmp/ld
export CFLAGS="${CFLAGS} -B/tmp"
export CXXFLAGS="${CXXFLAGS} -B/tmp"
export LDFLAGS="${LDFLAGS} -B/tmp"
- Karena sistem build semacam ini bisa rumit, disarankan memverifikasi dengan
readelf apakah Wild benar-benar digunakan saat linking binary
-
Konfigurasi Cargo untuk Illumos
- Di Illumos, path absolut ke Clang harus ditentukan, dan Wild juga harus diberikan sebagai path absolut
- Jika path absolut Wild tidak diberikan, proses bisa diam-diam didelegasikan ke GNU ld atau Sun ld
[target.x86_64-unknown-illumos]
# Absolute path to clang - on OmniOS this is likely something like /opt/ooce/bin/clang.
linker = "/usr/bin/clang"
rustflags = [
# Will silently delegate to GNU ld or Sun ld unless the absolute path to Wild is provided.
"-Clink-arg=-fuse-ld=/absolute/path/to/wild"
]
Status dukungan dan hal yang belum didukung
- Platform dan arsitektur yang saat ini didukung adalah sebagai berikut
-
x86-64 di Linux
-
ARM64 di Linux
-
RISC-V(riscv64gc) di Linux
- LoongArch64 di Linux
- Masih dalam tahap dukungan awal
- PPC64LE di Linux
- Masih dalam tahap dukungan awal
- Fitur yang berfungsi saat ini adalah sebagai berikut, meskipun disertai catatan bahwa bug masih mungkin ada
- Output binary static-linked non-relocatable
- Output binary static-linked position-independent, yaitu static-PIE
- Output binary dynamic linking
- Output file shared object
.so
- Rust proc-macro yang di-link dengan Wild
- Lolos pengujian pada sebagian besar crate teratas yang banyak diunduh di crates.io
- Informasi debug
- Dukungan GNU jobserver
- Dukungan linker script parsial
- Untuk detail, lihat linker script support matrix
- Linker plugin LTO
- Ada known issues
- Item besar yang belum diimplementasikan saat ini, kira-kira menurut urutan prioritas, adalah sebagai berikut
-
Incremental linking
- linker script yang lebih kompleks
- Dukungan Mach-O
- Dukungan Windows
Cara memeriksa apakah Wild digunakan
readelf dapat dipasang dari paket binutils, dan string pada section .comment bisa diperiksa dengan perintah berikut
readelf --string-dump .comment my-executable
- Jika ada baris seperti berikut, berarti binary tersebut di-link dengan Wild
Linker: Wild version 0.1.0
strings juga tersedia dari paket binutils, dan pemeriksaan bisa dilakukan dengan perintah berikut juga
strings my-executable | grep 'Linker:'
Benchmark dan target pengujian
- Tujuan Wild pada akhirnya adalah menjadi linker yang sangat cepat melalui incremental linking
- Wild juga menargetkan agar linking awal, baik dalam mode non-incremental maupun saat incremental linking diaktifkan, tetap secepat mungkin
- Semua benchmark dijalankan dengan output ke tmpfs
- Cara menjalankan benchmark dirangkum di BENCHMARKING.md
- Sistem yang menjadi target benchmark adalah sebagai berikut
- Contoh benchmark mencakup waktu linking dan penggunaan memori Chromium, waktu linking
librustc-driver, waktu linking Wild itu sendiri, dan waktu linking rust-analyzer di Raspberry Pi 5
Contoh linking kode Rust dan informasi proyek
- Berikut contoh membangun dan menguji crate dengan
cargo test menggunakan Wild
- Perintah ini telah berhasil dijalankan pada beberapa crate populer seperti
ripgrep, serde, tokio, rand, dan bitflags
- Binary
wild harus tersedia di PATH, dan karena GCC tidak mengizinkan penggunaan linker sembarang, instalasi Clang diperlukan
RUSTFLAGS="-Clinker=clang -Clink-args=--ld-path=wild" cargo test
- Jika symbolic link
ld.wild menunjuk ke wild, cara berikut juga bisa digunakan
RUSTFLAGS="-Clinker=clang -Clink-args=-fuse-ld=wild" cargo test
- Untuk menggunakan Wild sebagai linker kode Rust di CI, lihat wild-action
- Informasi kontribusi ada di CONTRIBUTING.md, dan ringkasan desain tingkat tinggi ada di DESIGN.md
- Percakapan terkait Wild berlangsung di Zulip server
- Blog David memuat banyak tulisan yang membahas berbagai aspek linker Wild
- Lisensinya dapat dipilih antara Apache License 2.0 atau MIT license
1 komentar
Opini Hacker News
Setelah mold direlisensikan ulang dari AGPL ke MIT (sebagai bagian dari rilis mold 2.0), saya pikir kebutuhan untuk membuat linker cepat lain secara global sudah jauh berkurang, jadi saya tidak menyangka proyek seperti ini akan muncul
Apalagi dalam beberapa kasus katanya sudah 2 kali lebih cepat daripada mold, itu makin di luar dugaan; saya akan mengikuti perkembangannya dan semoga sukses untuk penulisnya
Linker Microsoft sudah menjadikan incremental linking sebagai default sejak puluhan tahun lalu, jadi agak memalukan bahwa Linux masih belum punya incremental linker yang siap produksi
Kalau melihat issue GitHub, penulisnya awalnya mencoba mendukungnya lalu memindahkan dukungan Windows ke linker sold, tetapi sold baru-baru ini diarsipkan; jadi saya bingung apakah akhirnya memang tidak ada dukungan Windows, atau saya salah memahami alurnya
Saya pernah melihat-lihat sebelumnya, tetapi belum tahu apakah sudah siap dipakai di produksi
Berdasarkan README sepertinya belum, jadi saya masih memakai mold
Kalau Anda pengguna macOS, Apple merilis linker baru sekitar 1–2 tahun lalu, dan karena itu penulis mold menghentikan pengerjaan versi macOS
Untuk memakainya di Rust, masukkan ini ke
config.toml[target.aarch64-apple-darwin]rustflags = ["-C","link-arg=-fuse-ld=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld","-C","link-arg=-ld_new",]Saya memasang command line tools, tetapi yang ada hanya
/usr/bin/lddan/usr/bin/ld-classicAkan terasa segar kalau compiler C/C++ menghapus tahap perantara bernama linking dan membangun seluruh program sebagai satu unit
Jika compiler bisa melihat seluruh program sejak awal, LTO sendiri tidak diperlukan
Untuk incremental build, sebagian artefak build tetap perlu disimpan, tetapi bukan dalam bentuk object file; diperlukan metadata yang tahu asal-usul dan dependensi kode yang dihasilkan agar hanya bagian yang benar yang bisa diganti
Saat ini library eksternal biasanya di-link secara dinamis, jadi tidak perlu dibangun dari source, dan menghapus linker juga tidak akan menjadi masalah bagi dependensi tertutup
Kalau itu masih kurang, compiler bisa dibuat menerima object file juga, untuk menangani kasus legacy atau khusus yang harus di-link statis ke binary
SQLite3 menggabungkan semuanya menjadi satu unit kompilasi
Mungkin lebih banyak orang daripada yang dibayangkan sudah memakai cara ini
https://sqlite.org/amalgamation.html
Minat pada linker cepat meningkat besar karena adopsi dan popularitas Rust
Binary Rust static-linked berukuran sedang pun bisa memakan beberapa menit pada tahap linking saat kompilasi mode rilis (saat memakai mold)
Ini bukan masalah khusus Rust; secara umum ini adalah gabungan dari static linking yang ketat, optimisasi tingkat lanjut pada waktu link seperti LTO dan BOLT yang disediakan LLVM, serta keluhan komunitas Rust soal waktu kompilasi
Karena hubungan yang kuat dengan LLVM, bahkan bisa dibilang ketergantungan de facto, Rust menjadi bahasa dengan adopsi “sihir” link-time LLVM paling luas; C++ juga bisa mengalami masalah yang sama, tetapi saat itu kemungkinan besar disalahkan pada toolchain, bukan bahasanya
Saya sudah cukup lama memantau wild karena potensinya menjadi incremental linker yang mengoptimalkan, tetapi jujur saja, sampai benar-benar bisa melakukan incremental linking, saya sama sekali tidak punya motivasi untuk mencobanya
Selain itu, ekosistem C/C++ punya budaya menerima library binary, sehingga ketika meng-clone repositori atau berpindah branch pengembangan, sering kali Anda hanya perlu mengompilasi aplikasi sendiri tanpa mengompilasi ulang seluruh dunia
Jika shell aplikasi luar memanggil business logic Wasm, hanya logika internal yang perlu dikompilasi ulang, dan shell aplikasi luar bahkan tidak perlu di-restart
2008: linker baru gold yang dibuat agar lebih cepat daripada GNU ld
Sekitar 2015: linker pengganti drop-in lld yang setidaknya 2 kali lebih cepat daripada gold
2021: linker baru mold yang beberapa kali lebih cepat daripada lld
2025: linker baru wild...
Terkait ini, ada buku lama tetapi bagus dari John Levine, Linkers and Loaders
Itu buku terakhir dalam daftar di bawah
https://www.johnlevine.com/books.phtml
Saya membacanya beberapa tahun lalu dan cukup menarik; buku ini adalah rujukan standar di bidang ini
Seperti terlihat di tautan, ia juga menulis beberapa buku komputer populer lainnya
Terlihat cukup menjanjikan
Dibuat dengan Rust sejak awal, dan tujuannya adalah cepat sekaligus mendukung incremental linking
Untuk memakainya di Rust, mungkin bisa juga memakai gcc sebagai driver linker
Di
.cargo/config.tomlproyek:[target.x86_64-unknown-linux-gnu]rustflags = ["-C", "link-arg=-fuse-ld=wild"]Sedikit menyimpang, tapi mengapa Rust harus bergantung pada gcc atau clang di sini? Apakah ada fitur yang belum ada?
Sayangnya, gcc tidak menerima linker arbitrer lewat flag
-fuse-ld=Linker yang diterima hanya bfd, gold, lld, dan mold
gcc memang bisa dibuat memanggil wild sebagai linker, tetapi saat ini Anda harus membuat direktori yang berisi linker wild, lalu mengganti nama biner atau symbolic link menjadi
"ld", kemudian meneruskan-B/path/to/directory/containing/wildke gccAlasan Rust tidak memanggil linker secara langsung, melainkan memanggil linker lewat gcc atau clang, adalah karena compiler C mengetahui flag linker yang diperlukan untuk menautkan ke libc dan C runtime pada platform saat ini
Contohnya hal-hal seperti
Scrt1.o,crti.o,crtbeginS.o,crtendS.o,crtn.oKarena compiler Rust menghasilkan bytecode IR, bukan bahasa mesin
Saya penasaran, secara teoretis apa alasan ini bisa lebih cepat daripada mold dalam kasus non-incremental?
“Karena Rust” adalah penjelasan yang cukup baik untuk banyak hal, tetapi tidak menjelaskan keunggulan performa yang diharapkan
Kalau alasannya “ada peluang paralelisme yang tingkat kesulitannya rendah dan mudah dimanfaatkan oleh Rust”, itu menarik, tetapi hal itu tidak dinyatakan maupun diisyaratkan
Salah satu petunjuknya adalah saya pernah mendengar Mold menjadi sekitar 10% lebih cepat jika memakai allocator yang lebih cepat, mimalloc
Saya sudah mencoba mimalloc di Wild, tetapi tidak ada peningkatan kecepatan yang terukur
Dari sini tampaknya Mold menggunakan allocator lebih banyak daripada Wild, dan di Wild jelas ada upaya untuk mengoptimalkan jumlah alokasi heap
Secara umum, saya melihatnya sebagai perbedaan keputusan desain
Kalau dikaitkan dengan Rust, saya yakin jika Wild di-port dari Rust ke C atau C++, performanya akan hampir sama
Namun di Rust, berkat borrow checker, pola kode yang baik-baik saja bisa menjadi jebakan di C atau C++, sehingga pemeliharaannya bisa menjadi rumit
Dulu saat menulis kode C++, saya menulis lebih defensif meski harus menanggung sedikit biaya performa, tetapi di Rust saya tahu compiler menjaga dari belakang, jadi saya bisa menulis dengan jauh lebih berani
Kebetulan sekali
Satu jam lalu saya membandingkan performa wild, mold, ld pada proyek C yang sedang saya kerjakan
Proyeknya 23 ribu baris, 172 file, dan dengan
gcc+ldmemakan waktu pengguna sekitar 23,4 detik,gcc+mold22,5 detik,gcc+wild21,8 detikJadi menurut saya, untuk proyek yang strukturnya baik, waktu linking mungkin bukan masalah sebesar itu
Dalam kasus itu, sebagian besar waktu dipakai untuk mengompilasi kode, bukan linking
Keunggulan linker cepat paling terasa pada pengembangan iteratif
Artinya, setelah membuat perubahan kecil pada kode lalu membuild ulang dan menjalankan hasilnya, biasanya compiler hampir tidak punya banyak pekerjaan, tetapi linking tetap dilakukan dari awal sehingga mudah menjadi waktu yang dominan
ld.lld?“Benchmark ini dijalankan di laptop David Lattimore (System76 Lemur Pro model 2020), dengan 4 core (8 thread) dan RAM 42GB”
https://news.ycombinator.com/item?id=33330499
Sebagai catatan, saya tidak bermaksud mengatakan wild itu bongsor
Kalau ada masalah, masalahnya ada pada perangkat lunak yang dikembangkan dengan itu, dan pada komputer orang-orang yang akan memakai perangkat lunak semacam itu
https://news.ycombinator.com/item?id=42896619
“... RAM-nya 16GB, dan tidak bisa di-upgrade...”
Setengah bercanda, tetapi kalau seseorang menulis kode dengan Rust, rasanya mereka sudah punya RAM 32GB
Secara pribadi, mengorbankan secara harfiah semua hal lain untuk meng-upgrade laptop ke 64GB hampir merupakan keputusan yang sangat bagus
Saya bilang hampir, karena seharusnya saya tidak all-in ke RAM saja, melainkan mengeluarkan uang untuk RAM dan layar sekaligus
Satu-satunya kekurangannya adalah membereskan tab yang terbuka seminggu sekali kini menjadi pekerjaan yang memakan waktu sepanjang malam