Çapraz Derleme ve Gerekli Ekipmanlar
Sistemimizde kullandığımız standart derleme araçları (gcc, g++ vb.) normal olarak aynı sistemde çalışacak obje kodları üretir. Derlenen uygulamada kullanılan kütüphaneler ve başlık dosyalarını öncesinde sistemde yer alır, derleme ve linkleme işlemi bu doğrultuda gerçekleşir. Sonrasında uygulama ilgili sistemde çalıştırılır.
Çapraz Derleme (Cross Compiling) sürecinde ise derleme işlemi sonucunda üretilecek obje kodlarının, işlemin yapıldığı sistemden bağımsız olarak başka bir hedef sistemde çalışması beklenir.
Derleme işleminin yapıldığı sistem host, derleme sonucunda oluşturulacak uygulamaların çalışacağı sistem ise target olarak isimlendirilir.
Örnek olarak Linux çalışan 64 bitlik X86 ailesi kişisel bilgisayarınızda ARM veya Windows platformu için derleme yaptığınızda, bilgisayarınız host, derleme sürecinin hedefi olan platform (örneğimizde ARM veya Windows) target olacaktır.
Bir hedef platform için çapraz derleme işlemini yapabilmek, sisteminizde ilgili hedef platform için obje kodları üretecek derleyici (gcc, g++), obje kodları üzerinde işlem yapabilecek çeşitli binary araçları (objdump, objcopy, readelf, strip vb.), temel C kütüphanesi ve ilgili başlık dosyalarının kurulu olmasını gerektirir. İşte tüm bu topluluk Toolchain olarak adlandırılır.
Toolchain Türleri ve İsimlendirme
Toolchain'ler genel olarak, ilgili hedef platformu tanımlayan bir ön ek ile isimlendirilirler. Örneğin ARM platformu için arm-linux ön eki kullanılabilir. Toolchain içerisinden çıkan tüm araçlarda bu ön ek bulunur: arm-linux-gcc, arm-linux-g++, arm-linux-as, arm-linux-objcopy vb.
Derleyicinin mutlaka gcc ailesi olması da gerekmez. Örneğin Linux bilgisayarınızda 32 bit Windows hedefli uygulama derlemek istiyorsanız, kullanacağınız C derleyicisi i686-w64-mingw32 olacaktır.
Çeşitli projelerde çalışırken toolchain isimlendirmelerinde kafa karıştırıcı durumlarla karşılaşabilirsiniz. Örnek olarak aşağıdaki toolchain isimlerini ele alalım:
- arm-linux
- arm-none-linux-gnueabi
- arm-fsl-linux-gnueabi
- arm-none-eabi
- arm-linux-gnueabihf
Toolchain isimlendirmelerinde genellikle arch [-vendor] [-os] - eabi
sistematiği takip edilir. Örneğin arm-none-linux-gnueabi toolchain'i için hedef mimari arm, üretici belirtilmemiş o yüzden none, işletim sistemi linux ve ABI versiyonu gnueabi olarak belirtilmek istenmiştir. Bu toolchain ile ARM Linux EABI binary formatında dosyaları üretebileceğimizi düşünebiliriz.
Diğer bir örneğe baktığımızda üretici alanında fsl ibaresini görmekteyiz. Bu da bize ilgili toolchain'in FreeScale firması tarafından üretildiğini gösteriyor.
Arm-none-eabi örneği ise diğerlerinden biraz daha farklı bir yerde duruyor, içerisinde hiç linux ibaresi geçmiyor yani işletim sistemi kısmı yok. Bu toolchain işletim sistemi olmayan bir ortamda doğrudan ARM işlemci üzerinde koşacak kodların üretimi için kullanılacaktır. Dolayısıyla bu toolchain ile kod üretirken harici kütüphaneler kullanmak ve linklemek (dinamik veya statik) mümkün olmayacaktır.
Arm-linux-gnueabihf toolchain'indeki hf ibaresi, ABI tipini göstermekte olup aşağıda bu konuya değinilmiştir.
Toolchain ABI (OABI, EABI)
Toolchain isimlendirmelerinde karşılaşabileceğiniz, oabi, eabi ve eabihf ibareleri, özellikle günümüzde popüler olan ARM platformları için Application Binary Interface'in ne olduğunu göstermektedir.
OABI, ARM platformu için kullanılan ilk ABI versiyonudur. OABI, ilgili sistemin kayar noktalı işlemleri hızlı yapabilmek için bir Floating Point Unit'e sahip olduğunu varsayar. Dolayısıyla böyle bir toolchain ile üretilecek olan obje kodlarında FPU Instruction'ları yer alacaktır.
Ancak özellikle ilk üretilen ARM platformlarında herhangi bir FPU birimi bulunmamaktaydı. Bu nedenle ilgili toolchain'ler üzerinden elde edilmiş olan uygulamalar, işlemcinin desteklemediği FPU Instruction'larını ürettiğinde CPU Exception durumu oluşmaktaydı.
İşlemci mimarilerinde exception ve interrupt mekanizmaları, beklenmedik bir olay ile normal akışı kesintiye uğratıp farklı bir şekilde ilerlenmesini sağlar.
Genel olarak exception durumu CPU içerisinde beklenmedik bir durumun oluşmasını, interrupt ise CPU dışında beklenmedik bir olay nedeniyle ortaya çıkar.
İlgili CPU mimarisi, Exception Handling için bir mekanizma tanımlamış ise, oluşan exception durumlarında sistemin çakılmasını engellemek ve bu durumu yönetmek mümkündür.
Exception durumları aşağıdaki olaylarda oluşur:
- Aritmetik işlemler sonucunda elde edilen değerin register'a sığmaması ve taşma durumu
- İşletim sistemi tarafından tetiklenen sistem çağrıları
- CPU tarafından bilinmeyen bir instruction gelmesi
OABI toolchain ile derlenmiş uygulamalar ARM mimarisinde bu üçüncü durumu sıklıkla oluştururlar. CPU tarafından exception üretilir ve bu exception sistemin çakılmasını engellemek için Linux çekirdeği içerisinde, FPU instruction'ları yazılım yoluyla emüle edilir. Böylelikle sistemin çakılması engellenmiş olur.
Ancak bu süreç beraberinde önemli bir performans maliyeti de getirmektedir. Özellikle kayan nokta işlemlerinin sık kullanıldığı uygulamalarda sürekli bu şekilde CPU Exception üretimi ve bunun çekirdek tarafından emülasyonunun yapılması, context-switch nedeniyle performansı ciddi oranda düşürmektedir.
EABI, ARM platformu için yeni ABI versiyonudur. Yukarıda bahsedilen context-switch kaynaklı performans sorununu, emülasyon işlemini kullanıcı kipinde yapmak suretiyle çözmektedir. EABI için hazırlanmış toolchain'lerin ürettiği obje kodları içerisinde asla FPU Instruction'ları yer almaz. Bunun yerine ilgili Instruction'lar, derleme sürecinde ayrı fonksiyonlarla emüle edilirler. Bu şekilde üretilmiş bir uygulama hiç bir FPU Instruction üretmediğinden, CPU Exception durumu oluşmayacak, context-switch gerçekleşmeyecek ve çekirdek seviyesinde bu nedenle bir exception handling ve emülasyon yapılmak zorunda kalmayacaktır.
EABI toolchain'leri içerisinde bu destek ön tanımlı olarak aktive edilmiş olabileceği gibi, -mfloat-abi=soft
şeklindeki derleyici parametresi ile de seçilebilmektedir. Yapılan testlerde FPU Instruction'ları yoğun kullanan uygulamaların, çekirdek seviyesinde emülasyon yerine kullanıcı kipinde bu şekilde emüle edilmesi halinde, 5 - 20 kat arası hızlanma sağladığı görülmüştür.
Yeni nesil ARM işlemcilerinde ise bu durum değişmeye başlamıştır. Çeşitli kayan nokta işlemlerini hızlandırmak için farklı bir instruction kümesine sahip olan Vector Floating Point birimi ve sonrasında da özellikle matris ve vektör işlemlerini hızlandıran NEON birimi işlemcilerde kullanılmaya başlanmıştır. Donanım tarafında sağlanan bu destekler, -mfloat-abi=soft
şeklinde derlenmiş olan uygulamalar için herhangi bir ek fayda sağlamayacaktır. Bu nedenle EABI için hard floating point destekli, eabihf toolchain'leri ortaya çıkmıştır.
Donanımınızın desteklemesi halinde sisteminizde yer alan tüm bileşenlerin (kütüphaneler ve uygulamalar) eabihf toolchain'i tarafından derlenmesi halinde, önemli oranda performans kazanımı elde edilebilmektedir. eabihf toolchain'lerinde -mfpu=vfp
veya -mfpu=neon
derleyici parametreleri ile donanımıza özgü hızlandırmaları aktive edebilirsiniz.
NOT: ABI versiyonları için verdiğimiz örnekler ARM mimarisi için geçerlidir. Farklı mimarilerde farklı ABI'ler bulunmaktadır. Örneğin MIPS için o32, o64, n32 ve n64 olmak üzere 4 farklı ABI bulunmaktadır. Çok daha eski bir mimari olmasına rağmen, bunun gibi pek çok dokümanda örnek olarak dahi yer alamıyor olması, ARM mimarisinin gömülü Linux sistemler pazarındaki hakimiyetine dair fikir verebilir. Her geçen yıl bu fark açılmaktadır.
Toolchain Edinme
Toolchain'ler hazır biçimde indirilip kullanılabileceği gibi, sıfırdan bir toolchain üretmek de mümkündür.
Toolchain üretimi oldukça zahmetli ve uzun zaman alan bir süreçtir. Bu süreci kolaylaştırmayı amaçlayan, crosstool
ve crosstool-ng
projeleri bulunmakla birlikte çoğu durumda hazır bir toolchain ile projelere devam edilmesi önerilir.
Kendi ürettiğiniz toolchain üzerinden ilgili mimari için üretilen kodlarda herhangi bir sıkıntı var ise, bunun algılanması ve çözülmesi çok ciddi zaman kayıpları getirebilir. Daha da kötüsü, geliştirme ortamında her şey yolundaymış gibi görünürken, proje sahaya çıktıktan sonra kaotik durumlar ile karşılaşabilirsiniz.
Hazır bir toolchain kullandığınızda böyle bir sorunla karşılaşma riskiniz çok daha düşüktür. Zira aynı toolchain tüm dünyada pek çok projede kullanıldığından, toolchain'in kendisinde bir problem varsa bunun tespit edilmesi ve düzeltilmesi kolay olacaktır. Ayrıca donanımın üreticisi tarafından uzun zaman test edilmiş ve müşterilere önerilen bir toolchain versiyonu varsa, elbette onun kullanılması da uygun olacaktır.
Peki ne zaman sıfırdan bir toolchain üretmek anlamlı olabilir?
Öncelikle söylemek gerekir ki, yukarıda özel toolchain üretiminin dezavantajları adına söylediklerimiz donanım üreticileri için de geçerlidir. Onlar da tüm bu ekosistem tarafından üretilen bilgi birikimini kullanmak ve kendi toolchain bazında kendilerine özgü bir problemi satın almamamak isterler.
Fakat bazen donanım üreticisinden gelen toolchain versiyonu çok eski olabilir. İçerisinden çıkan glibc
standart C kitaplığının versiyonu çok düşük ise, alışageldiğiniz bazı fonksiyonları bulamayacağınızdan geliştirme yaparken bir miktar konfor kaybına uğrayabilirsiniz.
Örneğin glibc 2.5 versiyonu kullanılıyorsa, asprinf()
fonksiyonu C kitaplığında yer almayacaktır. Veya glibc 2.12 öncesinde bir versiyon kullanılıyorsa, getsubopt()
fonksiyonu yer almayacaktır. Bu sorunları çözmek adına versiyonu yükseltmek için gene hazır bir toolchain kullanabilirsiniz. Ancak böyle bir durumla karşılaştığınızda muhtemelen kullandığınız donanım eskidir ya da üretici toolchain noktasında fazla destek sunmuyordur. Bu noktada donanımıza göre özelleştirilmiş bir toolchain üretimi, son çare olarak düşünülebilir.
Toolchain Sağlayıcıları
Günümüzde ARM platformu gömülü Linux sistemleri dünyasını domine ettiği için, daha çok bu platforma özgü opsiyonları incelediğimizde, aşağıdaki toolchain sağlayıcılarının öne çıktığını görmekteyiz:
Mentor Graphics / Sourcery CodeBench: Destek ile birlikte satılan ücretli versiyonlarının yanı sıra, kayıt formunu doldurup ücretsiz olarak kullanılabilecek Lite versiyonları da bulunmaktadır. Uzun yıllardır bu alanda çalışan deneyimli bir firma olup gömülü Linux dünyasında yoğun bir kullanımı mevcuttur. ARM, MIPS, PowerPC, SuperH mimarileri için toolchain üretimi yapmaktadırlar.
Linaro: Özellikle ARM platformu ve hard-float toolchain'ler üzerinde çalışmaktadırlar. Her geçen gün kullanımı artmaktadır.
Linux Dağıtımları: Debian GNU/Linux, Ubuntu gibi dağıtımlarda ARM mimarisi için
gcc-arm-linux-gnueabi
vegcc-arm-linux-gnueabihf
paketlerini kurmak suretiyle paket geliştiricileri tarafından üretilmiş toolchain'ler de kullanılabilir
Kullanım
Toolchain arşivini sisteminizdeki bir dizine açtığınızda, arm-none-linux-gnueabi-gcc
örneğindeki gibi derleyici araçlarına ait dosyalar oluşacaktır. Toolchain ön ekleri çoğunlukla buradakine benzer olmakla birlikte önceki bölümlerde değindiğimiz şekilde, değişkenlik de gösterebilir.
Eğer toolchain içerisinde kullanılan ön ek, arm-none-linux-gnueabi-
şeklinde uzun olduğunda alışkanlık, kolaylık vb. nedenlerle, arm-linux-
ön ekini kullanmak isterseniz, toolchain bin dizinine gidip, aşağıdaki gibi bir komutla sembolik linkler oluşturmak suretiyle, hem arm-linux-gcc
şeklinde hem de arm-none-linux-gnueabi-gcc
şeklinde derleyici çalıştırmanız mümkün olacaktır:
$ cd /path/to/toolchain/bin && \
for i in `ls`; do s=`echo $i | cut -b 24-`; ln -s $i arm-linux-$s; done
Toolchain içerisinden çıkan derleyici çalıştırmak için ya bulunduğu yerin mutlak yolunu (absolute path) vermeli, ya da toolchain bin dizinini PATH
ortam değişkeninize ekleyip, sadece derleyici adını vererek çalıştırmalısınız: değişkeninimize toolchain bin
dizinini ekleyebiliriz:
$ export PATH=$PATH:/path/to/toolchain/bin
$ arm-linux-gcc -v
PATH
ortam değişkenini bu şekilde her bir kabuk oturumu için ayarlayabilir veya kullandığınız kabuğun her girişte okuduğu temel konfigürasyon dosyalarından birine yazarak sonraki oturumlar için de kalıcı hale getirebilirsiniz.
Çalışılan Toolchain Hakkında Bilgi Edinme
Toolchain içerisinden çıkan gcc derleyicisine -v
parametresini vermek suretiyle, toolchain'in oluşturulması sırasında yapılan tercihleri öğrenebiliriz:
$ arm-linux-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gcc
COLLECT_LTO_WRAPPER=/home/demirten/work/downloads/arm-2011.03/bin/../libexec/gcc/arm-none-linux-gnueabi/4.5.2/lto-wrapper
Target: arm-none-linux-gnueabi
Configured with: /scratch/janisjo/arm-linux-lite/src/gcc-4.5-2011.03/configure \
--build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi \
--enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch \
--enable-extra-sgxxlite-multilibs --with-arch=armv5te --with-gnu-as --with-gnu-ld \
--with-specs='%{save-temps: -fverbose-asm} %{funwind-tables|fno-unwind-tables|mabi=*|ffreestanding|nostdlib:;:-funwind-tables} \
-D__CS_SOURCERYGXX_MAJ__=2011 -D__CS_SOURCERYGXX_MIN__=3 -D__CS_SOURCERYGXX_REV__=41 %{O2:%{!fno-remove-local-statics: -fremove-local-statics}}\
%{O*:%{O|O0|O1|O2|Os:;:%{!fno-remove-local-statics: -fremove-local-statics}}}' --enable-languages=c,c++ --enable-shared \
--enable-lto --enable-symvers=gnu --enable-__cxa_atexit --with-pkgversion='Sourcery G++ Lite 2011.03-41' \
--with-bugurl=https://support.codesourcery.com/GNUToolchain/ --disable-nls --prefix=/opt/codesourcery -\
-with-sysroot=/opt/codesourcery/arm-none-linux-gnueabi/libc --with-build-sysroot=/scratch/janisjo/arm-linux-lite/install/arm-none-linux-gnueabi/libc \
--with-gmp=/scratch/janisjo/arm-linux-lite/obj/host-libs-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr --with-mpfr=/scratch/janisjo/arm-linux-lite/obj/host-libs-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr --with-mpc=/scratch/janisjo/arm-linux-lite/obj/host-libs-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr --with-ppl=/scratch/janisjo/arm-linux-lite/obj/host-libs-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr \
--with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' \
--with-cloog=/scratch/janisjo/arm-linux-lite/obj/host-libs-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr --with-libelf=/scratch/janisjo/arm-linux-lite/obj/host-libs-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr \
--disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/janisjo/arm-linux-lite/install/arm-none-linux-gnueabi/bin --with-build-time-tools=/scratch/janisjo/arm-linux-lite/install/arm-none-linux-gnueabi/bin
Thread model: posix
gcc version 4.5.2 (Sourcery G++ Lite 2011.03-41)
gcc --sysroot
parametresi
Çapraz derleme süreci boyunca sadece glibc standart C kitaplığına ihtiyaç duyan uygulamaların derlenmesi oldukça kolaydır. Ancak spesifik bir uygulama için derleme sürecinde ihtiyaç duyduğumuz diğer kütüphanelerin, çapraz derleme hedef sistemi için de önceden derlenmiş olması, başlık ve kütüphane dosyalarının çapraz derleme için kullanılan derleyicinin baktığı dizinlerden birinde yer alması gereklidir.
Örnek olarak, eğer Sqlite C arayüzünü kullanan bir uygulama geliştiriyorsanız, uygulamayı çapraz derlemeye başlamadan önce, sqlite kütüphanesini hedef platform için derlemeli, başlık dosyalarını ve kütüphanelerini belirli bir dizinde oluşturmalısınız. Bu adımdan sonra yazmış olduğunuz uygulamayı da hedef platform için derleyebilirsiniz.
Örnekten yola çıkarak şöyle bir soru sorabiliriz: Sqlite kütüphanesini bu şekilde derlemek zorunda kalmak yerine toolchain üreticisi aynı derleme işlemini yapıp, başlık ve kütüphaneleri toolchain içerisine dahil etse daha iyi olmaz mıydı?
Bu mümkündür hatta bazı toolchain'lerde gömülü sistemlerde sık kullanılan kütüphanelerin önceden derlenip hazır halde sunulduğunu görmekteyiz. Toolchain üretiminde verilen bu türden ek kararlar, oluşan toolchain'lerin boyutlarının birbirinden farklı olmasına yol açmaktadır.
Kullanılan toolchain içerisinde ihtiyaç duyulan tüm kütüphane ve başlık dosyalarının bulunması olanaksızdır. Dolayısıyla uygulamamızın ihtiyaç duyduğu diğer kütüphanelerin derlenmesi işlemi kaçınılmaz olarak ihtiyaç duyuldukça yapılması gereken bir süreçtir.
İhtiyaç duyulan tüm dosyaları belirli bir dizin yapısı altında birleştirebilmemiz halinde çapraz derleme işlemlerini çok daha kolay hale getirebiliriz. Örnek olarak /opt/cross
şeklinde bir dizin açıp, başlık dosyalarını /opt/cross/usr/include
, kütüphane dosyalarını ise /opt/cross/usr/lib
dizini altında topladığımızı varsayalım. Yeni nesil gcc derleyicilerinde yer alan --sysroot
parametresi aracılığıyla, derleyicimizin sadece /opt/cross
dizini altında hazırladığımız başlık ve kütüphane dosyalarına bakmasını sağlayabiliriz. Bunun için derleyiciyi aşağıdaki şekilde çağırmamız yeterli olacaktır:
$ gcc --sysroot=/opt/cross test.c
Sysroot parametresiyle sağlanan bu kolaylık, Buildroot gibi hedef mimari için derleme ve dosya sistemi üretimi süreçlerini modellemeyi amaçlayan projelerde yoğun olarak kullanılmaktadır. Buildroot ile yeni bir projeye başlandığında, staging adında bir dizin oluşturulmakta ve öncelikle toolchain içerisinden çıkan başlık dosyaları staging/usr/include
dizinine, kütüphane dosyaları ise staging/usr/lib
dizinine kopyalanmaktadır. Sonrasında Buildroot içerisinde seçilmiş tüm kütüphaneler için derleme yapıldıkça ortaya çıkan yeni kütüphane ve başlık dosyaları da bu dizinler altında oluşturulmaya devam etmektedir.
Böylelikle host bilgisayarımızdaki /usr/include
ve /usr/lib
dizin yapısına benzer şekilde staging
dizini altında bileşenler hazır hale getirilmektedir. Yapılan tüm çapraz derleme işlemlerinde de --sysroot=staging/
gcc parametresi kullanıldığından derleme işlemleri daha kolay şekilde yapılabilmektedir.
pkg-config
pkg-config
uygulaması, bir kütüphaneyi kullanmak istediğinizde vermeniz gereken derleme zamanı parametrelerini belirlemenize yardımcı olan bir araçtır. Örnek olarak xt kütüphanesiyle uygulamamızı linklemek istediğimizde gerekecek LDFLAGS ve CFLAGS parametrelerini pkg-config ile şu şekilde öğrenebiliriz:
$ pkg-config --libs xt
-lXt -lX11
$ pkg-config --cflags xt
-I/usr/include/X11
Ancak pkg-config uygulamasının bu bilgileri verebilmesi için, ilgili kütüphane sisteme kurulurken, pkg-config veritabanı dizinine gereken bilgileri içeren .pc
uzantılı bilgi dosyasının da konulmuş olması gerekir. Her kütüphane bu şekilde bir .pc dosyası sağlamıyor olsa da büyük çoğunlukta .pc dosyaları sağlanmaktadır.
Bu sistemi destekleyen bir kütüphaneyi derlediğinizde, make install
işlemi sonrası, .pc
uzantılı tanım dosyası da sisteme kopyalanmaktadır. Bu dosyaların da başlık ve kütüphane dosyalarında olduğu gibi, hedef mimari için ortak bir dizin yapısı altında birleştirilmesinde fayda vardır. Normalde .pc
dosyaları host bilgisayarda /usr/lib/pkgconfig
dizini altına kurulur. Çapraz derleme işlemlerinde ./configure
aşamasında --prefix=/usr
şeklinde verilmiş ise, make install
aşamasında DESTDIR
ortam değişkenini düzenleyerek sysroot için hazırladığımız dizin yapısı altında hem .pc dosyalarını hem de diğer başlık ve kütüphane dosyalarını olması gereken yerlere kopyalayabiliriz:
$ make DESTDIR=/opt/cross install
Bu komut sonrasında (configure aşamasında verilen prefix değerine bağlı olarak) başlık dosyaları /opt/cross/usr/include
, kütüphane dosyaları /opt/cross/usr/lib
ve .pc dosyaları /opt/cross/usr/lib/pkgconfig
dizini altına kopyalanacaktır.
DESTDIR
ortam değişkenini kullanmaz isek kopyalama işlemi hedef platform yerine, host bilgisayardaki /usr/lib/pkgconfig dizinine kopyalanmaya çalışır ki bu istediğimiz bir durum değildir.
pkg-config
uygulaması öntanımlı olarak /usr/lib/pkgconfig
dizinine baktığı için çapraz derleme senaryolarında bu duruma müdahale etmez isek, host sisteminde yer alan kütüphaneler için yanıtlar üreyecektir. PKG_CONFIG_PATH
ortam değişkenini kullanarak, uygulamanın veritabanı olarak farklı bir dizine bakmasını sağlayabiliriz:
$ PKG_CONFIG_PATH=/opt/cross/usr/lib/pkgconfig ./configure --host=arm-linux
Tipik Bir Çapraz Derleme Senaryosu
Autoconf Uygulamaları
GNU autoconf sistemiyle birlikte gelen kütüphane veya uygulamaların çapraz derlenmesi süreci oldukça kolaydır. Toolchain ön ekinin --host
parametresiyle belirtilmesi yeterlidir. Toolchain'imizdeki derleyici arm-linux-gcc
ise:
$ ./configure --host=arm-linux
şeklinde, arm-none-linux-gnueabi-gcc
şeklinde ise:
$ ./configure --host=arm-none-linux-gnueabi
şeklinde configure sürecini tamamladığımızda, tüm Makefile dosyaları doğru derleyici araçlarını gösterecek biçimde üretilecektir.
Autoconf destekli uygulamaların çapraz derleme işlemleriyle bir süre uğraştıktan sonra,
--host
parametresi ile hedef platformunu belirtiyor olmamız size biraz tuhaf veya yanlış gelebilir. Hatta./configure -h
ile configure sistemi hakkında yardım aldığınızda, orada--target
ve--build
şeklinde parametreler olduğunu daha görürsünüz. Çapraz derleme süreci bir hedef (target) sistem için kod üretmeyi amaçladığına ve genel olarak da host kavramı işlemin yapıldığı geliştirme bilgisayarını gösterdiğine göre,--target
parametresinin daha anlamlı olduğunu düşünmek doğaldır. Ancak GNU autoconf sisteminde target parametresi, sadece toolchain üretiminde anlamlı olan özel bir parametredir. Aşağıdaki örnekte gcc uygulamasının kaynak kodundan çapraz derlemede kullanılmak üzere configure edildiğini görüyoruz:
$ ./configure --build=i686-pc-linux-gnu --host=arm-linux --target=i686-pc-linux-gnu
Bu örnekte
- Kaynak koddan derleme sürecinde x86 Linux geliştirme bilgisayarındaki derleme araçlarının kullanılacağı [--build]
- İşlem sonucunda oluşacak gcc uygulamasının ARM üzerinde çalışacağı [--host]
- Derleme sonrası oluşacak gcc uygulamasının x86 mimarisi için kod üreteceği [--target]
tanımlanmış oluyor. Derleme bittikten sonra oluşacak gcc uygulaması ARM üzerinde çalışacak, ancak ürettiği kod x86 mimarisi için olacaktır (ARM üzerinden çapraz derlemeyle x86 kodu üretilecektir)
Derleme işlemi yapacağımız kütüphane ve uygulamaların konfigürasyon adımlarında farklılıklar görülebilir. İlgili yazılımın ihtiyaç duyduğu diğer kütüphaneler ve bu kütüphanelerin çapraz derlenmiş versiyonlarının nerede bulunabileceğini gösterebileceğimiz onlarca parametre bulunmaktadır.
$ ./configure --help
ile bunları görebiliriz.
Bu noktada yardımımıza pkg-config
uygulaması koşar. PKG_CONFIG_PATH
ortam değişkeni düzgün şekilde ayarlanmışsa, ek bir işleme gerek kalmaksızın ihtiyaç duyulan diğer kütüphanelerin çapraz derlenmiş versiyonlarına ait bilgiler configure uygulaması tarafından bulunabilir.
Ancak bunun mümkün olmadığı senaryolarda (pkg-config sisteminde tanımı olmayan kütüphaneler, standart dışı dizinlerde kurulu kütüphaneler vb.), ortam değişkenlerini kullanarak bu dizinleri gösterebiliriz:
$ CFLAGS="-I/opt/other_build/xxx/include" \
LDFLAGS="-L/opt/other_build/xxx/lib -lxxx" \
./configure --host=arm-linux
Başarılı bir configure sonrasında gerekli tüm Makefile
dosyaları üretilmiş olduğundan sonrasında:
$ make
komutu ile derleme işlemleri yapılır.
Uygulama derlendikten sonra, DESTDIR
yöntemiyle çapraz derlenmiş yazılımları topladığımız mini root filesystem altına kurulum yapabiliriz:
$ make DESTDIR=/opt/custom_build install
Bazı eski programlar DESTDIR
özel değişkenini dikkate almayabilirler, bu durumda el yordamı ile ilgili dosyaların mini root filesystem altında yüklenmesi gerekecektir.
Autoconf Dışındaki Uygulamaların Derlenmesi
Bazı eski uygulamalarda, autoconf içermeyen küçük uygulamalarda veya Linux kernel kodu, busybox gibi bazı özel derleme süreçleri olan uygulamalarda çapraz derleme işleminin nasıl olacağı, ilgili sistemle birlikte gelen Makefile dosyaları incelenerek anlaşılabilir.
Linux kernel kodu, busybox gibi uygulamaların Makefile dosyalarında aşağıdaki gibi bir tanım bulunur:
CC = $(CROSS_COMPILE)gcc
Bu şekildeki bir Makefile dosyasında CROSS_COMPILE
değişkeni verilmediği müddetçe standart gcc
derleyicisi çalışacaktır. Ancak CROSS_COMPILE
değişkenine arm-linux-
şeklinde bir değer atandığında yukarıdaki satır doğrultusunda Makefile içerisinde birleştirme yapıldığında C derleyicisini gösteren CC
değişkeninin değeri çapraz derleme için istediğimiz biçimde arm-linux-gcc
halini alacaktır. Bu tarz uygulamaları aşağıdaki gibi derleyebiliriz:
$ make CROSS_COMPILE=arm-linux-
Not: Autoconf sistemindeki host parametremizden farklı olarak sondaki - karakterine dikkat ediniz. Bu gereklilik tamamen Makefile dosyalarındaki kuralların tanımıyla ilgilidir.
Autoconf desteği dışındaki bu tarz uygulamalarda çoğunlukla CROSS_COMPILE ve CROSS_COMPILE_PREFIX değişkenleri kullanılır, bu değişkenlere doğru toolchain ön ekleri atandığında çapraz derleme işlemi gerçekleştirilir.
Nadiren bazı uygulamaların Makefile dosyalarında
CC = gcc
doğrudan tanımlar da bulunabilmektedir. Bu şekildeki bir uygulamayı çapraz derlenebilir hale getirmek için Makefile dosyalarında düzenleme yapmaktan başka yöntem bulunmamaktadır.