Kompilacja całego systemu lub pakietów
Ostatnia zmiana: 2024-11-26 18:34

Ten poradnik nie jest przeznaczony dla zupełnie początkujących - jeżeli nie wiesz co to make, jak nakłada się łatki czy jak wygląda praca z repozytorium - najpierw zgromadź tą wiedzę u wujka Google.

Założenie - w poradniku będzie opisana kompilacja wersji stabilnej OpenWrt, źródła będą znajdować się w katalogu domowym, w podkatalogu openwrt. Kompilację wykonuje się na zwykłym komputerze, więc do kompilacji potrzebny jest system *unix (np. Linux) lub MacOS/OS X. System powinien zawierać podstawowy zestaw programów przeznaczonych do kompilacji, czyli np. dla debiana/ubuntu/mint należy zainstalować odpowiednie pakiety poleceniem:


    $ sudo apt install build-essential binutils bzip2 gawk gettext git libncurses5-dev patch unzip zlib1g-dev

oraz w zależności od wersji systemu


    $ sudo apt install python3-setuptools
    lub
    $ sudo apt install python3-distutils

Mogą być też potrzebne też inne pakiety - jeżeli tak będzie to podczas procesu kompilacji zwykle zostanie wyświetlona odpowiednia informacja.
Do kompilacji można używać systemu na maszynie wirtualnej, ale wymagane jest 4GB lub więcej pamięci ram. Przy 2GB mają wystąpić problem typu out-of-memory.

Kompilacja działa prawidłowo dla Debiana i pochodnych (Ubuntu/Mint), dla x86/64. W tym przykładzie kompilowany będzie system dla architektury ath79 - w przypadku innej platformy należy po prostu dostosować polecenia czy opcje. W zależności od wybranych opcji potrzebne jest od 10GB do kilkuset gigabajtów wolnej przestrzeni dyskowej i dostęp online do internetu (do pobierania źródeł). Może się wydawać dziwne że potrzeba aż kilkudziesięciu gigabajtów żeby wyszedł obraz o wielkości kilku megabajtów, ale OpenWrt kompiluje wszystko łącznie z kompilatorem C dla danej architektury, więc większość tej przestrzeni wymagana jest do kompilacji odpowiednich wersji programów narzędziowych.

Kompilacja OpenWrt

Pobieranie źródeł określonego wydania stabilnego



    $ cd ~
    $ git clone https://github.com/openwrt/openwrt.git
    $ cd openwrt
    $ git fetch --tags
    $ git checkout v23.05.5

Te polecenia pobierają sam podstawowy system, aktualną stabilną wersję wydania OpenWrt (numer wersji może się zmienić, więc należy pobrać tą wersję która ma być kompilowana). Listę wszystkich dostępnych wersji można uzyskać poleceniem:


    $ git tag

Dostępne są jeszcze dodatkowe pakiety, które uzupełniają całość (tzw. feeds), które też warto pobrać.


    $ make package/symlinks

Wszystkie poniższe operacje wykonuje już się będąc w katalogu ze źródłami, czyli wg założeń w ~/openwrt.

Wydanie stabilne w określonej wersji (tag) nie zmienia się i zawsze jest w tej samej wersji. Jeżeli wyszło nowe wydanie OpenWrt należy zrobić git checkout podając jako argument odpowiedni tag.

Pobieranie źródeł aktualnego wydania stabilnego (opcjonalnie)

Jeżeli chcemy skompilować aktualną gałąź wydania stabilnego OpenWrt 23.05 (tzw. "branch" openwrt-23.05, który wewnętrznie przez samo OpenWrt nazywany jest 23.05-SNAPSHOT) to zamiast określonego wydania (tag) robimy:


    $ git checkout openwrt-23.05

Branch i tags to nie jest to samo!

Jeżeli wybraliśmy całą gałąź wersji stabilnej (branch openwrt-23.05) to są tam wprowadzane poprawki dopóki jest ona utrzymywana (to z niej właśnie kiedyś może powstać następna wersja stabilna oznaczona określonym numerem). Aktualizację tej gałęzi można wykonać poleceniami (będąc w katalogu ze źródłami):


    $ git pull
    $ make package/symlinks
    $ make defconfig

O ile byliśmy przełączeni na branch openwrt-23.05 (można to sprawdzić poleceniem git branch). Zawartość repozytorium gałęzi wydania stabilnego zmienia się co jakiś czas (a jeszcze rzadziej wydawane są oficjalne wydania obrazów przez zespół OpenWrt), więc jeżeli budujemy obrazy to warto mieć aktualne źródła.

Konfiguracja



    $ make menuconfig

Tu należy wybrać żądną platformę i pakiety. Na samym początku wystarczy zostawić wartości domyślne, wybieramy tylko Target System np. Atheros ATH79 oraz Target Profile jako TP-Link TL-WR1043ND jeżeli chcemy kompilować dla tego urządzenia.
Znaczek <*> oznacza że z tego pakietu będzie z tego zrobiona paczka ipk i zostanie wkompilowany w wynikowy obraz, <M> - zostanie tylko skompilowany jako paczka. <--> oznacza że pakiet jest domyślnie wybrany, bo od niego zależy inny pakiet i nie da się go odznaczyć. Jeżeli wiemy że jakiś pakiet będzie używany i niezbyt często aktualizowany (np. moduły do USB, serwer ftp czy transmission) warto takie pakiety wkompilować w obraz - będą zajmowały znacznie mniej miejsca niż ich późniejsza instalacja w systemie.

Kompilacja środowiska



    $ make

Podczas kompilacji wymagane jest połączenie do internetu, ponieważ ściągane są źródła pakietów (można ściągnąć najpierw wszystkie wymagane źródła poleceniem make download). Początkowa kompilacja (kroskompilator, kernel, pakiety) w zależności od ilości wybranych pakietów może trwać nawet kilka godzin! Przy kolejnych kompilacjach, np. dodaniu kolejnego pakietu, kompilacja będzie już krótsza, bo kompilowane są tylko zmiany.

Jeżeli mamy kilka rdzeni w CPU to przy późniejszych operacjach możemy uruchomić kompilację "równoległą" poleceniem


    $ make -j$(nproc)

(nie należy używać tej opcji jeżeli wyskoczą błędy podczas kompilacji i chcemy się dowiedzieć w jakich pakietach się one pojawiły).
Jeżeli chcemy uzyskać więcej informacji podczas kompilacji należy posłużyć się odpowiednim przełącznikiem


    $ make V=s -j1

Obrazy wynikowe i pakiety zostaną umieszczone w podkatalogu bin/. Jeżeli zaznaczymy za dużo pakietów i przekroczy to dopuszczalny rozmiar obrazów (np. 8MB dla TL-WR1043ND v1) to obraz po prostu nie zostanie wygenerowany.

Czasami (w bardzo rzadkich przypadkach) może przydać się zmiana opcji kompilacji kernela. Można to zrobić poleceniem (po uprzedniej kompilacji systemu!)


    $ make kernel_menuconfig

zaznaczyć niezbędne opcje, zapisać a potem jeszcze raz skompilować cały system poleceniem make.

Czyszczenie kompilacji

Przy zmianie czegoś w kernelu może okazać się konieczna ponowna rekompilacja jądra i pakietów z modułami, przed kompilacją należy więc je wyczyścić:


    $ make target/linux/clean

Czasami wykonane zostało więcej zmian i nie da się skompilować ponownie obrazu. W takich przypadkach pomaga wyczyszczenie całego środowiska z plików kompilacji:


    $ make dirclean


Dodanie własnych plików do obrazu

Niekiedy istnieje potrzeba dodania do obrazów własnych plików konfiguracyjnych, ustawień lub skryptów. OpenWrt posiada do tego specjalny mechanizm, pozwalający łatwo wprowadzać zmiany do obrazu. Tworzymy folder o nazwie files w głównym katalogu z naszymi źródłami:


    $ cd ~
    $ cd openwrt
    $ mkdir -p files

A następnie umieszczamy w nim pliki lub katalogi które mają znaleźć się w docelowym obrazie. Cała struktura katalogów zostanie przeniesiona w identyczny sposób, więc np. jeżeli chcemy podmienić plik /etc/banner w obrazie wynikowym na swój, to w katalogu files robimy podkatalog etc a w nim umieszczamy plik banner z własną zawartością:


    $ mkdir -p files/etc
    $ echo ">>>> to dziala!!! <<<<" > files/etc/banner


Jeżeli chcemy dodać skrypt który wykonuje się jeden raz przy uruchomieniu routera (np. wprowadza jakiś ustawienia - poniższy przykład uruchamia wifi przy starcie routera) to należy to zrobić w katalogu etc/uci-defaults, np tak:


    $ mkdir -p files/etc/uci-defaults
    $ chmod 755 files/etc/uci-defaults/01-mojskrypt.sh

    $ echo "#!/bin/sh" > files/etc/uci-defaults/01-mojskrypt.sh
    $ echo "uci del wireless.@wifi-device[0].disabled" >> files/etc/uci-defaults/01-mojskrypt.sh
    $ echo "uci commit" >> files/etc/uci-defaults/01-mojskrypt.sh


Kompilacja pojedynczego pakietu



    $ make package/nazwa_katalogu_z_pakietem/compile

Gdzie nazwa_katalogu_z_pakietem to nazwa katalogu w którym znajduje się pakiet (to trzeba niestety wiedzieć). Czyli jeżeli chcemy skompilować np. pakiet libffmpeg, a znajduje się on w katalogu ffmpeg, to kompilacja wygląda następująco: "make package/ffmpeg/compile", a nie "make package/libffmpeg/compile"! Żeby pakiet dało się skompilować musi być także wcześniej zaznaczony w konfiguracji (w make menuconfig - trzeba go wybrać przez <M> lub <*>).

Dostępna jest opcja czyszczenia kompilacji pakietu, czyli


    $ make package/nazwa_katalogu_z_pakietem/clean

Co może być pomocne w przypadku dużych aktualizacji pakietów czy samodzielnego tworzenia łatek.

Kompilacja programu z kodu źródłowego

Ogólnie - należy zrobić odpowiedni plik Makefile który pozwoli na przygotowanie pakietu ze skompilowanym programem. W niektórych przypadkach chcemy tylko skompilować prosty program i można to zrobić "ręcznie".
Kroskompilator i resztę wymaganych plików (nagłówki, biblioteki) można znaleźć w katalogu staging_dir/toolchain-XXX (dla ath79 i openwrt-22.03 jest to np. staging_dir/toolchain-mips_24kc_gcc-11.2.0_musl). Kroskompilator znajduje się w podkatalogu bin (mips-openwrt-linux-musl-gcc), biblioteki są w staging_dir/target_*/usr/lib, pliki nagłówkowe w staging_dir/target_*/usr/include (w zależności od wersji mogą to być katalogi odpowiednio usr/bin, usr/lib i usr/include). Kompilacja przykładowego programu może więc wyglądać następująco:


    $ export STAGING_DIR=~/openwrt/staging_dir/toolchain-mips_24kc_gcc-11.2.0_musl
    $ cd ${STAGING_DIR}
    $ bin/mips-openwrt-linux-musl-gcc -o program plik1.c plik2.c ... -I${STAGING_DIR}/../target-mips_24kc_musl/usr/include -L${STAGING_DIR}/../target-mips_24kc_musl/usr/lib -ljakas_biblioteka

Oczywiście należy podać wszystkie opcje kompilacji i linkowania niezbędne do stworzenia danego programu (zamiast plik*.c i jakas_biblioteka). Powyższy przykład sprawdzi się dla prostych programów, dla bardziej zaawansowanych projektów prościej jest napisać odpowiedni Makefile podobnie jak to jest zrobione dla innych pakietów w katalogach package lub feeds. Budowa takiego Makefile opisana jest na wiki openwrt (po angielsku): http://wiki.openwrt.org/doc/devel/packages
Przykładowy program helloworld z odpowiednim Makefile dostępny jest tutaj: http://dl.eko.one.pl/projekty/helloworld.tar.gz

Kompilacja Gargoyle

Generalnie kompilacja wygląda w podobny sposób jak normalnego OpenWrt z tą różnicą, że Gargoyle zawiera własne skrypty służące do nakładania łatek i budowania całości.

Pobieranie źródeł



    $ git clone https://github.com/ericpaulbishop/gargoyle.git
    $ cd gargoyle

Kompilacja

Jeżeli chcemy zbudować wszystko co buduje gargoyle:


    $ make

lub można skompilować określoną platformę np:


    $ make ath79

lub określony subtraget, np:


    $ make ath79.default

Listę targetów/subtargetów można znaleźć w źródłach gargoyle w katalogu targets.

Gargoyle samodzielnie pobiera źródła OpenWrt, nakłada swoje łatki i kompiluje środowisko. Po wykonaniu w/w operacji powstaje katalog o nazwie np. ath79-src który zawiera wszystkie źródła wraz nałożonymi już łatkami. Jeżeli potrzebujemy minimalnej zmiany typu dodanie pakietu czy coś podobnego to nie ma sensu ponownie kompilować całego środowiska - należy po prostu wejść do tego katalogu i wykonać polecenia make menuconfig && make

Tworzenie własnego repozytorium

"Przepis" jak zrobić repozytorium pakietów zawarty jest w źródłach OpenWrt: https://github.com/openwrt/openwrt/blob/openwrt-24.10/package/Makefile#L136

Do utworzenia repozytorium niezbędne jest posiadania skryptów i plików wykonywalnych wchodzących w skład SDK OpenWrt, więc najlepiej posłużyć się źródłami z których zostały pakiety skompilowane.
Należy utworzyć katalog tymczasowy:


    $ mkdir -p /tmp/x

I skopiować do niego pakiety ipk które mają wchodzić w skład repozytorium i mają zostać zaindeksowane.

Zakładając że źródła OpenWrt mamy w katalogu /home/user/openwrt/ath79/generic należy wykonać po kolei:


    $ cd /tmp/x
    $ export OPENWRTDIR=/home/user/openwrt/ath79/generic
    $ MKHASH=$OPENWRTDIR/staging_dir/host/bin/mkhash PATH=$OPENWRTDIR/staging_dir/host/bin:$PATH $OPENWRTDIR/scripts/ipkg-make-index.sh . 2>&1 > Packages.manifest
    $ grep -vE '^(Maintainer|LicenseFiles|Source|SourceName|Require|SourceDateEpoch)' Packages.manifest > Packages
    $ case "$(((64 + $(stat -L -c%s Packages)) % 128))" in 110|111) { echo ""; echo ""; } >> Packages; esac
    $ gzip -9k Packages
    $ $OPENWRTDIR/staging_dir/host/bin/usign -S -m Packages -s $OPENWRTDIR/key-build
    $ cp $OPENWRTDIR/key-build.pub ./moje-repo.pub


To jest gotowe repozytorium. Teraz należy zawartość katalogu /tmp/x wystawić w internecie tak, aby można było bezpośrednio pobierać pliki z danego adresu URL. Zakładamy że udostępniamy adres URL np. https://moje-repo.domena.pl/openwrt/pakiety, czyli powinno dać się pobrać bezpośrednio plik np. https://moje-repo.domena.pl/openwrt/pakiety/Packages.gz

Aby móc instalować pakiety z takiego repozytorium należy do routera z OpenWrt dodać do pliku /etc/opkg/customfeeds.conf następujący wpis:


    src/gz moje_pakiety https://moje-repo.domena.pl/openwrt/pakiety

Gdzie moje_pakiety to dowolna nazwa ale musi być unikalna dla każdego dostępnego repozytorium.

Jeżeli używany jest inny obraz OpenWrt, który nie był skompilowany z w/w źródeł to może on nie zawierać klucza publicznego naszego repozytorium. W takim przypadku należy jeszcze dodać do routera ten klucz poleceniami:


    # wget https://moje-repo.domena.pl/openwrt/pakiety/moje-repo.pub -O /tmp/moje-repo.pub
    # opkg-key add /tmp/moje-repo.pub


Następnie należy wykonać opkg update, powinna wczytać się lista wszystkich pakietów i można instalować już żądane pakiety.