00 Cross-compilation kavramı
Cross-compilation, kodun çalışacağı mimariden farklı bir makinede derlenmesidir. Gömülü geliştirmede standart yaklaşımdır: güçlü x86_64 iş istasyonunda ARM veya RISC-V binary üretirsin.
Üç makine kavramı
Canadian Cross
Build ≠ host ≠ target olan senaryodur. Örnek: x86_64 Linux makinesinde, Windows'ta çalışacak bir ARM cross-derleyici üretmek. crosstool-NG bu senaryoyu da destekler ancak tipik embedded kullanımda gerekmez.
Tipik cross-compile:
┌─────────────────────────────────────────────┐
│ build = x86_64-pc-linux-gnu │
│ host = x86_64-pc-linux-gnu (aynı) │
│ target = arm-unknown-linux-gnueabihf │
└─────────────────────────────────────────────┘
Canadian cross:
┌─────────────────────────────────────────────┐
│ build = x86_64-pc-linux-gnu │
│ host = x86_64-w64-mingw32 (Windows) │
│ target = aarch64-unknown-linux-gnu │
└─────────────────────────────────────────────┘
Neden paket yöneticisi toolchain'i yetmez?
Ubuntu'nun gcc-arm-linux-gnueabihf paketi genel amaçlıdır. Cortex-A53 için özel FPU optimizasyonu, belirli bir glibc sürümü veya musl libc gibi gereksinimler için crosstool-NG ile özel toolchain gerekir.
Toolchain ile hedef sistemin C kütüphanesi sürüm uyumlu olmalıdır. Toolchain'deki glibc sürümü, hedef rootfs'teki glibc sürümünden yeni olamaz — aksi hâlde binary çalışmaz (version 'GLIBC_2.33' not found hatası).
01 crosstool-NG kurulumu
crosstool-NG, GNU toolchain bileşenlerini (binutils, gcc, glibc/musl, gdb) otomatik indirip derleyen bir meta-build aracıdır. Autotools tabanlıdır, kaynak koddan kurulur.
Sistem bağımlılıkları (Ubuntu/Debian)
sudo apt update
sudo apt install -y \
gcc g++ gperf bison flex texinfo help2man make \
libncurses5-dev python3-dev autoconf automake \
libtool libtool-bin gawk wget bzip2 xz-utils \
unzip patch libstdc++6 rsync git meson ninja-build
Kaynak koddan kurulum
# Kararlı sürümü indir (2024-02 itibariyle 1.26.0)
git clone https://github.com/crosstool-ng/crosstool-ng.git
cd crosstool-ng
git checkout crosstool-ng-1.26.0
# configure ve install (~$HOME/ct-ng veya /usr/local)
./bootstrap
./configure --prefix="${HOME}/ct-ng"
make -j$(nproc)
make install
# PATH'e ekle
export PATH="${HOME}/ct-ng/bin:${PATH}"
echo 'export PATH="${HOME}/ct-ng/bin:${PATH}"' >> ~/.bashrc
# doğrula
ct-ng version
# crosstool-NG 1.26.0
Hazır sample listeleme
# desteklenen örnek konfigürasyonları listele
ct-ng list-samples
# ARM ile ilgili örnekler
ct-ng list-samples | grep arm
# arm-cortex_a8-linux-gnueabi
# arm-unknown-linux-gnueabi
# armv6-rpi-linux-gnueabi
# aarch64-unknown-linux-gnu
# örnek konfigürasyonu yükle
ct-ng arm-cortex_a8-linux-gnueabi
# ya da temiz başlangıç
ct-ng menuconfig
ct-ng komutlarını her zaman proje dizininde çalıştır. .config dosyası geçerli dizinde oluşturulur. Farklı projeler için ayrı dizinler kullan.
02 ct-ng menuconfig — arch ve libc seçimi
menuconfig, Kconfig tabanlı bir arayüzdür — Linux kernel konfigürasyonuyla aynı sistem. Ok tuşları, Space ve Enter ile gezinilir.
ARM Cortex-A53 konfigürasyonu
mkdir ~/toolchains/arm-cortex-a53 && cd ~/toolchains/arm-cortex-a53
ct-ng menuconfig
arm seç. 64-bit için aarch64.Little endian.32-bit.cortex-a53 — gcc'ye -mcpu=cortex-a53 geçer.neon-fp-armv8 — Cortex-A53'ün desteklediği FPU.hardware (FPU) — hard-float ABI için.C kütüphanesi seçimi
C-library → C library → glibc # tam POSIX, büyük boyut (~2 MB)
C-library → C library → musl # hafif, statik linking dostu (~600 KB)
C-library → C library → uclibc-ng # çok küçük MCU/router hedef (~400 KB)
pthread_setname_np gibi).GCC sürümü ve ek bileşenler
Toolchain options → Tuple's vendor string → "unknown"
→ Tuple's alias → "arm-linux-gnueabihf"
CC → GCC version → 13.2.0 # ya da mevcut en güncel
→ C++ support → [*] # C++ için işaretle
→ Fortran support → [ ] # gerekmiyorsa kapat
Debug facilities → gdb → [*] # target üzerinde çalışacak gdb
→ strace → [*]
03 ct-ng build — derleme süreci
Konfigürasyon tamamlandıktan sonra derleme başlatılır. İlk derleme internet bağlantısı gerektirir — kaynak arşivleri otomatik indirilir.
Derlemeyi başlat
# tüm CPU çekirdeklerini kullan (2 eksik bırakmak iyi pratik)
ct-ng build.$(( $(nproc) - 2 ))
# ya da sabit sayı
ct-ng build.4
# hata ayıklama modu — her adımı verbose yazdır
ct-ng build V=1 2>&1 | tee build.log
İlk derleme 30–90 dakika sürer (makineye ve seçilen bileşenlere göre değişir). Sonraki derlemeler, kaynak arşivler önbelleğe alındığı için daha hızlıdır. Önbellek dizini: ~/src/ (CT_LOCAL_TARBALLS_DIR ile değiştirilebilir).
Çıktı konumu
# varsayılan çıktı dizini
ls ~/x-tools/arm-unknown-linux-gnueabihf/
# çıktı dizinini değiştirmek için .config'de
CT_PREFIX_DIR="${HOME}/toolchains/${CT_TARGET}"
# toolchain'i PATH'e ekle
export PATH="${HOME}/x-tools/arm-unknown-linux-gnueabihf/bin:${PATH}"
# test et
arm-unknown-linux-gnueabihf-gcc --version
# arm-unknown-linux-gnueabihf-gcc (crosstool-NG 1.26.0) 13.2.0
Yaygın derleme hataları
CT_SAVE_TARBALLS=y ayarı ve elle indirip ~/src/'e kopyalama çözüm.CT_WORK_DIR ile büyük disk bölümüne yönlendir.ct-ng menuconfig'de sysroot seçeneklerini kontrol et.04 Tuple formatı
Toolchain prefix'i "tuple" olarak adlandırılır. Hedef sistemi tanımlayan standart bir format vardır.
arm - unknown - linux - gnueabihf
│ │ │ │
│ │ │ └─ ABI: gnu + eabi + hf (hard-float)
│ │ └─ İşletim sistemi: linux
│ └─ Vendor: unknown (özel: "rpi", "linaro", vb.)
└─ Mimari: arm
Örnekler:
┌─────────────────────────────────────────────────────┐
│ aarch64-unknown-linux-gnu 64-bit ARM, glibc │
│ arm-unknown-linux-gnueabihf 32-bit ARM hard-FP │
│ arm-unknown-linux-gnueabi 32-bit ARM soft-FP │
│ arm-unknown-linux-musleabihf 32-bit ARM + musl │
│ riscv64-unknown-linux-gnu RISC-V 64-bit │
│ riscv32-unknown-linux-gnu RISC-V 32-bit │
│ arm-unknown-linux-uclibcgnueabi uclibc-ng │
└─────────────────────────────────────────────────────┘
ABI açıklaması
05 Toolchain testi — Hello World ARM
Toolchain doğrulaması için minimal C programı derle, ARM binary olduğunu kontrol et ve QEMU ile çalıştır.
Kaynak dosya
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("Merhaba ARM dünyası!\n");
printf("sizeof(long) = %zu\n", sizeof(long));
return EXIT_SUCCESS;
}
Cross-compile ve doğrulama
# cross-compile
arm-unknown-linux-gnueabihf-gcc -o hello hello.c
# binary tipini doğrula
file hello
# hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
# dynamically linked, interpreter /lib/ld-linux-armhf.so.3, ...
# native x86_64'te çalışmaz
./hello
# bash: ./hello: cannot execute binary file: Exec format error
# QEMU user-mode ile çalıştır
sudo apt install qemu-user-static
qemu-arm-static ./hello
# Merhaba ARM dünyası!
# sizeof(long) = 4
# objdump ile mimariye bak
arm-unknown-linux-gnueabihf-objdump -f hello
# architecture: arm, flags 0x00000112:
# EXEC_P, HAS_SYMS, D_PAGED
Dinamik linked binary'yi QEMU ile çalıştırmak için qemu-arm-static toolchain sysroot'unu bilmeli. QEMU_LD_PREFIX=~/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot qemu-arm-static ./hello komutunu kullan ya da statik link: gcc -static -o hello hello.c.
06 Sysroot yapısı
Sysroot, hedef sistemin dosya sistemi hiyerarşisinin derleme makinesindeki taklididir. Başlık dosyaları ve kütüphaneler buradan alınır.
Dizin yapısı
SYSROOT=~/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot
ls $SYSROOT
# etc lib lib64 sbin usr
tree $SYSROOT -L 3
# ├── lib/
# │ ├── ld-linux-armhf.so.3 ← dynamic linker
# │ ├── libc.so.6 ← glibc
# │ ├── libm.so.6 ← math
# │ └── libpthread.so.0 ← threads
# └── usr/
# ├── include/ ← başlık dosyaları
# │ ├── stdio.h
# │ ├── pthread.h
# │ └── ...
# └── lib/
# ├── libc.a ← statik kütüphane
# └── crt1.o ← C runtime başlangıç
Sysroot'a kütüphane ekleme
# hedef sistemde kurulu bir kütüphanenin başlık ve lib dosyalarını sysroot'a kopyala
# örnek: libssl cross-compile için sysroot'a ekle
SYSROOT=~/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot
TARGET_ROOTFS=/mnt/rpi-rootfs # SD karttaki rootfs mount noktası
# başlık dosyaları
cp -r ${TARGET_ROOTFS}/usr/include/openssl ${SYSROOT}/usr/include/
# kütüphane dosyaları
cp ${TARGET_ROOTFS}/usr/lib/arm-linux-gnueabihf/libssl.so* ${SYSROOT}/usr/lib/
cp ${TARGET_ROOTFS}/usr/lib/arm-linux-gnueabihf/libcrypto.so* ${SYSROOT}/usr/lib/
# artık --sysroot ile otomatik bulunur
arm-unknown-linux-gnueabihf-gcc --sysroot=$SYSROOT -lssl -lcrypto ...
07 Raspberry Pi toolchain örneği
Raspberry Pi 4 (ARM Cortex-A72, 64-bit) için özel toolchain oluşturma adımları.
Konfigürasyon dosyası
# Temel mimari
CT_ARCH="arm"
CT_ARCH_64=y
CT_ARCH_ARCH="cortex-a72"
CT_ARCH_FPU="crypto-neon-fp-armv8"
CT_ARCH_FLOAT="hard"
CT_ARCH_WITH_ARCH="-march=armv8-a+crc"
# Vendor tuple
CT_TARGET_VENDOR="rpi4"
# Kernel headers (Raspbian Bullseye = 5.15)
CT_KERNEL_VERSION="5.15.0"
# C kütüphanesi
CT_LIBC="glibc"
CT_LIBC_VERSION="2.35"
# GCC sürümü
CT_CC_GCC_VERSION="13.2.0"
Derleme ve test
ct-ng build.$(nproc)
# Tuple: aarch64-rpi4-linux-gnu
export PATH="${HOME}/x-tools/aarch64-rpi4-linux-gnu/bin:${PATH}"
# derleme
aarch64-rpi4-linux-gnu-gcc -mcpu=cortex-a72 -O2 -o hello hello.c
# RPi'ye kopyala ve çalıştır
scp hello pi@raspberrypi.local:/home/pi/
ssh pi@raspberrypi.local "./hello"
# Merhaba ARM dünyası!
# sizeof(long) = 8 ← 64-bit
08 RISC-V toolchain örneği
RISC-V 64-bit (rv64gc) toolchain oluşturma — SiFive HiFive Unmatched, BeagleV Ahead gibi kartlar için.
menuconfig RISC-V ayarları
# hazır sample ile başla
ct-ng riscv64-unknown-linux-gnu
# veya manuel
ct-ng menuconfig
# Target Architecture → riscv
# Bitness → 64-bit
# Architecture level → rv64gc (general + compressed + double FP)
CT_ARCH="riscv"
CT_ARCH_64=y
CT_ARCH_ARCH="rv64gc"
CT_ARCH_ABI="lp64d" # double-precision FP ABI
CT_TARGET_VENDOR="unknown"
CT_KERNEL_VERSION="6.1.0"
CT_LIBC="glibc"
CT_LIBC_VERSION="2.36"
CT_CC_GCC_VERSION="13.2.0"
RISC-V derleme ve test
ct-ng build.$(nproc)
export PATH="${HOME}/x-tools/riscv64-unknown-linux-gnu/bin:${PATH}"
# derleme — rv64gc ABI
riscv64-unknown-linux-gnu-gcc \
-march=rv64gc -mabi=lp64d \
-O2 -o hello hello.c
# doğrula
file hello
# hello: ELF 64-bit LSB executable, UCB RISC-V, RVC, double-float ABI
# QEMU ile test
qemu-riscv64-static ./hello
# Merhaba ARM dünyası!
# sizeof(long) = 8
09 Pre-built toolchain alternatifleri
Özel derleme gerekmiyorsa, topluluğun sağladığı hazır toolchain'ler zaman kazandırır.
Linaro Toolchain
# Linaro aarch64 toolchain indir (releases.linaro.org)
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/\
gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
tar xf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
export PATH="$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:${PATH}"
aarch64-linux-gnu-gcc --version
# aarch64-linux-gnu-gcc (Linaro GCC 7.5-2019.12) 7.5.0
ARM GNU Toolchain (arm.com)
# developer.arm.com'dan indirme (2023.10 sürümü)
wget https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/\
arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
tar xf arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
export PATH="$(pwd)/arm-gnu-toolchain-13.2.Rel1-x86_64-aarch64-none-linux-gnu/bin:${PATH}"
aarch64-none-linux-gnu-gcc --version
# aarch64-none-linux-gnu-gcc (Arm GNU Toolchain 13.2.rel1) 13.2.0
Ubuntu/Debian paket toolchain'i
# ARM 32-bit hard-float
sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
arm-linux-gnueabihf-gcc --version
# ARM 64-bit
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
aarch64-linux-gnu-gcc --version
# RISC-V 64-bit
sudo apt install gcc-riscv64-linux-gnu
riscv64-linux-gnu-gcc --version
Paket toolchain'leri çoğu proje için yeterlidir. crosstool-NG'yi şu durumlarda tercih et: özel glibc sürümü gereksinimi, musl/uclibc seçimi, belirli CPU için agresif optimizasyon (-mcpu=cortex-a53 yerine özel arch level), ya da reproducible build gerekliliği.