2012-05-04    dr inż. Piotr Romaniuk
Co to jest toolchain?
Okazuje się, że zbudowanie własnego kross-kompilatora nie jest trywialne. Sam proces jest wieloetapowy i wymaga budowania kompilatora, po to, aby zbudować kompilator.
Chociaż brzmi to trochę jak "wąż zjadający własny ogon", to jednak daje się zrealizować. W uproszczeniu, budowanie docelowego kross-kompilatora polega na wykonaniu:
- kross-narzędzi (takich jak asembler, linker, itp.) - [binutils],
- pierwszej wersji kross-kompilatora C - wersja statyczna, bez obsługi wątków,
- standardowej biblioteki C,
- końcowej wersji kross-kompilatora C.
Jak widać, w przedstawionej sekwencji budowane są kolejne elementy, które następnie są wykorzystywane do budowania następnych.
Cały ten proces budowania narzędzi [ang. tools] tworzy swego rodzaju łańcuch [ang. chain] stąd nosi on nazwę toolchaina.
Termin ten jest też często używany do określenia zbioru narzędzi powstałych na końcu procesu budowania.
Aby dowiedzieć się wiecej na temat budowania toolchaina warto przeczytać początkowe rozdziały: Cross Linux From Scratch.
Projekt ten dotyczy budowania całego obrazu systemu, łącznie z kernelem Linuxa, przygotowaniem obrazu plików, bootloadera a także ich instalacją
w docelowym systemie. Pierwszym etapem jest zbudowanie toolchaina, za pomocą którego są kompilowane nastepne elementy.
Chociaż wszystkie etapy są dobrze opisane, to jest to jednak droga dość uciążliwa, ze względu na brak automatycznych metod (jeśli coś chce się poprawić,
trzeba wykonywać następującą sekwencję ponownie ręcznie). Trzeba pamiętać, że celem projektu Cross Linux From Scratch jest przedstawienie metod postępowania,
a nie dostarczenie środowiska do budowania.
Budowanie toolchaina
Aby zbudować własny toolchain dobrze jest skorzystać z gotowego środowiska przeznaczonego do budowania tego typu narzędzi,
np. crosstool-NG. W takim przypadku zbudowanie toolchaina sprowadza się do ustawienia opcji konfiguracji
oraz rozpoczęcia procesu budowania, który będzie wykonywał sie automatycznie. Ze względu na złożoność tworzenia toolchaina może
to trochę potrwać (co najmniej kilkadziesiąt minut).
W zależności od używanego systemu operacyjnego, budowanie można wykonać pod Linuxem (zalecane) lub pod Windows z wykorzystaniem Cygwina.
Użycie Cygwina pociąga za sobą dodatkowe wymagania, które są opisane poniżej.
Zgodnie z instrukcją przedstawioną na stronie crosstool-NG należy:
I. pobrać wybraną wersję pakietu crosstool-NG ze strony projektu, np. crosstool-ng-1.14.1.tar.bz2
II. rozpakować źródła i przejść do tego katalogu:
tar -xjf crosstool-ng-1.14.1.tar.bz2
cd crosstool-ng-1.14.1
III. skonfigurować pakiet:
./configure --prefix=/jakis/katalog/ctng-bin
gdzie: prefix jest wybraną przez nas ścieżką, która wskazuje gdzie zostanie zbudowane narzędzie crosstool-NG (uwaga, to jeszcze nie toolchain)
  Jeśli podczas konfiguracji pojawi się komunikat o braku jakiegoś pakietu należy go doinstalować i rozpocząć ponownie konfigurowanie (Cygwin wymagał zamknięcia
okna swojej konsoli przy instalacji niektórych pakietów).
IV. Zbudować i zainstalować narzędzie crosstool-ng:
make
make install
V. dodać do ścieżki systemowej ścieżkę do crosstool-ng
export PATH="${PATH}:/jakis/katalog/ctng-bin/bin
VI. przejść do katalogu, w którym będzie budowany toolchain i przechowywana konfiguracja toolchaina:
cd /jakis/katalog/development
Po pomyślnym wykonaniu powyższych kroków, crosstool-NG jest gotowe do konfiguracji opcji toolchaina oraz rozpoczęcia jego budowania.
Aby skonfigurować toolchain należy uruchomić:
ct-ng menuconfig
Spowoduje to otwarcie menu konfiguracyjnego:
Za pomocą powyższego interfejsu należy ustawić poszczególne opcje toolchaina i zapisać je przy wyjściu z tego programu (domyślnie są one zapisywane w pliku .config).
Po zakończeniu konfiguracji można uruchomić budowanie poprzez polecenie:
ct-ng build
Proces budowania jest długotrwały, w moim przypadku, na Linuxie zajął około 40minut, natomiast na Windows/Cygwin 2h. Jeśli nie zostało to wyłączone w konfiguracji, podczas budowania
będą pojawiały się komunikaty o przeprowadzanych operacjach, znacznik postępu w postaci obracającej się belki i wskaźnik czasu, który upłynał od rozpoczęcia.
Trzeba pamiętać, że Crosstool-NG samodzielnie ściąga odpowiednie wersje źródeł pakietów,
rozpakowuje je, aplikuje patche oraz wykonuje ich kompilację.
Opcje konfiguracji toolchaina
Ze względu na dużą ilość opcji, nie będą tu one wszystkie opisywane, ograniczę się jedynie do najważniejszych:
Path and misc options
   - Prefix directory - katalog, w którym będzie umieszczony zbudowany końcowy toolchain (domyślnie: ${HOME}/x-tools/${CT_TARGET} )
   - Number of parallel jobs - określa zrównoleglenie procesu budowania (szybkość budowania vs. obciążenie komputera)
   - Maximum log level - szczegółowość loga podczas budowania
Target options
   - Target Architecture - architektura procesora na docelowej platformie (np. x86, arm, itp.)
   - Bitness - 32/64 bitowy
   - Architecture level - odmiana procesora, np. i686
   - Emit assembly for CPU - jaki asembler ma używać (jak wyżej)
   - Tune for CPU - optymalizacje do modelu (jak wyżej)
Operating system
   - Target OS - system operacyjny jaki będzie na docelowej platformie
       bare-metal - bez systemu operacyjnego,
       linux - z linuxem (dla linuxa należy podać wersje kernela; jeśli nie ma jej na liście należy wybrać custom_tarbal_directory
    
       i wskazać ścieżkę do archiwum ze
źródłami (kernel można pobrać ze strony www.kernel.org).
C compiler
   C++ - opcja decyduje czy ma być dostępne C++
C-library
   C library - rodzaj standardowej biblioteki C ( rozmiar, szybkość działania vs. funkcjonalność )
     - uClibc - ograniczona funkcjonalność, mały rozmiar,
     - glibc - pełna biblioteka GNU C Library - duży rozmiar, pełna funkcjonalność,
     - eglibc - odmiana GNU C Library dla systemów embedded.
Jak używać toolchain?
Po zakończeniu procesu budowania gotowy toolchain znajduje się w katalogu ${HOME}/x-tools/arch-vendor-kernel-system jeśli nie zostało to zmienione w konfiguracji.
Aby skorzystać z kross-kompilatora należy dodać go do ścieżki systemowej, np:
export PATH="${PATH}:/home/user/x-tools/i686-unknown-linux-gnu/bin"
a w makefile'ach kompilowanych programów używać narzędzi z przedrostkiem, np:
CC=i686-unknown-linux-gnu-gcc
LD=i686-unknown-linux-gnu-gcc
AR=i686-unknown-linux-gnu-ar
AS=i686-unknown-linux-gnu-as
wtedy podczas budowania będą używane nasze kross-narzędzia, a w wyniku ich działania powstaną pliki
wykonywalne z binarnymi kodami instrukcji przeznaczonymi dla docelowej platformy.
Jak zbudować toolchain w Cygwinie?
Podczas budowania crosstool-NG (1.14.1) i samego toolchaina na Cygwinie natrafiłem na następujące problemy:
1. crosstool-NG wymaga systemu plików rozróżniających wielkość liter.
Niestety system plików NTFS używany w Windowsach ma tę opcje wyłączoną,
co można skorygować poprzez wprowadzenie zmiany wartości parametru w rejestrze Windows i zrestartowanie systemu:
   HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\kernel\obcaseinsensitive=0
wg.   (1) Cygwin FAQ 4.30: Is Cygwin case-sensitive?
oraz: (2) Using Cygwin, rozdział "Case sensitive filenames"
Uwaga:
trzeba pamiętać, że zmienia to zachowanie całego systemu plików a nie tylko plików pod Cygwinem. Mogłoby się więc zdarzyć, że jakiś program korzysta z
niewrażliwości na wielkość liter, co po zmianie w rejestrze nie będzie już zachodzić. W takim przypadku mogłby on zachowywać się dziwnie.
W [2] znajduje się ostrzeżenie, że robi się to na własne ryzyko.
Ostrzeżenie to wydaje się być troche na wyrost, w swoich Windowsach 7 zmieniłem to trwale, jak na razie, nie dostrzegam żadnych problemów.
Niemniej jednak trzeba o tym pamiętać.
2. zbędne elementy w ścieżce systemowej
Po uruchomieniu konsoli Cygwina ścieżka systemowa Windowsów (%PATH%) jest kopiowana do $PATH. Ponieważ może ona wskazywać na inne programy używające
innych wersji binarnych narzędzi Cygwina lub MinGW, to będa one wykrywane przez skrypt ./configure. Aby tego uniknąć należy skrócić ścieżkę w Cygwinie.
Proponuje najpierw ją podejrzeć a potem skrócić do niezbędnego minimum:
echo $PATH
export PATH=/usr/local/bin:/usr/bin
3. problem z nagłówkami ncurses
Chociaż nagłówki ncurses są właściwie wykrywane przez skrypt konfiguracyjny, to podczas budowania pojawiał się błąd o ich braku.
Dodanie ścieżki w kconfig/Makefile rozwiązało problem:
# Build flags
CFLAGS = -DCONFIG_=\"CT_\" -DPACKAGE="\"crosstool-NG $(VERSION)\"" -I/usr/include/ncurses
4. problem z brakującą biblioteką libintl
Dodanie biblioteki w kconfig/Makefile rozwiązało problem:
# Build flags
...
LDFLAGS = -lintl
5. problem z ESCDELAY
Symbol wydaje sie być niezdefiniowany dla ncurses w Cygwinie [?].
Zakomentowanie w kconfig/nconf.c@1518 pomogło:
notimeout(stdscr, FALSE);
/*ESCDELAY = 1;*/
6. problem z Make w wersji nowszej niż 3.81
W nowszej wersji Make (Cygwin daje możliwość zainstalowania pakietu Make-v.3.82) nastąpiła drobna zmiana interpretacji makefile'i. Skorygowano pewien
problem, który poprzednio byc ignorowany (dotyczy to zachowania Make dla mieszanych reguł). Chociaż poprawka jest słuszna, niestety prowadzi to do problemu
z budowaniem. Na razie proponuje zainstalować w Cygwinie Make w wersji 3.81 (interfejs GUI setup.exe daje taką możliwość).
7. znacznie dłuższy czas budowania niż na Linuxie
Niestety tu na razie niewiele można poradzić, należy uzbroić się w cierpliwość, w końcu nie codziennie buduje się toolchain ;). Ta własność jest spowodowana
zapewne dodatkowym obciażeniem metod open-file oraz fork w Cygwinie w stosunku do tych operacji na Linuxie. Trzeba pamiętać, że Cygwin to pewne "opakowanie"
umożliwiające uruchamianie na Windowsach programów "jak gdyby" w środowisku linuxo-podobnym.