00 --sysroot, -I, -L ve -rpath-link farkı
Cross-compile'da derleyicinin başlık ve kütüphane dosyalarını doğru yerden okuması kritiktir. Bu üç bayrak farklı aşamalarda devreye girer.
-I/usr/include yerine DIR/usr/include aranır. Aynı zamanda -L/lib yerine DIR/lib kullanılır. En temiz ve önerilen yöntem.-I${SYSROOT}/usr/include/libfoo.-L${SYSROOT}/usr/lib.Kullanım örneği
SYSROOT=~/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot
CROSS=arm-unknown-linux-gnueabihf
# en temiz yöntem: --sysroot her şeyi halleder
${CROSS}-gcc \
--sysroot=${SYSROOT} \
-o app main.c \
-lssl -lcrypto
# ek başlık dizini gerekirse
${CROSS}-gcc \
--sysroot=${SYSROOT} \
-I${SYSROOT}/usr/include/openssl \
-o app main.c -lssl
# rpath-link ile dolaylı bağımlılık çözümü
${CROSS}-gcc \
--sysroot=${SYSROOT} \
-Wl,-rpath-link,${SYSROOT}/lib/arm-linux-gnueabihf \
-o app main.c -lfoo
Cross-compile'da asla host sisteminin /usr/include veya /usr/lib dizinlerinden başlık/kütüphane okuma. Bu, undefined symbol veya mimari uyumsuzluğu hatasına yol açar. --sysroot kullanmak bu riski ortadan kaldırır.
01 -march / -mcpu / -mtune / -mfpu / -mfloat-abi
ARM için CPU-spesifik bayraklar hem doğruluk hem performans açısından kritiktir. Yanlış ABI seçimi runtime'da illegal instruction hatası verir.
armv7-a, armv8-a, armv8-a+crc+crypto. Bu seviyeyi destekleyen tüm CPU'larda çalışır — taşınabilir.cortex-a53, cortex-a72, cortex-a55. -march'ı da belirler.neon-fp-armv8, vfpv4, neon-vfpv4. Yalnızca 32-bit ARM'de gerekli.soft: FPU yok, yazılımda. softfp: FPU var ama ABI soft. hard: FPU register'larını kullanır — en hızlı.Yaygın ARM kombinasyonları
# Raspberry Pi 4 (Cortex-A72) — 64-bit
aarch64-linux-gnu-gcc \
-mcpu=cortex-a72 \
-O2 -o app main.c
# Raspberry Pi 3 (Cortex-A53) — 32-bit hard-float
arm-linux-gnueabihf-gcc \
-march=armv8-a -mcpu=cortex-a53 \
-mfpu=neon-fp-armv8 -mfloat-abi=hard \
-O2 -o app main.c
# BeagleBone Black (Cortex-A8) — 32-bit hard-float
arm-linux-gnueabihf-gcc \
-march=armv7-a -mcpu=cortex-a8 \
-mfpu=neon -mfloat-abi=hard \
-O2 -o app main.c
# Eski ARM926 (soft-float)
arm-linux-gnueabi-gcc \
-march=armv5te -mcpu=arm926ej-s \
-mfloat-abi=soft \
-O2 -o app main.c
# RISC-V 64-bit, rv64gc
riscv64-linux-gnu-gcc \
-march=rv64gc -mabi=lp64d \
-O2 -o app main.c
Mevcut seçenekleri sorgula
# desteklenen CPU listesi
arm-linux-gnueabihf-gcc --target-help | grep -A1 "Known ARM CPUs"
# desteklenen FPU listesi
arm-linux-gnueabihf-gcc -mfpu=help 2>&1 | head -30
# aktif tüm özellikleri göster
arm-linux-gnueabihf-gcc -Q -mcpu=cortex-a53 --help=target 2>/dev/null | head -40
02 Multilib — --print-multi-lib
Multilib, tek bir toolchain'in farklı ABI kombinasyonları için önceden derlenmiş kütüphaneler içermesidir. Sistem toolchain'lerinde yaygındır.
Multilib'i sorgula
# toolchain'in desteklediği multilib kombinasyonları
arm-linux-gnueabihf-gcc --print-multi-lib
# .;@march=armv7-a@mfpu=vfpv3-d16@mfloat-abi=hard@mmode=thumb
# thumb;@mthumb
# armv7-a;@march=armv7-a
# belirli bayraklarla hangi multilib seçileceğini göster
arm-linux-gnueabihf-gcc \
-march=armv7-a -mfloat-abi=hard \
--print-multi-directory
# armv7-a/thumb
# multilib dizini nerede?
arm-linux-gnueabihf-gcc --print-multi-os-directory
# ../lib
crosstool-NG ile oluşturulan toolchain'ler varsayılan olarak multilib içermez — tek bir ABI için optimize edilmiştir. Bu kasıtlıdır: her hedef için ayrı toolchain tutmak daha temizdir. Multilib gerekiyorsa CT_MULTILIB=y seçeneğini etkinleştir.
03 LTO — Link-Time Optimization cross ortamda
LTO, derleme birimlerinin birbirini "görerek" optimize edilmesini sağlar. Cross ortamda özel dikkat gerektirir.
LTO etkinleştirme
# derleme ve link aşamasında -flto gerekir
CROSS=arm-unknown-linux-gnueabihf
${CROSS}-gcc -flto -O2 -c main.c -o main.o
${CROSS}-gcc -flto -O2 -c util.c -o util.o
# link aşamasında da -flto
${CROSS}-gcc -flto -O2 -o app main.o util.o
# paralel LTO (GCC 10+)
${CROSS}-gcc -flto=4 -O2 -o app main.o util.o
LTO ve cross araçları
# LTO, cross toolchain'in ar/nm/ranlib araçlarını kullanır
# Makefile'da cross araçlarını ayarla
AR = arm-unknown-linux-gnueabihf-ar
NM = arm-unknown-linux-gnueabihf-nm
RANLIB = arm-unknown-linux-gnueabihf-ranlib
CC = arm-unknown-linux-gnueabihf-gcc
CFLAGS = -flto -O2 -march=armv8-a -mcpu=cortex-a53
LDFLAGS = -flto
# LTO ile statik kütüphane oluştururken
# gcc-ar kullan (plugin destekli)
arm-unknown-linux-gnueabihf-gcc-ar rcs libfoo.a foo.o bar.o
-ffat-lto-objects bayrağı hem LTO IR hem normal object code içeren "fat" nesne dosyası üretir. LTO'yu desteklemeyen araçlarla (eski ar, nm) uyumlu kütüphaneler için kullanılır. Boyut artar ama esneklik kazanılır.
04 PIE ve ASLR embedded'da
PIE (Position Independent Executable), ASLR ile birlikte adres tahmin saldırılarını zorlaştırır. Ancak embedded'da bazen performans veya bellek kısıtları nedeniyle devre dışı bırakılır.
-fPIE derleme, -pie link bayrağı.Embedded senaryolar
# Normal uygulama — PIE önerilen (güvenlik)
arm-linux-gnueabihf-gcc \
-fPIE -pie \
-O2 -o app main.c
# PIE kontrolü
arm-linux-gnueabihf-readelf -h app | grep Type
# Type: DYN (Position-Independent Executable file)
# Bellek kısıtlı sistem — PIE devre dışı
arm-linux-gnueabihf-gcc \
-no-pie -fno-PIE \
-O2 -o app main.c
arm-linux-gnueabihf-readelf -h app | grep Type
# Type: EXEC (Executable file)
# Paylaşımlı kütüphane
arm-linux-gnueabihf-gcc \
-fPIC -shared \
-o libfoo.so foo.c
Eğer hedef sistem ASLR destekliyorsa (modern Linux kernel + glibc) ve bellekte yeri varsa PIE kullan. Sabit adres gerektiren boot-time kodunda, MCU stub'larında veya çok kısıtlı sistemlerde -no-pie tercih et.
05 Debug sembolleri — -g / -g3 / -gdwarf-4
Debug sembolleri binary'nin boyutunu artırır ama GDB, Valgrind ve perf gibi araçlar için gereklidir. Cross ortamda DWARF sürümü ve boyut dengesini yönetmek önemlidir.
Debug + optimizasyon kombinasyonu
# geliştirme: debug semboller, optimizasyon yok
arm-linux-gnueabihf-gcc -g3 -gdwarf-4 -O0 -o app_debug main.c
# üretim debug: optimize + debug (GDB'de değişkenler inline edilmiş olabilir)
arm-linux-gnueabihf-gcc -g -O2 -o app_reldbg main.c
# yayın: debug yok, maksimum optimize
arm-linux-gnueabihf-gcc -O2 -DNDEBUG -o app_release main.c
# debug bilgisi miktarı karşılaştır
arm-linux-gnueabihf-size app_debug app_reldbg app_release
# text data bss dec filename
# 1234 104 16 1354 app_debug
# 892 104 16 1012 app_reldbg
# 756 104 16 876 app_release
# DWARF bilgisini incele
arm-linux-gnueabihf-objdump --dwarf=info app_debug | head -50
06 objcopy ile stripped ve debug binary ayırma
Standart yaklaşım: debug sembolli binary'yi ayrı dosyaya kaydet, hedefe debug sembolsüz ("stripped") binary gönder. GDB build host'tan debug sembollerini okur.
Adım adım ayırma
CROSS=arm-unknown-linux-gnueabihf
# 1. debug sembolli binary derle
${CROSS}-gcc -g -O2 -o app main.c util.c
# 2. debug sembollerini ayrı dosyaya çıkar (.debug uzantısı standart)
${CROSS}-objcopy --only-keep-debug app app.debug
# 3. ana binary'den debug sembollerini sil
${CROSS}-strip --strip-debug app
# veya daha agresif (sembol tablosunu da sil)
${CROSS}-strip --strip-unneeded app
# 4. stripped binary'yi debug dosyasına bağla (GNU debug link)
${CROSS}-objcopy --add-gnu-debuglink=app.debug app
# boyut karşılaştır
ls -lh app app.debug
# -rwxr-xr-x app 12K ← hedefe bu gider
# -rw-r--r-- app.debug 48K ← geliştirici ortamında kalır
GDB ile uzak debug (remote GDB)
# Hedef sistemde (ARM kart)
gdbserver :2345 ./app
# Host'ta (x86_64)
arm-unknown-linux-gnueabihf-gdb app.debug
# GDB içinde
(gdb) set sysroot ~/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot
(gdb) target remote 192.168.1.100:2345
(gdb) continue
GNU debug link yerine build-id tabanlı ayrım da kullanılabilir: --build-id=sha1 bayrağıyla derleme. Debug semboller /usr/lib/debug/.build-id/ hiyerarşisine yerleştirilebilir. eu-strip (elfutils) bu akışı otomatikleştirir.
07 --gc-sections ile boyut optimizasyonu
Embedded sistemlerde flash/ROM boyutu kritik olabilir. GCC ve linker birlikte kullanılmayan kod ve veri bölümlerini binary'den çıkarabilir.
Temel bayraklar
.text.myfunc). Linker'ın kullanılmayan fonksiyonu çıkarmasını mümkün kılar..data.myvar). Kullanılmayan global değişkenleri çıkarmak için.KEEP() direktifi ile işaretlenmeyen section'lar silinir.CROSS=arm-unknown-linux-gnueabihf
# gc-sections olmadan
${CROSS}-gcc -O2 -o app_fat main.c libutil.c
# gc-sections ile
${CROSS}-gcc \
-O2 \
-ffunction-sections \
-fdata-sections \
-Wl,--gc-sections \
-o app_slim main.c libutil.c
# boyut karşılaştır
${CROSS}-size app_fat app_slim
# text data bss dec filename
# 24680 312 128 25120 app_fat
# 18240 280 96 18616 app_slim ← ~26% küçük
# hangi section'ların çıkarıldığını görmek için
${CROSS}-gcc \
-ffunction-sections -fdata-sections \
-Wl,--gc-sections \
-Wl,--print-gc-sections \
-o app_slim main.c libutil.c 2>&1 | head -20
Ek boyut optimizasyonu bayrakları
# -Os: boyut için optimize (O2 yerine)
${CROSS}-gcc -Os -ffunction-sections -fdata-sections \
-Wl,--gc-sections -o app main.c
# -Oz: GCC 12+ — daha agresif boyut optimizasyonu
${CROSS}-gcc -Oz -ffunction-sections -fdata-sections \
-Wl,--gc-sections -o app main.c
# strip ile son boyut küçültme
${CROSS}-strip --strip-all app
# UPX ile sıkıştırma (dinamik linked exe için dikkatli kullan)
# upx --best app
08 CFLAGS / LDFLAGS / CC / CXX ortam değişkenleri
Autotools ve birçok build sistemi, cross-compile konfigürasyonunu ortam değişkenleri üzerinden alır. Bu değişkenlerin doğru ayarlanması projeyi yeniden yazmadan cross-compile etmenin en pratik yoludur.
arm-linux-gnueabihf-gccarm-linux-gnueabihf-g++arm-linux-gnueabihf-ararm-linux-gnueabihf-strip-march=armv8-a -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard --sysroot=...--sysroot=... -L${SYSROOT}/usr/libcross-compile ortam şablonu
#!/bin/bash
# ARM Cortex-A53 cross-compile ortam değişkenleri
# Kullanım: source cross-env.sh
CROSS_TRIPLE="arm-unknown-linux-gnueabihf"
TOOLCHAIN_DIR="${HOME}/x-tools/${CROSS_TRIPLE}"
SYSROOT="${TOOLCHAIN_DIR}/${CROSS_TRIPLE}/sysroot"
export PATH="${TOOLCHAIN_DIR}/bin:${PATH}"
export CC="${CROSS_TRIPLE}-gcc"
export CXX="${CROSS_TRIPLE}-g++"
export AR="${CROSS_TRIPLE}-ar"
export AS="${CROSS_TRIPLE}-as"
export LD="${CROSS_TRIPLE}-ld"
export RANLIB="${CROSS_TRIPLE}-ranlib"
export STRIP="${CROSS_TRIPLE}-strip"
export OBJCOPY="${CROSS_TRIPLE}-objcopy"
export OBJDUMP="${CROSS_TRIPLE}-objdump"
CPU_FLAGS="-march=armv8-a -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard"
export CFLAGS="${CPU_FLAGS} --sysroot=${SYSROOT} -O2 -ffunction-sections -fdata-sections"
export CXXFLAGS="${CFLAGS}"
export LDFLAGS="--sysroot=${SYSROOT} -Wl,--gc-sections -L${SYSROOT}/usr/lib"
export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig"
export PKG_CONFIG_PATH=""
echo "Cross-compile ortamı aktif: ${CROSS_TRIPLE}"
09 Pratik: configure script ile cross-compile
Autotools tabanlı projeler (libssl, libcurl, zlib, vb.) configure script kullanır. Cross-compile için --host parametresi ve ortam değişkenleri yeterlidir.
zlib cross-compile örneği
source cross-env.sh # ortamı yükle
SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"
INSTALL_PREFIX="${SYSROOT}/usr"
# zlib kaynak kodunu indir
wget https://zlib.net/zlib-1.3.1.tar.gz
tar xf zlib-1.3.1.tar.gz
cd zlib-1.3.1
# configure — zlib --host desteklemez, CC ile geçilir
./configure \
--prefix="${INSTALL_PREFIX}" \
--static
make -j$(nproc)
make install
ls ${INSTALL_PREFIX}/lib/libz.a
# /home/user/x-tools/.../sysroot/usr/lib/libz.a
libcurl cross-compile örneği
source cross-env.sh
SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"
CROSS_TRIPLE="arm-unknown-linux-gnueabihf"
wget https://curl.se/download/curl-8.5.0.tar.gz
tar xf curl-8.5.0.tar.gz
cd curl-8.5.0
./configure \
--host="${CROSS_TRIPLE}" \
--prefix="${SYSROOT}/usr" \
--with-ssl="${SYSROOT}/usr" \
--disable-shared \
--enable-static \
--disable-ldap \
--disable-sspi \
--without-libidn \
--without-librtmp
make -j$(nproc)
make install
# doğrula — ARM binary olmalı
file ${SYSROOT}/usr/bin/curl-config
# ELF 32-bit LSB shared object, ARM, EABI5
configure script'e --build derleme makinesini, --host hedef makinesini belirtir. --target yalnızca derleyici gibi araç zincirleri için geçerlidir. Normal kütüphane/uygulama cross-compile'ında --host=arm-unknown-linux-gnueabihf yeterlidir.