Cross-Compilation & Toolchain
TEKNİK REHBER CROSS-COMPILATION PKG-CONFIG 2026

pkg-config —
cross ortamda kütüphane bulma.

PKG_CONFIG_LIBDIR ile native path sızmasını önle. Wrapper script yaz. libssl, libcurl ve zlib'i cross sysroot'tan otomatik bul.

00 pkg-config nedir — .pc dosyası anatomisi

pkg-config, bir kütüphanenin derleme bayraklarını (include path, link flags) standart bir dosya formatından okur. Build sistemleri doğrudan kütüphane yolunu sabitlemek yerine pkg-config sorgular.

Örnek .pc dosyası

/usr/lib/pkgconfig/openssl.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib/arm-linux-gnueabihf
includedir=${prefix}/include

Name: OpenSSL
Description: Secure Sockets Layer and cryptography libraries and tools
Version: 3.0.2
Requires: libssl libcrypto
Libs: -L${libdir} -lssl -lcrypto
Libs.private: -ldl -lpthread
Cflags: -I${includedir}

pkg-config sorgulama

bash
# derleme bayrakları (CFLAGS için)
pkg-config --cflags openssl
# -I/usr/include

# link bayrakları (LDFLAGS için)
pkg-config --libs openssl
# -lssl -lcrypto

# her ikisi birden
pkg-config --cflags --libs openssl
# -I/usr/include -lssl -lcrypto

# sürüm kontrolü
pkg-config --modversion openssl
# 3.0.2

# minimum sürüm kontrolü
pkg-config --atleast-version=1.1.0 openssl && echo "OK"

# gcc ile doğrudan kullanım
gcc $(pkg-config --cflags --libs openssl) -o app main.c
.pc DOSYASI KONUMU

.pc dosyaları genellikle /usr/lib/pkgconfig/, /usr/share/pkgconfig/ veya /usr/lib/<arch>/pkgconfig/ altında bulunur. Cross ortamda bunların sysroot altındaki karşılıkları okunmalıdır.

01 PKG_CONFIG_PATH vs PKG_CONFIG_LIBDIR farkı

Bu iki değişken benzer görünse de cross-compile açısından kritik bir farkları vardır. Yanlış kullanım native kütüphanelerin cross binary'ye karışmasına yol açar.

PKG_CONFIG_PATH
Varsayılan arama dizinlerine eklenen yollar. Yani varsayılan dizinler (/usr/lib/pkgconfig vb.) hâlâ aranır. Cross ortamda tehlikelidir — host sistemin .pc dosyaları sızmaya devam eder.
PKG_CONFIG_LIBDIR
Varsayılan arama dizinlerini tamamen değiştirir. Sadece bu dizinler aranır. Cross-compile'da kullanılması gereken değişken budur — host .pc dosyaları devre dışı kalır.

Karşılaştırma

bash
SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"

# YANLIŞ: PKG_CONFIG_PATH host dizinlerini hâlâ arar
export PKG_CONFIG_PATH="${SYSROOT}/usr/lib/pkgconfig"
pkg-config --libs openssl
# -lssl -lcrypto  ← hangi openssl? host mu, target mı?
# tehlike: /usr/lib/pkgconfig/openssl.pc de bulunur

# DOĞRU: PKG_CONFIG_LIBDIR yalnızca hedef sysroot'u arar
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig"
export PKG_CONFIG_PATH=""   # PATH'i boşalt
pkg-config --libs openssl
# -lssl -lcrypto  ← kesinlikle sysroot'taki openssl

# mevcut .pc dosyalarını kontrol et
ls ${SYSROOT}/usr/lib/pkgconfig/

02 PKG_CONFIG_SYSROOT_DIR — path ön eki

.pc dosyasındaki prefix=/usr satırı mutlak yol içerir. Cross ortamda bu yolun başına sysroot eklenmesi gerekir — aksi hâlde linker host sistemini arar.

Sorun ve çözüm

bash
SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"

# PKG_CONFIG_SYSROOT_DIR olmadan
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig"
pkg-config --libs zlib
# -L/usr/lib -lz  ← YANLIŞ: /usr/lib host sistemi

# PKG_CONFIG_SYSROOT_DIR ile
export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig"
export PKG_CONFIG_PATH=""
pkg-config --libs zlib
# -L${SYSROOT}/usr/lib -lz  ← DOĞRU: sysroot altındaki lib

Mekanizma açıklaması

  .pc dosyasında:  prefix=/usr
                   Libs: -L${prefix}/lib -lz

  PKG_CONFIG_SYSROOT_DIR=/home/user/.../sysroot

  pkg-config çıktısı:
    -L/home/user/.../sysroot/usr/lib -lz
          ↑
    SYSROOT_DIR + /usr/lib
    

03 pkg-config --cross-compile modu

--cross-compile bayrağı pkg-config'e cross ortamda olduğunu bildirir. Bu bayrak bazı güvenlik kontrollerini devre dışı bırakır.

bash
SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"

export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig"
export PKG_CONFIG_PATH=""

# cross-compile bayrağı ile sorgula
pkg-config --cross-compile --cflags --libs openssl

# Makefile'da kullanım
CFLAGS += $(shell PKG_CONFIG_SYSROOT_DIR=${SYSROOT} \
              PKG_CONFIG_LIBDIR=${SYSROOT}/usr/lib/pkgconfig \
              PKG_CONFIG_PATH= \
              pkg-config --cross-compile --cflags openssl)

LDFLAGS += $(shell PKG_CONFIG_SYSROOT_DIR=${SYSROOT} \
               PKG_CONFIG_LIBDIR=${SYSROOT}/usr/lib/pkgconfig \
               PKG_CONFIG_PATH= \
               pkg-config --cross-compile --libs openssl)
NOT

--cross-compile, pkg-config'in Libs.private alanındaki -I ve -L path'lerindeki doğruluğu kontrol etmesini atlar. Cross ortamda bu kontrolün false positive vermesi engellenir.

04 Wrapper script — arm-linux-gnueabihf-pkg-config

Her sorguda ortam değişkenlerini elle yazmak yerine, cross toolchain için özel bir pkg-config wrapper scripti oluşturmak en temiz çözümdür. Birçok build sistemi PKG_CONFIG değişkeni ile bu scripti kullanır.

Wrapper scripti

~/bin/arm-linux-gnueabihf-pkg-config
#!/bin/bash
# pkg-config wrapper — ARM Cortex-A53 cross ortamı
# Kullanım: PKG_CONFIG=arm-linux-gnueabihf-pkg-config cmake ...

SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"

export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig"
export PKG_CONFIG_PATH=""

exec pkg-config "$@"
bash
# çalıştırma izni ver ve PATH'e ekle
chmod +x ~/bin/arm-linux-gnueabihf-pkg-config
export PATH="${HOME}/bin:${PATH}"

# test
arm-linux-gnueabihf-pkg-config --libs openssl
# -L/home/.../sysroot/usr/lib -lssl -lcrypto

# build sistemlerine bildir
export PKG_CONFIG=arm-linux-gnueabihf-pkg-config

# configure script ile kullanım
PKG_CONFIG=arm-linux-gnueabihf-pkg-config \
    ./configure --host=arm-unknown-linux-gnueabihf

# CMake ile kullanım
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
      -DPKG_CONFIG_EXECUTABLE=$(which arm-linux-gnueabihf-pkg-config) \
      ..

05 Ortak sorunlar — native path sızması

Cross-compile sırasında en sık karşılaşılan sorun, host sistemin kütüphanelerinin hedef binary'ye karışmasıdır. Bu genellikle linker hatası veya çalışma zamanı hatası olarak ortaya çıkar.

Teşhis yöntemleri

bash
# binary'nin bağlı olduğu kütüphaneleri kontrol et
arm-linux-gnueabihf-readelf -d ./app | grep NEEDED
# 0x00000001 (NEEDED) Shared library: [libssl.so.3]
# 0x00000001 (NEEDED) Shared library: [libc.so.6]

# dynamic interpreter'ı kontrol et (ARM olmalı)
arm-linux-gnueabihf-readelf -l ./app | grep interpreter
# [Requesting program interpreter: /lib/ld-linux-armhf.so.3]  ← DOĞRU
# [Requesting program interpreter: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2]  ← YANLIŞ

# pkg-config hangi .pc dosyasını okuduğunu göster
PKG_CONFIG_DEBUG_SPEW=1 pkg-config --libs openssl 2>&1 | grep "File"

# mevcut tüm .pc dizinlerini listele
pkg-config --variable pc_path pkg-config

Sızma nedenleri ve çözümleri

PKG_CONFIG_PATH içinde host dizini
Çözüm: export PKG_CONFIG_PATH="" — PATH'i tamamen boşalt.
PKG_CONFIG_LIBDIR ayarlanmamış
Varsayılan dizinler (/usr/lib/pkgconfig) aranmaya devam eder. Çözüm: LIBDIR'i sysroot'a ayarla.
PKG_CONFIG_SYSROOT_DIR eksik
.pc dosyasındaki mutlak yollar sysroot ön eki almaz. -L/usr/lib host'u işaret eder.
CMake'in kendi pkg-config çağrısı
CMake bazen wrapper scripti yok sayar. PKG_CONFIG_EXECUTABLE değişkeni ile zorla.

06 CMake FIND_PACKAGE ile pkg-config entegrasyonu

CMake'in PkgConfig modülü, pkg-config sorgularını CMake target'larına dönüştürür. Cross ortamda toolchain.cmake ile birlikte kullanılır.

CMakeLists.txt — pkg-config kullanımı

CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(myapp C)

# pkg-config modülünü yükle
find_package(PkgConfig REQUIRED)

# openssl bul
pkg_check_modules(OPENSSL REQUIRED openssl>=1.1.0)

# curl bul
pkg_check_modules(CURL REQUIRED libcurl>=7.68.0)

add_executable(myapp main.c)

# include ve link bayrakları otomatik eklenir
target_include_directories(myapp PRIVATE
    ${OPENSSL_INCLUDE_DIRS}
    ${CURL_INCLUDE_DIRS}
)

target_link_libraries(myapp PRIVATE
    ${OPENSSL_LIBRARIES}
    ${CURL_LIBRARIES}
)

# IMPORTED target kullanımı (daha modern)
pkg_check_modules(ZLIB REQUIRED IMPORTED_TARGET zlib)
target_link_libraries(myapp PRIVATE PkgConfig::ZLIB)

toolchain.cmake — pkg-config ayarları

toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CROSS_TRIPLE "arm-unknown-linux-gnueabihf")
set(TOOLCHAIN_DIR "$ENV{HOME}/x-tools/${CROSS_TRIPLE}")
set(SYSROOT "${TOOLCHAIN_DIR}/${CROSS_TRIPLE}/sysroot")

set(CMAKE_C_COMPILER   "${TOOLCHAIN_DIR}/bin/${CROSS_TRIPLE}-gcc")
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_DIR}/bin/${CROSS_TRIPLE}-g++")
set(CMAKE_SYSROOT "${SYSROOT}")

# pkg-config wrapper
set(PKG_CONFIG_EXECUTABLE "$ENV{HOME}/bin/arm-linux-gnueabihf-pkg-config"
    CACHE STRING "pkg-config wrapper for ARM cross-compile" FORCE)

# cmake'e sysroot path'i bildir
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} "")

07 Pratik: libssl ve libcurl için cross .pc dosyası

Sysroot'ta .pc dosyası yoksa ya da yanlışsa, elle oluşturmak gerekebilir. Özellikle hedef rootfs'ten kopyalanan kütüphaneler için bu durum yaygındır.

Sysroot'a kütüphane kopyalama

bash
SYSROOT="${HOME}/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot"
TARGET_ROOT="/mnt/rpi-rootfs"   # mount edilmiş hedef rootfs

# OpenSSL kütüphane ve başlıklarını kopyala
mkdir -p ${SYSROOT}/usr/include/openssl
mkdir -p ${SYSROOT}/usr/lib/pkgconfig

cp -r ${TARGET_ROOT}/usr/include/openssl/ ${SYSROOT}/usr/include/
cp ${TARGET_ROOT}/usr/lib/arm-linux-gnueabihf/libssl.so* ${SYSROOT}/usr/lib/
cp ${TARGET_ROOT}/usr/lib/arm-linux-gnueabihf/libcrypto.so* ${SYSROOT}/usr/lib/
cp ${TARGET_ROOT}/usr/lib/arm-linux-gnueabihf/pkgconfig/openssl.pc ${SYSROOT}/usr/lib/pkgconfig/

Manuel .pc dosyası oluşturma

${SYSROOT}/usr/lib/pkgconfig/openssl.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: OpenSSL
Description: Secure Sockets Layer and cryptography libraries
Version: 3.0.2
Requires: libssl libcrypto
Libs: -L${libdir} -lssl -lcrypto
Cflags: -I${includedir}
${SYSROOT}/usr/lib/pkgconfig/libcurl.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: libcurl
Description: Library to transfer files with ftp, http, etc.
Version: 7.81.0
Libs: -L${libdir} -lcurl
Libs.private: -lssl -lcrypto -lz -lpthread
Cflags: -I${includedir}

Doğrulama

bash
export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig"
export PKG_CONFIG_PATH=""

pkg-config --modversion openssl
# 3.0.2

pkg-config --cflags --libs openssl
# -I${SYSROOT}/usr/include -L${SYSROOT}/usr/lib -lssl -lcrypto

# derleme testi
arm-unknown-linux-gnueabihf-gcc \
    $(pkg-config --cflags --libs openssl) \
    -o ssl_test ssl_test.c

08 Static linking — --static bayrağı

Bazı embedded sistemlerde dinamik kütüphaneleri dağıtmak yerine statik link tercih edilir. pkg-config, --static ile statik linking için bayraklar sağlar.

--static bayrağı ile sorgulama

bash
# dinamik linking için bayraklar
pkg-config --libs openssl
# -lssl -lcrypto

# statik linking için bayraklar (Libs.private dahil)
pkg-config --static --libs openssl
# -lssl -lcrypto -ldl -lpthread
# (statik link için tüm bağımlılıklar listelenir)

Statik binary derleme

bash
CROSS=arm-unknown-linux-gnueabihf
SYSROOT="${HOME}/x-tools/${CROSS}/${CROSS}/sysroot"

export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig"
export PKG_CONFIG_PATH=""

# statik bağlantılı binary
${CROSS}-gcc \
    --sysroot=${SYSROOT} \
    -static \
    $(pkg-config --static --cflags --libs openssl) \
    -o app_static main.c

# dinamik bağımlılık yok mu kontrol et
${CROSS}-readelf -d app_static | grep NEEDED
# (boş çıktı — bağımlılık yok)

# QEMU'da dinamik linker gerektirmeden çalıştır
qemu-arm-static app_static

Yocto sysroot'unu elle kullanmak

bash
# Yocto SDK sysroot'u genellikle bu konumdadır:
YOCTO_SDK="/opt/poky/4.0.15/sysroots"
YOCTO_SYSROOT="${YOCTO_SDK}/cortexa53-poky-linux"

# pkg-config'i Yocto sysroot'u ile kullan
export PKG_CONFIG_SYSROOT_DIR="${YOCTO_SYSROOT}"
export PKG_CONFIG_LIBDIR="${YOCTO_SYSROOT}/usr/lib/pkgconfig:\
${YOCTO_SYSROOT}/usr/share/pkgconfig"
export PKG_CONFIG_PATH=""

# Yocto'da çapraz derleyici
export CC="${YOCTO_SDK}/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux-gcc"

pkg-config --list-all | head -20
# Yocto'nun sysroot'undaki tüm kütüphaneler listelenir
YOCTO SDK SETUP

Yocto SDK kurulum scripti (environment-setup-cortexa53-poky-linux) tüm bu değişkenleri otomatik ayarlar. source komutuyla yükle: source /opt/poky/4.0.15/environment-setup-cortexa53-poky-linux. Kendi toolchain'in için aynı yaklaşımı uygulayabilirsin.