00 Meson cross-compilation mimarisi
Meson, cross-compilation için INI formatında "cross file" kullanır. CMake'in toolchain.cmake'ine karşılık gelir, ancak daha okunabilir bir sözdizimi vardır.
Genel akış
meson setup builddir --cross-file arm-cortex-a53.ini
│
↓
cross file okunur
┌─────────────────────────────────────────────────────────┐
│ [host_machine] → hedef sistemin özellikleri │
│ [binaries] → derleyici ve araç yolları │
│ [properties] → CPU ve platform özellikleri │
│ [built_in_options]→ varsayılan derleme bayrakları │
└─────────────────────────────────────────────────────────┘
│
↓
Compiler introspection (ARM gcc ile)
Dependency detection (pkg-config wrapper ile)
│
↓
Ninja build dosyaları üretilir
Meson kurulumu
# pip ile güncel sürüm
pip3 install --user meson ninja
# veya sistem paketi
sudo apt install meson ninja-build
meson --version
# 1.3.0
Dikkat: Meson'un terminolojisi diğer araçlardan tersdir. Meson'da build_machine derlemenin yapıldığı makine (x86_64 iş istasyonu), host_machine binary'nin çalışacağı hedef (ARM kart). CMake ve autotools'daki "host" ile "target" kavramlarıyla karıştırma.
01 Cross file formatı — machine / binaries / properties
Cross file, INI formatında bölümlerden oluşur. Her bölüm farklı bir yapılandırma kategorisini kapsar.
Tam cross file yapısı
[host_machine]
# Hedef sistemin özellikleri
system = 'linux' # işletim sistemi
cpu_family = 'arm' # CPU ailesi: arm, aarch64, riscv32, riscv64, x86, x86_64
cpu = 'cortex-a53' # spesifik CPU (meson.get_compiler().cpu() ile okunur)
endian = 'little' # endianness: little veya big
[binaries]
# Cross derleyici ve araç yolları
c = 'arm-unknown-linux-gnueabihf-gcc'
cpp = 'arm-unknown-linux-gnueabihf-g++'
ar = 'arm-unknown-linux-gnueabihf-ar'
as = 'arm-unknown-linux-gnueabihf-as'
ld = 'arm-unknown-linux-gnueabihf-ld'
strip = 'arm-unknown-linux-gnueabihf-strip'
objcopy = 'arm-unknown-linux-gnueabihf-objcopy'
objdump = 'arm-unknown-linux-gnueabihf-objdump'
ranlib = 'arm-unknown-linux-gnueabihf-ranlib'
nm = 'arm-unknown-linux-gnueabihf-nm'
pkgconfig = '/home/user/bin/arm-linux-gnueabihf-pkg-config'
# QEMU ile cross test (opsiyonel)
exe_wrapper = ['qemu-arm-static', '-L',
'/home/user/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot']
[properties]
# Hedef sistem hakkında ek bilgi
sys_root = '/home/user/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot'
# Meson'un test edemediği özellikler (cross ortamda çalıştıramaz)
sizeof_int = 4
sizeof_long = 4
sizeof_void* = 4
# pkg-config için sysroot
pkg_config_libdir = [
'/home/user/.../sysroot/usr/lib/pkgconfig',
'/home/user/.../sysroot/usr/share/pkgconfig'
]
[built_in_options]
# Varsayılan derleme seçenekleri
c_args = ['-march=armv8-a', '-mcpu=cortex-a53', '-mfpu=neon-fp-armv8', '-mfloat-abi=hard']
cpp_args = ['-march=armv8-a', '-mcpu=cortex-a53', '-mfpu=neon-fp-armv8', '-mfloat-abi=hard']
c_link_args = ['--sysroot=/home/user/.../sysroot']
cpp_link_args = ['--sysroot=/home/user/.../sysroot']
cpu_family değerleri
02 exe_wrapper — QEMU ile cross test
exe_wrapper, Meson'un cross ortamda ürettiği binary'leri çalıştırmasını sağlar. Derleme testleri ve unit testler için kritiktir.
QEMU user-mode kurulumu
# QEMU user-mode static binary'leri kur
sudo apt install qemu-user-static binfmt-support
# binfmt desteğini etkinleştir (ARM binary'leri otomatik çalıştırır)
sudo update-binfmts --enable qemu-arm
sudo update-binfmts --enable qemu-aarch64
# test
qemu-arm-static --version
# qemu-arm version 8.x.x
# ARM binary'yi doğrudan çalıştır (binfmt aktifse)
./arm-binary
# veya açıkça
qemu-arm-static ./arm-binary
Cross file'da exe_wrapper
[binaries]
# ... diğer araçlar ...
# QEMU ile çalıştır + sysroot belirt
exe_wrapper = [
'qemu-arm-static',
'-L', '/home/user/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot'
]
Meson test çalıştırma
meson setup builddir --cross-file arm-cortex-a53.ini
cd builddir
ninja
# testleri QEMU ile çalıştır
ninja test
# [1/3] test_basic PASSED 0.12s (via qemu-arm-static)
# [2/3] test_math PASSED 0.08s (via qemu-arm-static)
# [3/3] test_io PASSED 0.15s (via qemu-arm-static)
exe_wrapper tanımlanmazsa Meson, cross ortamda derleyici özellik testlerini ve unit testleri atlayabilir. Derleme hâlâ çalışır ama bazı özellik algılamaları properties bölümündeki sabit değerlerle yapılır.
03 --cross-file parametresi ve birden fazla cross file
Meson, birden fazla cross file kabul eder — sonrakiler önceki dosyaları geçersiz kılar. Bu, temel toolchain dosyasını değiştirmeden proje-spesifik ayarlar eklemeye olanak tanır.
# tek cross file
meson setup builddir \
--cross-file arm-cortex-a53.ini \
--buildtype release
# birden fazla cross file (ikinci birincinin üzerine yazar)
meson setup builddir \
--cross-file toolchains/arm-base.ini \
--cross-file projects/myproject-arm.ini \
--buildtype release
# native file ile birlikte
meson setup builddir \
--native-file native-x86_64.ini \
--cross-file arm-cortex-a53.ini
Proje-spesifik ek cross file
# Temel arm-cortex-a53.ini üzerine proje-spesifik ayarlar
# Bu dosya arm-cortex-a53.ini'yi geçersiz kılmaz, tamamlar
[built_in_options]
# Proje özel derleme seçenekleri (temel dosyadakilerle birleşir)
c_args = ['-DMYPROJECT_VERSION="1.2.3"', '-DENABLE_FEATURE_X=1']
Meson introspect ile cross bilgisini sorgula
cd builddir
# cross-compile bilgisini göster
meson introspect --machines
# {
# "host": {"cpu": "cortex-a53", "cpu_family": "arm", ...},
# "build": {"cpu": "x86_64", "cpu_family": "x86_64", ...}
# }
# kullanılan derleyicileri göster
meson introspect --compilers
# {"c": {"id": "gcc", "exelist": ["arm-unknown-linux-gnueabihf-gcc"], ...}}
04 pkg-config entegrasyonu cross dosyada
Meson, bağımlılıkları bulmak için pkg-config kullanır. Cross ortamda cross sistemine ait pkg-config wrapper'ı kullanılmalıdır.
Cross file'da pkgconfig ayarı
[binaries]
# ... derleyiciler ...
pkgconfig = '/home/user/bin/arm-linux-gnueabihf-pkg-config'
[properties]
# pkg-config arama dizinleri
pkg_config_libdir = [
'/home/user/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot/usr/lib/pkgconfig',
'/home/user/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot/usr/share/pkgconfig'
]
meson.build'de dependency kullanımı
project('myapp', 'c', version: '1.0.0')
# pkg-config üzerinden bağımlılık bul
openssl_dep = dependency('openssl', version: '>=1.1.0')
zlib_dep = dependency('zlib')
curl_dep = dependency('libcurl', required: false)
# cross ortamda otomatik olarak arm pkg-config kullanılır
executable('myapp', 'main.c',
dependencies: [openssl_dep, zlib_dep, curl_dep],
)
# cmake bul
# cmake paketi pkg-config desteklemiyorsa
sdl2_dep = dependency('sdl2', method: 'pkg-config')
Bağımlılık durumunu kontrol et
meson setup builddir --cross-file arm-cortex-a53.ini
# Meson üretir:
# Checking for pkg-config binary... /home/user/bin/arm-linux-gnueabihf-pkg-config (1.8.1)
# Dependency openssl found: YES 3.0.2
# Dependency zlib found: YES 1.2.11
# Dependency libcurl found: NO (disabled)
05 Native file vs cross file farkı
Native file, derleme makinesi (build machine) için araçları tanımlar. Cross file ise hedef makine (host machine) için. İkisi birbirini tamamlar.
Native file örneği
[binaries]
# Build makinesinde çalışan araçlar (code generation için)
c = 'gcc'
cpp = 'g++'
python3 = '/usr/bin/python3'
# protobuf code generator (ARM'da çalışamaz, host'ta çalışır)
protoc = '/usr/bin/protoc'
# Qt moc (host'ta kurulu Qt araçları)
moc = '/usr/lib/qt6/libexec/moc'
rcc = '/usr/lib/qt6/libexec/rcc'
uic = '/usr/lib/qt6/libexec/uic'
Meson'da native vs cross kullanımı
# protobuf: proto dosyalarından C++ üret (build makinesinde çalışır)
protoc = find_program('protoc', native: true)
proto_gen = custom_target('proto_gen',
input: 'messages.proto',
output: ['messages.pb.cc', 'messages.pb.h'],
command: [protoc, '--cpp_out=.', '@INPUT@'],
native: true # build makinesinde çalışır
)
# ana kütüphane (cross — ARM için derlenir)
mylib = library('mylib',
'mylib.c',
proto_gen, # üretilen dosyaları dahil et
)
# hem native hem cross file ile setup
meson setup builddir \
--native-file native-x86_64.ini \
--cross-file arm-cortex-a53.ini
06 meson configure ile cross değiştirme
Bir kez kurulmuş build dizininde cross file değiştirilemez. Yeni hedef için yeni build dizini gerekir. Ancak bazı build seçenekleri değiştirilebilir.
Build seçeneklerini değiştirme
# Mevcut build seçeneklerini listele
meson configure builddir
# build tipini değiştir (cross file değişmez)
meson configure builddir --buildtype=debug
# proje-spesifik seçenek değiştir
meson configure builddir -Denable_tests=false
# c_args ekle (dikkat: mevcut değerlerin üzerine yazar)
meson configure builddir -Dc_args="-DDEBUG_VERBOSE=1"
# sonra yeniden derle
ninja -C builddir
Farklı hedef için yeni build dizini
# ARM 32-bit için
meson setup build-arm32 \
--cross-file arm-cortex-a53.ini \
--buildtype release
# ARM 64-bit için (ayrı dizin)
meson setup build-arm64 \
--cross-file aarch64-cortex-a55.ini \
--buildtype release
# RISC-V için (ayrı dizin)
meson setup build-riscv64 \
--cross-file riscv64.ini \
--buildtype release
# hepsini derle
for dir in build-arm32 build-arm64 build-riscv64; do
ninja -C $dir
done
meson setup --wipe builddir --cross-file yeni-cross.ini komutu build dizinini temizleyip yeni cross file ile yeniden konfigüre eder. Cache ve derleme çıktıları silinir, kaynak değişmez.
07 Subproject ve wrap dependency cross'ta
Meson subproject'leri ve .wrap dosyaları, bağımlılıkları kaynak koddan derler. Cross ortamda otomatik olarak aynı cross toolchain kullanılır.
Wrap dosyası ile bağımlılık
[wrap-file]
directory = zlib-1.3.1
source_url = https://zlib.net/zlib-1.3.1.tar.gz
source_hash = 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23
[provide]
zlib = zlib_dep
project('myapp', 'c')
# önce sistem pkg-config'te ara, bulamazsa subproject'ten al
zlib_dep = dependency('zlib',
fallback: ['zlib', 'zlib_dep']
)
# sadece subproject'ten al (sistem kütüphanesi kullanma)
openssl_dep = dependency('openssl',
fallback: ['openssl', 'openssl_dep'],
default_options: ['default_library=static']
)
executable('myapp', 'main.c',
dependencies: [zlib_dep, openssl_dep]
)
WrapDB'den bağımlılık
# WrapDB'den mevcut wrap dosyalarını listele
meson wrap list
# zlib wrap dosyasını indir
meson wrap install zlib
# cross compile — subproject otomatik olarak ARM için derlenir
meson setup build-arm \
--cross-file arm-cortex-a53.ini \
--wrap-mode=forcefallback # sistem kütüphanesini yoksay, hep subproject kullan
ninja -C build-arm
--wrap-mode=nofallback: subproject fallback'leri devre dışı bırak (sadece sistem kütüphanesi). --wrap-mode=forcefallback: her zaman subproject kullan. Cross ortamda forcefallback kullanmak güvenlidir — tüm bağımlılıklar hedef mimari için derlenir.
08 Pratik: ARM aarch64 cross file örneği
Raspberry Pi 4 (Cortex-A72, AArch64) için tam cross file — pkg-config, QEMU ve sysroot dahil.
# ════════════════════════════════════════════════════════════
# Meson Cross File — Raspberry Pi 4 (AArch64 / Cortex-A72)
# Kullanım: meson setup builddir --cross-file aarch64-rpi4.ini
# ════════════════════════════════════════════════════════════
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'cortex-a72'
endian = 'little'
[binaries]
c = 'aarch64-unknown-linux-gnu-gcc'
cpp = 'aarch64-unknown-linux-gnu-g++'
ar = 'aarch64-unknown-linux-gnu-ar'
strip = 'aarch64-unknown-linux-gnu-strip'
objcopy = 'aarch64-unknown-linux-gnu-objcopy'
pkgconfig = '/home/user/bin/aarch64-linux-gnu-pkg-config'
exe_wrapper = [
'qemu-aarch64-static',
'-L', '/home/user/x-tools/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot'
]
[properties]
sys_root = '/home/user/x-tools/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot'
sizeof_int = 4
sizeof_long = 8
sizeof_void* = 8
pkg_config_libdir = [
'/home/user/x-tools/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot/usr/lib/pkgconfig',
'/home/user/x-tools/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot/usr/share/pkgconfig'
]
[built_in_options]
c_args = ['-mcpu=cortex-a72', '-O2', '-ffunction-sections', '-fdata-sections']
cpp_args = ['-mcpu=cortex-a72', '-O2', '-ffunction-sections', '-fdata-sections']
c_link_args = ['--sysroot=/home/user/x-tools/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot', '-Wl,--gc-sections']
cpp_link_args = ['--sysroot=/home/user/x-tools/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot', '-Wl,--gc-sections']
Kullanım
# setup
meson setup build-rpi4 \
--cross-file aarch64-rpi4.ini \
--buildtype release \
--strip
# derleme
ninja -C build-rpi4 -j$(nproc)
# test (QEMU ile)
ninja -C build-rpi4 test
# RPi'ye kopyala ve çalıştır
scp build-rpi4/myapp pi@raspberrypi.local:/home/pi/
ssh pi@raspberrypi.local "./myapp"
09 musl-libc ile cross ve Meson + crosstool-NG combo
musl-libc, statik linkinge uygun hafif C kütüphanesidir. crosstool-NG ile musl toolchain oluştururken Meson cross file'ı da buna göre ayarlamak gerekir.
musl cross file
[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'cortex-a53'
endian = 'little'
[binaries]
c = 'arm-unknown-linux-musleabihf-gcc'
cpp = 'arm-unknown-linux-musleabihf-g++'
ar = 'arm-unknown-linux-musleabihf-ar'
strip = 'arm-unknown-linux-musleabihf-strip'
pkgconfig = '/home/user/bin/arm-linux-musleabihf-pkg-config'
exe_wrapper = ['qemu-arm-static', '-L',
'/home/user/x-tools/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/sysroot']
[properties]
sys_root = '/home/user/x-tools/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/sysroot'
pkg_config_libdir = [
'/home/user/x-tools/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/sysroot/usr/lib/pkgconfig'
]
[built_in_options]
# musl için statik link önerilir
c_args = ['-march=armv8-a', '-mcpu=cortex-a53', '-mfpu=neon-fp-armv8', '-mfloat-abi=hard']
c_link_args = ['--sysroot=/home/user/x-tools/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/sysroot', '-static']
cpp_args = ['-march=armv8-a', '-mcpu=cortex-a53', '-mfpu=neon-fp-armv8', '-mfloat-abi=hard']
cpp_link_args = ['--sysroot=/home/user/x-tools/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/sysroot', '-static']
crosstool-NG + Meson tam iş akışı
# ── ADIM 1: crosstool-NG ile musl toolchain derle ─────────────
mkdir ~/toolchains/arm-musl && cd ~/toolchains/arm-musl
ct-ng arm-unknown-linux-musleabihf
ct-ng menuconfig
# C-library → musl seç
# Target → cortex-a53, neon-fp-armv8, hard-float
ct-ng build.$(nproc)
# ── ADIM 2: pkg-config wrapper oluştur ────────────────────────
cat > ~/bin/arm-linux-musleabihf-pkg-config <<'EOF'
#!/bin/bash
SYSROOT="${HOME}/x-tools/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/sysroot"
export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig"
export PKG_CONFIG_PATH=""
exec pkg-config "$@"
EOF
chmod +x ~/bin/arm-linux-musleabihf-pkg-config
# ── ADIM 3: Meson ile cross-compile ───────────────────────────
cd ~/projects/myapp
meson setup build-musl-arm \
--cross-file arm-musl-cortex-a53.ini \
--buildtype release \
--default-library static # musl ile statik tercih et
ninja -C build-musl-arm -j$(nproc)
# ── ADIM 4: Binary boyutunu kontrol et ────────────────────────
arm-unknown-linux-musleabihf-size build-musl-arm/myapp
file build-musl-arm/myapp
# ELF 32-bit LSB executable, ARM, EABI5, statically linked
# musl statik binary — hedef sistemde hiçbir kütüphane gerektirmez
qemu-arm-static build-musl-arm/myapp
musl ile statik linklenmiş binary, hedef sistemde herhangi bir dinamik kütüphane gerektirmez. Minimal rootfs (BusyBox benzeri) kurulumlarında, güvenlik kritik uygulamalarda ve containerize edilmiş embedded sistemlerde ideal yaklaşımdır. Binary boyutu glibc dinamik'e kıyasla genellikle daha küçük olur.