00 CMake cross-compile mimarisi
CMake'in cross-compile desteği, toolchain dosyası adı verilen özel bir CMake scripti üzerinden çalışır. Bu dosya cmake konfigürasyonu başlamadan önce okunur ve tüm compiler/linker ayarlarını belirler.
Akış
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
│
↓
toolchain.cmake yüklenir
┌────────────────────────────────────────────────┐
│ CMAKE_SYSTEM_NAME = Linux │
│ CMAKE_SYSTEM_PROCESSOR = arm │
│ CMAKE_C_COMPILER = arm-...-gcc │
│ CMAKE_SYSROOT = /path/to/sysroot │
│ CMAKE_FIND_ROOT_PATH = ... │
└────────────────────────────────────────────────┘
│
↓
CMakeLists.txt okunur
Compiler testi (CMakeCCompiler.cmake)
find_package() / find_library() çağrıları →
FIND_ROOT_PATH içinde arar
│
↓
Makefile / Ninja dosyaları üretilir
CMake'in tespit ettiği değişkenler
# cmake konfigürasyon sonrası kontrol et
cmake --build . --verbose 2>&1 | head -5
# ya da
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
-DCMAKE_VERBOSE_MAKEFILE=ON \
..
# cache'e yazılan değerleri göster
cmake -L .. | grep CMAKE_C_COMPILER
# CMAKE_C_COMPILER:FILEPATH=/home/.../arm-unknown-linux-gnueabihf-gcc
01 toolchain.cmake — temel değişkenler
Toolchain dosyasının çekirdeği birkaç zorunlu değişkenden oluşur. Bunlar cmake'e hedef sistem ve derleyici hakkında bilgi verir.
Minimal toolchain.cmake
# ─── Hedef sistem ─────────────────────────────────────────────
# CMAKE_SYSTEM_NAME: çapraz derleme hedefinin OS adı
# Linux, Windows, Darwin, Android, iOS, Generic (bare-metal)
set(CMAKE_SYSTEM_NAME Linux)
# CMAKE_SYSTEM_PROCESSOR: hedef CPU mimarisi
# arm, aarch64, riscv64, x86_64
set(CMAKE_SYSTEM_PROCESSOR arm)
# ─── Derleyiciler ─────────────────────────────────────────────
set(CROSS_TRIPLE "arm-unknown-linux-gnueabihf")
set(TOOLCHAIN_BIN "$ENV{HOME}/x-tools/${CROSS_TRIPLE}/bin")
set(CMAKE_C_COMPILER "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-gcc")
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-g++")
set(CMAKE_ASM_COMPILER "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-as")
# ─── Araçlar ──────────────────────────────────────────────────
set(CMAKE_AR "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-ar" CACHE FILEPATH "" FORCE)
set(CMAKE_RANLIB "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-ranlib" CACHE FILEPATH "" FORCE)
set(CMAKE_STRIP "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-strip" CACHE FILEPATH "" FORCE)
set(CMAKE_OBJCOPY "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-objcopy" CACHE FILEPATH "" FORCE)
CMAKE_SYSTEM_NAME'i ayarlamak cmake'e cross-compile modunda olduğunu söyler. Bu değişken ayarlandığında CMAKE_CROSSCOMPILING otomatik olarak TRUE olur. Bunu CMakeLists.txt'te kontrol ederek platform-spesifik kod dalları oluşturabilirsin.
02 CMAKE_SYSROOT ve CMAKE_FIND_ROOT_PATH
Bu iki değişken, cmake'in hedef sisteme ait başlık ve kütüphaneleri nerede arayacağını belirler.
--sysroot bayrağı olarak geçirilir. Hem derleme hem link aşamasını etkiler. find_library() ve find_path() bu kök altında arar.set(CROSS_TRIPLE "arm-unknown-linux-gnueabihf")
set(SYSROOT "$ENV{HOME}/x-tools/${CROSS_TRIPLE}/${CROSS_TRIPLE}/sysroot")
# --sysroot derleyici bayrağı
set(CMAKE_SYSROOT "${SYSROOT}")
# find_*() için kök dizinler
set(CMAKE_FIND_ROOT_PATH
"${SYSROOT}"
"${SYSROOT}/usr"
)
# staging: cross-derlenen kütüphanelerin geçici kurulum yeri
set(CMAKE_STAGING_PREFIX "$ENV{HOME}/staging/arm-cortex-a53")
03 FIND_ROOT_PATH_MODE — arama politikası
Cross-compile'da cmake'e bazı şeylerin host'ta, bazılarının target'ta aranması gerektiğini söylemek gerekir. FIND_ROOT_PATH_MODE değişkenleri bunu kontrol eder.
NEVER: çalıştırılabilir araçları (gcc, python vb.) HOST'ta ara. Cross ortamda standart ayar.ONLY: kütüphaneleri yalnızca FIND_ROOT_PATH içinde ara. Host kütüphanelerini dışarıda bırakır.ONLY: başlık dosyalarını yalnızca FIND_ROOT_PATH içinde ara.ONLY: CMake package config dosyalarını yalnızca FIND_ROOT_PATH içinde ara.# programlar (araçlar) host'ta aransın
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# kütüphane ve başlıklar yalnızca target sysroot'ta aransın
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
BOTH değeri hem host hem target'ta arar — güvensiz ama bazen host araçlarına hedeften erişim gerektiğinde kullanılır. Genellikle yalnızca PROGRAM için BOTH mantıklıdır.
04 cmake -DCMAKE_TOOLCHAIN_FILE ile geç
Toolchain dosyası cmake komutuna -DCMAKE_TOOLCHAIN_FILE parametresiyle verilir. Bu parametre her zaman ilk cmake çağrısında belirtilmelidir — cache temizlenmeden değiştirilemez.
Kullanım
mkdir -p build-arm && cd build-arm
cmake \
-DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-cortex-a53.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
..
cmake --build . -- -j$(nproc)
# hangi derleyicinin kullanıldığını doğrula
cmake -L . | grep CMAKE_C_COMPILER
# CMAKE_C_COMPILER:FILEPATH=.../arm-unknown-linux-gnueabihf-gcc
Preset ile toolchain (CMake 3.19+)
{
"version": 3,
"configurePresets": [
{
"name": "arm-cortex-a53",
"displayName": "ARM Cortex-A53 Cross Compile",
"description": "arm-unknown-linux-gnueabihf cross compilation",
"toolchainFile": "${sourceDir}/cmake/toolchain-arm-cortex-a53.cmake",
"binaryDir": "${sourceDir}/build-arm",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INSTALL_PREFIX": "/usr"
}
},
{
"name": "riscv64",
"displayName": "RISC-V 64-bit Cross Compile",
"toolchainFile": "${sourceDir}/cmake/toolchain-riscv64.cmake",
"binaryDir": "${sourceDir}/build-riscv64"
}
]
}
# preset ile kullanım
cmake --preset arm-cortex-a53
cmake --build --preset arm-cortex-a53
05 ExternalProject_Add ile bağımlılık
ExternalProject_Add, bağımlı projeyi cross toolchain ile indirip derler. Cross-compiled bağımlılıkları staging prefix'e kurarak ana projenin bulmasını sağlar.
include(ExternalProject)
set(STAGING_DIR "$ENV{HOME}/staging/arm-cortex-a53")
# zlib'i cross-compile et
ExternalProject_Add(zlib_cross
URL https://zlib.net/zlib-1.3.1.tar.gz
URL_HASH SHA256=9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_INSTALL_PREFIX=${STAGING_DIR}
-DCMAKE_BUILD_TYPE=Release
BUILD_BYPRODUCTS
${STAGING_DIR}/lib/libz.a
)
# ana proje zlib'e bağımlı olsun
add_executable(myapp main.c)
add_dependencies(myapp zlib_cross)
target_include_directories(myapp PRIVATE ${STAGING_DIR}/include)
target_link_libraries(myapp PRIVATE ${STAGING_DIR}/lib/libz.a)
FetchContent ile alternatif
include(FetchContent)
FetchContent_Declare(
zlib
URL https://zlib.net/zlib-1.3.1.tar.gz
URL_HASH SHA256=9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23
)
FetchContent_MakeAvailable(zlib)
add_executable(myapp main.c)
# zlib CMakeLists.txt'i otomatik bulunur — cross toolchain ile derlenir
target_link_libraries(myapp PRIVATE zlibstatic)
FetchContent, bağımlılığı ana projeye dahil eder (configure zamanında). ExternalProject bağımsız bir build oluşturur (build zamanında). Cross-compile için ExternalProject daha güvenlidir — bağımlılık kesinlikle aynı toolchain ile derlenir.
06 Cross install — DESTDIR
DESTDIR, install prefix'inin önüne geçici bir kök dizin ekler. Hedef dosya sistemine veya sysroot'a kurmak için kullanılır.
DESTDIR ile install
SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"
# cmake ile install prefix /usr, DESTDIR ile sysroot altına kurulur
cmake \
-DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
..
cmake --build . -- -j$(nproc)
# DESTDIR: dosyalar ${DESTDIR}/${CMAKE_INSTALL_PREFIX} altına gider
DESTDIR="${SYSROOT}" cmake --install .
# sonuç: dosyalar ${SYSROOT}/usr/lib, ${SYSROOT}/usr/include altında
ls ${SYSROOT}/usr/lib/libmylib.a
Makefile ile DESTDIR
# autotools ile DESTDIR kullanımı da aynı
make DESTDIR="${SYSROOT}" install
# meson ile
DESTDIR="${SYSROOT}" ninja install
07 Pratik: ARM Cortex-A53 tam toolchain.cmake
Gerçek dünya kullanımı için eksiksiz toolchain.cmake dosyası — pkg-config, CPU bayrakları ve install prefix dahil.
# ════════════════════════════════════════════════════════════
# ARM Cortex-A53 Cross-Compile Toolchain
# Kullanım: cmake -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-cortex-a53.cmake ..
# ════════════════════════════════════════════════════════════
# ─── Hedef sistem ─────────────────────────────────────────────
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# ─── Toolchain yolu ───────────────────────────────────────────
set(CROSS_TRIPLE "arm-unknown-linux-gnueabihf")
set(TOOLCHAIN_ROOT "$ENV{HOME}/x-tools/${CROSS_TRIPLE}")
set(TOOLCHAIN_BIN "${TOOLCHAIN_ROOT}/bin")
set(SYSROOT "${TOOLCHAIN_ROOT}/${CROSS_TRIPLE}/sysroot")
# ─── Derleyiciler ─────────────────────────────────────────────
set(CMAKE_C_COMPILER "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-gcc")
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-g++")
set(CMAKE_ASM_COMPILER "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-gcc")
# ─── Araçlar ──────────────────────────────────────────────────
set(CMAKE_AR "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-ar" CACHE FILEPATH "" FORCE)
set(CMAKE_RANLIB "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-ranlib" CACHE FILEPATH "" FORCE)
set(CMAKE_STRIP "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-strip" CACHE FILEPATH "" FORCE)
set(CMAKE_OBJCOPY "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-objcopy" CACHE FILEPATH "" FORCE)
set(CMAKE_OBJDUMP "${TOOLCHAIN_BIN}/${CROSS_TRIPLE}-objdump" CACHE FILEPATH "" FORCE)
# ─── CPU bayrakları ───────────────────────────────────────────
set(CPU_FLAGS "-march=armv8-a -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
set(CMAKE_C_FLAGS_INIT "${CPU_FLAGS}")
set(CMAKE_CXX_FLAGS_INIT "${CPU_FLAGS}")
# ─── Sysroot ──────────────────────────────────────────────────
set(CMAKE_SYSROOT "${SYSROOT}")
set(CMAKE_FIND_ROOT_PATH
"${SYSROOT}"
"${SYSROOT}/usr"
"$ENV{HOME}/staging/arm-cortex-a53"
)
# ─── Arama politikası ─────────────────────────────────────────
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)
# ─── pkg-config ───────────────────────────────────────────────
set(PKG_CONFIG_EXECUTABLE "$ENV{HOME}/bin/arm-linux-gnueabihf-pkg-config"
CACHE STRING "" FORCE)
set(ENV{PKG_CONFIG_SYSROOT_DIR} "${SYSROOT}")
set(ENV{PKG_CONFIG_LIBDIR}
"${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig")
set(ENV{PKG_CONFIG_PATH} "")
# ─── Staging prefix ───────────────────────────────────────────
set(CMAKE_STAGING_PREFIX "$ENV{HOME}/staging/arm-cortex-a53")
Kullanım
mkdir build-arm && cd build-arm
cmake \
-DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-arm-cortex-a53.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
..
cmake --build . -j$(nproc)
# sysroot'a kur
DESTDIR="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot" \
cmake --install .
08 Qt cross-compile ipuçları
Qt 6 cross-compile için cmake tabanlı yeni sistemin birkaç ek değişkeni vardır. Qt 5'ten farklı olarak ayrı host Qt kurulumu gerektirir.
Qt6 cross-compile ön koşulları
# 1. Host Qt kurulumu (moc, rcc, uic araçları için)
sudo apt install qt6-base-dev qt6-tools-dev
# 2. Hedef sysroot'ta Qt kütüphaneleri (RPi rootfs'ten kopyala)
rsync -avz pi@rpi:/usr/lib/aarch64-linux-gnu/libQt6*.so* \
${SYSROOT}/usr/lib/
rsync -avz pi@rpi:/usr/include/aarch64-linux-gnu/qt6/ \
${SYSROOT}/usr/include/qt6/
Qt6 toolchain.cmake eklentisi
# Qt6 cross-compile için ek değişkenler
# Üst toolchain dosyasını dahil et
include("${CMAKE_CURRENT_LIST_DIR}/toolchain-arm-cortex-a53.cmake")
# Host Qt araçlarını belirt
set(QT_HOST_PATH "/usr" CACHE PATH "Host Qt installation")
set(QT_HOST_PATH_CMAKE_DIR "${QT_HOST_PATH}/lib/cmake")
# Qt'un platform plugin'ini belirt
set(QT_QMAKE_TARGET_MKSPEC "linux-aarch64-gnu-g++")
# Qt6 projesini cross-compile et
cmake \
-DCMAKE_TOOLCHAIN_FILE=toolchain-qt6-arm.cmake \
-DQT_HOST_PATH=/usr \
-DCMAKE_BUILD_TYPE=Release \
..
cmake --build . -j$(nproc)
09 Hunter ve Conan ile cross bağımlılık yönetimi
Hunter ve Conan, CMake projelerinde bağımlılık yönetimini otomatikleştiren araçlardır. Her ikisi de cross-compile desteği sunar ancak yaklaşımları farklıdır.
Hunter ile cross-compile
cmake_minimum_required(VERSION 3.20)
# Hunter bootstrap
include("cmake/HunterGate.cmake")
HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.24.18.tar.gz"
SHA1 "1292e4d661e1770d6d6ca08c12c722a83b58eac2"
)
project(myapp C CXX)
# Hunter paketi iste — cross toolchain ile otomatik derlenir
hunter_add_package(OpenSSL)
hunter_add_package(ZLIB)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE OpenSSL::SSL ZLIB::ZLIB)
# Hunter, toolchain dosyasını otomatik propagate eder
cmake \
-DCMAKE_TOOLCHAIN_FILE=toolchain-arm-cortex-a53.cmake \
-DCMAKE_BUILD_TYPE=Release \
..
# Hunter, OpenSSL ve ZLIB'i ARM için otomatik derler
Conan ile cross-compile
[requires]
openssl/3.1.3
zlib/1.3.1
libcurl/8.4.0
[generators]
CMakeToolchain
CMakeDeps
[settings]
os=Linux
arch=armv8
compiler=gcc
compiler.version=13
compiler.libcxx=libstdc++11
build_type=Release
# cross-compile profili oluştur
mkdir -p ~/.conan2/profiles
cat > ~/.conan2/profiles/arm-cortex-a53 <<'EOF'
[settings]
os=Linux
arch=armv8
compiler=gcc
compiler.version=13
compiler.libcxx=libstdc++11
build_type=Release
[env]
CC=arm-unknown-linux-gnueabihf-gcc
CXX=arm-unknown-linux-gnueabihf-g++
CFLAGS=-mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard
CXXFLAGS=-mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard
EOF
# bağımlılıkları derle
conan install . \
--profile:host=arm-cortex-a53 \
--profile:build=default \
--output-folder=build-arm \
--build=missing
# cmake ile derle
cd build-arm
cmake \
-DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release \
..
cmake --build . -j$(nproc)
Hunter tamamen CMake tabanlıdır, ek araç gerektirmez. Conan daha geniş paket ekosistemi sunar ve profesyonel ortamlarda yaygındır. Küçük projeler için Hunter, büyük organizasyonlarda Conan tercih edilir. Her ikisi de cross-compile toolchain'ini doğru kullandığınızda bağımlılıkları hedef mimari için derler.