Seluruh biner yang kita bangun sejauh ini mewarisi satu keterbatasan senyap: mereka hanya bisa berjalan di arsitektur CPU yang sama dengan mesin praktikum ini, x86-64. Laptop ARM modern, Raspberry Pi, papan embedded, atau server berarsitektur lain akan menolaknya begitu saja. Menyewa mesin per arsitektur hanya untuk membangun bukan satu-satunya jalan — compiler GNU memang dirancang untuk cross-compilation: satu mesin yang sama bisa membangun biner untuk target yang berbeda, asalkan toolchain untuk target itu tersedia. Chapter ini membahas mekanismenya — target triple, toolchain terpisah, sysroot, dan toolchain file CMake — dengan satu program portabel sebagai bahan uji, plus cara memverifikasi arsitektur hasil build tanpa harus menjalankannya.
Program Portabel sebagai Bahan Uji #
Source yang akan kita cross-compile harus dulu layak untuk itu: tidak ada API spesifik OS, hanya standard library. Program penghitung BMI berikut memenuhi syarat itu:
#include <iomanip>
#include <iostream>
// Program portabel untuk latihan cross-compilation: menghitung BMI dari
// berat (kg) dan tinggi (m). Tidak ada API spesifik OS — source yang sama
// bisa dibangun toolchain mana pun untuk arsitektur mana pun.
int main(int argc, char* argv[]) {
if (argc < 3) {
std::cerr << "Pemakaian: hitung-bmi <berat-kg> <tinggi-m>\n";
return 1;
}
double berat = std::stod(argv[1]);
double tinggi = std::stod(argv[2]);
double bmi = berat / (tinggi * tinggi);
std::cout << std::fixed << std::setprecision(1);
std::cout << "BMI = " << bmi;
if (bmi < 18.5) std::cout << " (kurang)\n";
else if (bmi < 25.0) std::cout << " (normal)\n";
else std::cout << " (berlebih)\n";
return 0;
}Output yang Dihasilkan:
BMI = 22.9 (normal)Baris 15-16 mengonversi argumen teks menjadi double dengan std::stod — bagian dari standard library, bukan fasilitas OS. Baris 19-20 membentuk output dengan std::fixed dan std::setprecision sehingga angka desimal tampil konsisten di platform mana pun. Dua poin kecil itu justru inti bab ini: portabilitas source adalah prasyarat cross-compilation — toolchain mana pun yang menggantikan g++ hanya bisa bekerja bila kode tidak menyentuh /proc/self/exe, windows.h, atau API lain yang mengikat diri ke satu sistem.
Target Triple: Identitas Toolchain #
Compiler yang dipakai sepanjang course ini sebenarnya punya identitas lengkap yang bisa kita tanyakan langsung:
g++ -dumpmachineOutput yang Dihasilkan:
x86_64-linux-gnuString itu adalah target triple — konvensi penamaan arsitektur-vendor-os-abi yang menyatakan untuk siapa toolchain ini membangun. Bacaannya: CPU x86_64, vendor generik, OS Linux, ABI GNU. Dengan mengganti komponen-komponennya kita mendapat keluarga target yang sama-sama dikenal ekosistem GNU:
| Target triple | Arti |
|---|---|
x86_64-linux-gnu | PC/server 64-bit, Linux, glibc — target praktikum kita |
aarch64-linux-gnu | CPU ARM 64-bit (laptop ARM, Raspberry Pi 4/5), Linux, glibc |
x86_64-w64-mingw32 | Windows 64-bit lewat toolchain MinGW-w64 |
arm-none-eabi | ARM 32-bit tanpa OS — dunia embedded/mikrokontroler |
Vendor sering ditulis unknown atau dilewati, dan untuk target tanpa OS bagian OS-nya diganti eabi (embedded ABI). Polanya yang penting: satu triple = satu kombinasi CPU + sistem yang biner hasilnya cocok.
Toolchain Terpisah dan Sysroot #
Compiler bukan program yang fleksibel ke segala arah: g++ yang terpasang di praktikum membangun untuk x86_64-linux-gnu dan tidak bisa dipaksa menghasilkan kode ARM. Cross-compilation bekerja dengan toolchain terpisah — biner compiler sendiri yang diberi nama sesuai targetnya. Di Debian/Ubuntu, toolchain untuk ARM 64-bit tersedia sebagai paket siap pasang:
sudo apt install g++-aarch64-linux-gnuPerhatikan pola penamaannya: aarch64-linux-gnu-g++ adalah g++ yang identik secara perilaku, tetapi membangun untuk target triple tersebut. Setelah terpasang, cara pakainya nyaris sama dengan g++ biasa:
aarch64-linux-gnu-g++ -std=c++23 -O2 hitung-bmi.cpp -o hitung-bmi-arm64
file hitung-bmi-arm64hitung-bmi-arm64: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.2.0, not strippedBlok di atas adalah pola dan bentuk output yang diharapkan — toolchain ARM64 memang tidak terpasang di lingkungan praktikum ini (lihat bagian Referensi untuk memasangnya sendiri), tetapi setiap elemennya sudah Anda kenal dari chapter-chapter lama: flag sama, hasilnya tetap ELF, hanya arsitektur dan jalur interpreternya yang berubah. Konsep pendukungnya adalah sysroot: direktori yang berisi header dan library milik target — untuk toolchain di atas, /usr/aarch64-linux-gnu. Compiler harus mengambil header dan menautkan library dari sana, bukan dari milik mesin host; pada paket siap pasang, pengaturan ini sudah dibenamkan, tetapi begitu Anda membangun toolchain sendiri atau menautkan library pihak ketiga, --sysroot= adalah flag yang mengatur jalurnya.
Memverifikasi Arsitektur Hasil Build #
Kebiasaan paling penting dari bab ini sebenarnya sudah tampil di blok sebelumnya: jangan pernah berasumsi soal arsitektur — tanyakan pada file. Satu perintah itu membaca header ELF dan melaporkan ARM aarch64 atau x86-64 apa adanya, sehingga kesalahan seperti “toolchain yang salah terpilih” ketahuan dalam hitungan detik. Bila ingin benar-benar mengeksekusi hasil cross-compile di mesin host, ekosistem Linux menyediakan emulator mode pengguna QEMU:
qemu-aarch64 -L /usr/aarch64-linux-gnu ./hitung-bmi-arm64 70 1.75Flag -L mengarahkan QEMU memakai sysroot target saat biner meminta library-nya. Untuk proyek serius, pasangan “cross-compile lalu uji via QEMU” inilah fondasi CI multi-arsitektur yang berjalan di satu mesin.
Toolchain File untuk CMake #
Proyek CMake menerima seluruh pengaturan cross-compile lewat satu berkas toolchain file, sehingga build normal dan build cross-compile hanya berbeda di satu flag configure:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-gnu)
set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)Simpan berkas di atas sebagai aarch64-toolchain.cmake.
Dua baris pertama mendeklarasikan target sehingga CMake tidak mencoba mendeteksinya dari mesin host; CMAKE_CXX_COMPILER menunjuk cross-compiler; dan empat baris FIND_ROOT_PATH_MODE memaksa pencarian library, header, dan paket terjadi di sysroot target saja — program bantu yang dijalankan saat build tetap boleh dari host (NEVER untuk PROGRAM). Pemakaiannya satu baris: cmake -B build-arm64 -DCMAKE_TOOLCHAIN_FILE=aarch64-toolchain.cmake, lalu cmake --build build-arm64, dan file kembali menjadi hakim akhir arsitektur hasilnya. Simpan toolchain file di repository proyek; kombinasi source portabel plus toolchain file yang terdokumentasi membuat “membangun untuk target baru” menjadi urusan menit, bukan riset.
Dengan cross-compilation, jangkauan biner kita tidak lagi terkunci oleh mesin yang membangunnya. Berikutnya kita kembali ke sisi distribusi: bagaimana menyalurkan aplikasi ke pengguna Linux — dari paket .deb yang kita rakit sendiri hingga tarball dan bundle mandiri.
Referensi: cmake-toolchains(7) — CMake Docs , Cross-Compiler — GCC Internals .