1 poin oleh GN⁺ 2025-01-25 | 1 komentar | Bagikan ke WhatsApp
  • 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

 
GN⁺ 2025-01-25
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

    • mold tidak berniat melakukan incremental linking, jadi ada alasan besar bagi linker lain untuk tetap ada
      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
    • Mengapa perbedaan antara AGPL dan MIT penting untuk linker?
    • Saya tidak tahu bagaimana status dukungan Windows di mold
      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
    • Mungkin saya yang salah memakai, tetapi kalau menggunakan LTO yang mungkin memang seharusnya dipakai, mold sama sekali tidak lebih cepat
    • Tunggu, memang bisa merelisensikan ulang sesuatu dari GPL ke MIT?
  • 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",

    ]

    • Penulisnya cukup jelas mengatakan bahwa ini belum boleh dipakai di produksi
    • Saya juga tidak memakai mold untuk produksi, melainkan untuk pengembangan
    • Bukankah sekarang linker baru itu sudah menjadi default? Saya tidak begitu yakin menambahkan itu masih ada efeknya
    • Bisa pastikan apakah lokasi itu juga benar di Sequioa?
      Saya memasang command line tools, tetapi yang ada hanya /usr/bin/ld dan /usr/bin/ld-classic
  • Akan 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

  • 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

    • C++ bisa dikompilasi jauh lebih cepat daripada Rust karena sebagian compiler mendukung incremental compilation dan incremental linking
      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
    • Masalah ini saya selesaikan dengan Wasm
      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...

    • Jarang disebut, tetapi semua ini dimungkinkan dengan mengorbankan tidak mengimplementasikan banyak fitur berguna yang dipakai program-program nyata
    • Saya tidak tahu apakah ini komentar negatif, positif, atau sekadar ringkasan sejarah singkat, tetapi fakta bahwa masih ada performa yang bisa diperas lebih jauh dari linker cukup menggembirakan
    • gold akan dihapus di binutils 2.44.0, jadi secara resmi bisa dibilang sudah mati
    • Di Windows juga ada The RAD Linker, meski masih tahap awal
  • 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.toml proyek:

    [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/wild ke gcc
    Alasan 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.o

  • Karena 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

    • Saya tidak tahu pasti, terutama karena saya tidak akrab dengan codebase Mold
      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+ld memakan waktu pengguna sekitar 23,4 detik, gcc+mold 22,5 detik, gcc+wild 21,8 detik
    Jadi menurut saya, untuk proyek yang strukturnya baik, waktu linking mungkin bukan masalah sebesar itu

    • Kedengarannya seperti build ulang dari awal
      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
    • Waktu linking penting saat membuild sesuatu seperti Chrome, bukan proyek kecil
    • Linker cepat umumnya berguna untuk memangkas siklus edit dalam situasi kompilasi incremental
    • Bagaimana dengan 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