Uwaga:
Oryginalna wersja tego artykułu została opublikowana w IBM developerWorks i
jest własnością Westtech Information Services. Poniższy dokument jest
poprawioną przez zespół GDP wersją oryginalnego tekstu i nie jest już
aktualizowany.
|
Bash w przykładach - część trzecia
1.
Poznawanie systemu ebuildów
Wkraczanie do systemu ebuildów
Po zapoznaniu się z podstawami programowania w bashu poprzez pierwszą i drugą część cyklu Bash w
przykładach, możemy zagłębić się w bardziej zaawansowane zagadnienia, jak
strategie projektowy czy programowanie prawdziwych aplikacji. W tym artykule
otrzymamy słuszną dawkę praktycznych doświadczeń projektowych. Będą one
przedstawione w oparciu o opis projektu, nad którym autor tego artykułu spędził
wiele godzin, kodując go i ulepszająć. Projektem tym jest system ebuildów
Linuksa Gentoo.
Autor artykułu jest głównym architektem Linuksa Gentoo - systemu operacyjnego
nowej generacji. Jednym z jego głównych zadań jest zapewnienie, aby wszystkie
binarne pakiety (podobne do pamietów RPM) były poprawnie tworzone i mogły
właściwie ze sobą współpracować. Jak prawdopodobnie wiemy, standardowe systemy
Linuksowe nie składają się z pojedynczego jednolitego drzewa źródłowego (jak
BSD), lecz budowane są z ponad 25 pakietów, które pracując razem tworzą rdzeń
systemu. Oto niektóre z tych pakietów:
| Pakiet |
Opis |
| linux |
Jądro systemu |
| util-linux |
Kolekcja różnorodnych programów poziązanych z Linuksem |
| e2fsprogs |
Kolekcja programów powiązanych z systemem plików ext2 |
| glibc |
Biblioteka GNU C |
Każdy pakiet znajduje się w oddzielnym tarballu i jest utrzymywany przez
niezależnych deweloperów lub ich grupy. Zbudowanie systemu polega na pobraniu
wszystkich pakietów, ich kompilacji i połączeniu w systemie. Za każdym razem gdy
pakiet musi zostać naprawiony, zaktualizowany lub ulepszony, konieczne jest
powtórzenie kompilacji i łączenia (a zdarza się to naprawdę często). Aby
wyeliminować konieczność powtarzania tych samych kroków w celu budowania i
tworzenia systemu, powstał system ebuildów. Został on napisany niemal
całkowicie w bashu. Aby zwiększyć naszą wiedzę o bashu, przyjrzymy się jak krok
po kroku zostały zaimplementowane funkcje odpowiedzialne za rozpakowywanie
archiwów i kompilowanie źródeł. Wyjaśniając każdy etap, omówimy dlaczego podjęte
zostały pewne decyzje projektowe. Po przeczytaniu tego artykułu nie tylko
poznamy techniki programowania na dużą skalę, ale również zaimplementujemy spory
fragment kompletnego systemu automatycznej kompilacji.
Dlaczego bash?
Bash stanowi podstawę systemu ebuildów Linuksa Gentoo. Został on wybrany ze
względu na wiele jego przydatnych cech. Po pierwsze, posiada on nieskomplikowaną
i intuicyjną składnię, która szczególnie dobrze nadaje się do wywoływania
zewnętrznych programów. System automatycznej kompilacji w głównej mierze
wywołuje inne aplikacje, więc bash nadaje się doskonale do jego implementacji.
Po drugie, obsługa funkcji pozwoliła na stworzenie modularnego i łatwego w
czytaniu kodu. Po trzecie, system ebuildów wykorzystuje obsługę zmiennych
środowiskowych w bashu, co pozwala konserwatorom i deweloperom na łatwe
konfigurowanie pakietów "w locie".
Przegląd procesu instalacji programu
Zanim zagłębimy się w system ebuildów, zastanówmy się jakie działania składają
się na kompilację i instalację pakietów. Jako przykład wykorzystamy pakiet
programu sed - standardowego narzędzia strumieniowej edycji tekstu, będącego
częścią wszystkich dystrybucji Linuksa. Pierwszym krokiem jest pobranie tarballa
ze źródłami (sed-3.02.tar.gz, link w dziale Źródła informacji). Umieścimy to archiwum w katalogu
/usr/src/distfiles, który jest wskazywany przez zmienną
środowiskową $DISTDIR. W tym katalogu przechowywane są wszystkie nasze
tarballe ze źródłami; jest to swoisty magazyn źródeł.
Kolejny etap to stworzenie tymczasowego katalogu o nazwie work, w
którym umieścimy rozpakowane źródła. Będziemy odwoływać się do tego katalogu
przy użyciu zmiennej środowiskowej $WORKDIR. Aby tego dokonać przejdźmy
do katalogu, w którym mamy prawo do zapisu i wykonajmy polecenia:
Listing 1.1: Rozpakowanie źródeł programy sed do tymczasowego katalogu |
$ mkdir work
$ cd work
$ tar xzf /usr/src/distfiles/sed-3.02.tar.gz
|
Źródła z tarballa zostaną rozpakowane do katalogu sed-3.02.
Będziemy się do niego odwoływać poprzez zmienną środowiskową $SRCDIR. Aby
skompilować program wykonajmy komendy:
Listing 1.2: Kompilacja programu sed |
$ cd sed-3.02
$ ./configure --prefix=/usr
$ make
|
Nie uwzględniamy tutaj komendy make install, ponieważ artykuł ten dotyczy
wyłącznie rozpakowywania i kompilacji. Gdybyśmy napisali skrypt basha, który
wykonałby wszystkie dotychczasowe kroki, wyglądałby on mniej więcej tak:
Listing 1.3: Przykładowy skrypt wykonujący rozpakowywanie i kompilację programu |
#!/usr/bin/env bash
if [ -d work ]
then
rm -rf work
fi
mkdir work
cd work
tar xzf /usr/src/distfiles/sed-3.02.tar.gz
cd sed-3.02
./configure --prefix=/usr
make
|
Generalizacja kodu
Chociaż powyższy skrypt działa poprawnie, nie jest on zbyt przydatny ze względu
na małą elastyczność. Zasadniczo zawiera on jedynie listę komend jakie
wpisywaliśmy w linii poleceń. Rozwiązanie jest poprawne, jednak lepiej byłoby
stworzyć bardziej ogólny skrypt, który można łatwo skonfigurować do
rozpakowania i kompilacji dowolnego pakietu poprzez zmianę kilku jego linijek.
W ten sposób konserwator pakietu może znacznie szybciej i prościej dodać nową
wersję do dystrybucji. Pierwszym krokiem ku temu jest wykorzystanie kilku
zmiennych środowiskowych do przedstawienia danych zależnych od programu, co
sprawi że skrypt będzie bardziej zgeneralizowany:
Listing 1.4: Bardziej zgeneralizowana wersja skryptu |
#!/usr/bin/env bash
P=sed-3.02
A=${P}.tar.gz
export ORIGDIR=`pwd`
export WORKDIR=${ORIGDIR}/work
export SRCDIR=${WORKDIR}/${P}
if [ -z "$DISTDIR" ]
then
DISTDIR=/usr/src/distfiles
fi
export DISTDIR
if [ -d ${WORKDIR} ]
then
rm -rf ${WORKDIR}
fi
mkdir ${WORKDIR}
cd ${WORKDIR}
tar xzf ${DISTDIR}/${A}
cd ${SRCDIR}
./configure --prefix=/usr
make
|
Dodaliśmy sporo zmiennych środowiskowych do skryptu, jednak generalnie wciąż
wykonuje on te same zadania. Natomiast teraz, aby skompilować jakiś program
oparty o autoconf wystarczy skopiować powyższy skrypt do nowego pliku (o
właściwej nazwie, która będzie nawiązywała do pakietu jakie instalujemy) i
zmienić wartości zmiennych $A i $P. Wszystkie inne zmienne
środowiskowe automatycznie dopasują się do nowych wartości i skrypt zadziała
zgodnie z oczekiwaniami. Jest to bardzo poręczne, jednak można jeszcze bardziej
ulepszyć nasz skrypt. Obecnie kod jest znacznie dłuższy od jego początkowej
wersji. Jednym z głównym celów każdego projektu programistycznego powinna być
redukcja nadmiernej złożoności kodu. Dobrze byłoby więc odchudzić skrypt lub
przynajmniej lepiej do zorganizować. Możemy tego dokonać poprzez pewien zgrabny
wybieg - rozdzielimy kod na dwa pliki. Poniższy fragment zapiszmy jako
sed-3.02.ebuild:
Listing 1.5: sed-3.02.ebuild |
P=sed-3.02
A=${P}.tar.gz
|
Pierwszy plik jest trywialny i zawiera tylko dwie zmienne, jakie muszą być
modyfikowane dla różnych pakietów. Poniżej znajduje się drugi plik, zawierający
zasadniczą część operacji. Zapiszmy go pod nazwą ebuild i nadajmy
mu prawa do wykonywania:
Listing 1.6: Skrypt ebuild |
#!/usr/bin/env bash
if [ $# -ne 1 ]
then
echo "Oczekiwano jednego argumentu."
exit 1
fi
if [ -e "$1" ]
then
source $1
else
echo "Plik ebuild $1 nie został odnaleziony."
exit 1
fi
export ORIGDIR=`pwd`
export WORKDIR=${ORIGDIR}/work
export SRCDIR=${WORKDIR}/${P}
if [ -z "$DISTDIR" ]
then
a
DISTDIR=/usr/src/distfiles
fi
export DISTDIR
if [ -d ${WORKDIR} ]
then
# usuwamy stary katalog work jeśli istnieje
rm -rf ${WORKDIR}
fi
mkdir ${WORKDIR}
cd ${WORKDIR}
tar xzf ${DISTDIR}/${A}
cd ${SRCDIR}
./configure --prefix=/usr
make
|
W ten sposób podzieliliśmy nasz skrypt na dwie części. Jak on teraz działa? Aby
skompilować program sed należy wykonać komendę:
Listing 1.7: Testowanie powyższego skryptu |
$ ./ebuild sed-3.02.ebuild
|
Gdy wykonujemy skrypt, próbuje ona wykonać polecenie source z parametrem
$1. Co to oznacza? Zgodnie z wcześniejszymi artykułami o bashu, zmienna
$1 odwołuje się do pierwszego argumentu wywołania skryptu - w tym
przypadku do łańcucha sed-3.02.ebuild. Komenda source czyta
zawartość tego pliku i wykonuje ją tak, jakby pojawiła się w miejscu wywołania
source, więc source ${1} spowoduje wykonanie zawartości pliku
sed-3.02.ebuild, czyli zainicjowanie zmiennych $P i
$A. Jest to bardzo przydatne, gdyż jeśli będziemy chcieli
skompilować inny program zamiast sed, wystarczy, że stworzymy nowy plik
.ebuild i przekażemy jego nazwę jako argument do skryptu ebuild.
Dzięki temu pliki .ebuild są bardzo proste, a wszystkie operacje
wykonywane są w innym miejscu - w skrypcie ebuild. W ten sposób możemy
aktualizować i rozbudowywać system ebuildów poprzez edytowanie skryptu ebuild,
utrzymując cały czas szczegóły implementacji poza plikiem .ebuild.
Oto przykładowy plik .ebuild dla programu gzip:
Listing 1.8: gzip-1.2.4a.ebuild |
P=gzip-1.2.4a
A=${P}.tar.gz
|
Zwiększanie funkcjonalności
Zrobiliśmy już spory postęp, jednak jest kilka dodatkowych funkcjonalności,
które warto byłoby dodać. Jedną z takich funkcjonalności jest obsługa drugiego
parametru wywołania, który może przyjmować wartość compile, unpack
lub all. Będzie on decydował, które etapy procesu mają zostać
przeprowadzone. Dzięki temu będziemu mogli nakazać skryptowi aby rozpakował
archiwum, ale nie kompilował źródeł (gdybyś chcieli przejrzeć kod przed jego
kompilacją). Dodamy tą funkcję wykorzystując konstrukcję case, która sprawdzi
wartość zmiennej $2 i wykonana różne czynności w zależności od jej
wartości. Obecnie kod ma postać:
Listing 1.9: ebuild, wersja druga |
#!/usr/bin/env bash
if [ $# -ne 2 ]
then
echo "Proszę podać dwa argumenty - nazwę pliku .ebuild oraz unpack, compile lub all"
exit 1
fi
if [ -z "$DISTDIR" ]
then
DISTDIR=/usr/src/distfiles
fi
export DISTDIR
ebuild_unpack() {
cd ${ORIGDIR}
if [ -d ${WORKDIR} ]
then
rm -rf ${WORKDIR}
fi
mkdir ${WORKDIR}
cd ${WORKDIR}
if [ ! -e ${DISTDIR}/${A} ]
then
echo "${DISTDIR}/${A} nie istnieje. Najpierw pobierz ten plik."
exit 1
fi
tar xzf ${DISTDIR}/${A}
echo "Rozpakowany ${DISTDIR}/${A}."
#źródła zostały rozpakowane
}
ebuild_compile() {
cd ${SRCDIR}
if [ ! -d "${SRCDIR}" ]
then
echo "${SRCDIR} nie istnieje - najpierw rozpakuj źródła."
exit 1
fi
./configure --prefix=/usr
make
}
export ORIGDIR=`pwd`
export WORKDIR=${ORIGDIR}/work
if [ -e "$1" ]
then
source $1
else
echo "Plik ebuild $1 nie istnieje."
exit 1
fi
export SRCDIR=${WORKDIR}/${P}
case "${2}" in
unpack)
ebuild_unpack
;;
compile)
ebuild_compile
;;
all)
ebuild_unpack
ebuild_compile
;;
*)
echo "Użyj unpack, compile lub all jako drugiego argumentu."
exit 1
;;
esac
|
Wprowadziliśmy wiele zmien - przyjrzymy się im dokładnie. Po pierwsze, etapy
rozpakowywania i kompilacji znajdują się teraz w oddzielnych funkcjach o nazwach
ebuild_compile() iebuild_unpack(). Jest to dobry krok, ponieważ
kod robi się coraz bardziej skomplikowany, a funkcje dają modularność pomocną w
organizacji programu. W pierwszej linii każdej funkcji wykonujemy komendę
cd z parametrem w postaci katalogu, w którym chcemy operować. Warto jest
zastosować ten element, ponieważ im bardziej kod jest modularny i
zgeneralizowany, tym łatwiej jest pomylić się w czasie jego wywoływania i zrobić
to z innego miejsca niż powinniśmy. Komenda cd przenosi nas dokładnie
tam, gdzie powinniśmy być i chroni tym samym przed kolejnymi błędami. Jest to
bardzo ważne, szczególnie jeśli w przyszłości dodamy do funkcji komendy
usuwające pliki.
Na początku funkcji ebuild_compile() dodaliśmy również warunek
sprawdzający czy istnieje katalog $SRCDIR, a jeśli nie istnieje
drukujący komunikat o błędzie i kończący wykonanie skryptu. Jeśli chcemy możemy
zmienić to zachowanie na przykład tak, aby skrypt automatycznie wypakowywał
źródła, jeśli nie zostało to zrobione wcześniej. Zrobimy to zastępując aktualną
wersję funkcji ebuild_compile() poniższym kodem:
Listing 1.10: Alternatywna wersja funkcji ebuild_compile() |
ebuild_compile() {
if [ ! -d "${SRCDIR}" ]
then
ebuild_unpack
fi
cd ${SRCDIR}
./configure --prefix=/usr
make
}
|
Główną zmianą dla przebiegu skryptu jest pojawianie się konstrukcji case na
końcu kodu. Sprawdza ona wartość drugiego argumentu wywołania i wykonuje dalsze
operacje odpowiednio do jego wartości. Spróbujmy wykonać komendę:
Listing 1.11: Wywołanie skryptu bez drugiego argumentu |
$ ebuild sed-3.02.ebuild
|
Powinniśmy otrzymać komunikat o błędzie. Skrypt ebuild wymaga teraz drugiego
argumentu, wskazującego jakie akcje ma podjąć:
Listing 1.12: Rozpakowywanie |
$ ebuild sed-3.02.ebuild unpack
|
lub:
Listing 1.13: Kompilacja |
$ ebuild sed-3.02.ebuild compile
|
lub:
Listing 1.14: Rozpakowywanie i kompilacja |
$ ebuild sed-3.02.ebuild all
|
Ważne:
Podanie dla drugiego argumentu innej wartości niż w przykładach powyżej
spowoduje wypisanie komunikatu o błędzie i zakończenie skryptu. Odpowiada za to
wzorzec * w konstrukcji case.
|
Dzielenie kodu na moduły
Teraz, gdy kod jest już całkiem zaawansowany i cechuje się pewną
funkcjonalnością, możemy stworzyć więcej plików .ebuild do
instalacji innych programów. Jednak jeśli tak zrobimy, wcześniej czy później
natrafimy na aplikacje, które nie korzystają z autoconf (./configure),
lub na inne, cechujące się niestandardowym procesem instalacji. Konieczne jest
wprowadzenie dodatkowych zmian do systemu ebuildów aby zapewnić obsługę również
dla tych aplikacji. Jednak zanim zaczniemy kodować, zastanówmy się jak
zrealizować ten cel.
Zaletą umieszczenia w skrypcie kodu ./configure --prefix=/usr; make jest
to, że zazwyczaj daje on oczekiwany efekt. Musimy jednak przystosować nasz
system do obsługi źródeł, które nie korzystają z autoconf, lecz ze zwykłych
plików make. Aby rozwiązać ten problem, ustalmy, że skrypt ebuild domyślnie
będzie postępował w następujący sposób:
-
Jeśli w katalogu ${SRCDIR} istnieje skrypt configure, wykonujemu go:
./configure --prefix=/usr. Jeśli nie - pomijamy ten krok.
- Wykonujemy komendę make
Skrypt ebuild wykona polecenie ./configure tylko jeśli istnieje
odpowiedni skrypt. Dzięki temu automatycznie dostosowujemy się do programów,
które nie korzystają z autoconf i posiadają pliki make. Co jednak zrobić, jeśli
sama komenda make nie wystarczy do zainstalowania aplikacji?
Musimy zastąpić wtedy nasz domyślny kod pewnymi specyficznymi poleceniami, które
pozwolą na instalację tych programów. W tym celu rozbijemy funkcję
ebuild_compile() na dwie inne. Pierwsza z nich, którą można nazwać
"rodzicem", wciąż będzie nazywać się ebuild_compile(). Drugą natomiast
nazwiemy user_compile() i umieścimy w niej domyślne zachowanie naszego
skryptu:
Listing 1.15: Funkcja ebuild_compile() rozbita na dwie części |
user_compile() {
if [ -e configure ]
then
#uruchamiany sktypt configure, jeśli istnieje
./configure --prefix=/usr
fi
#uruchamiamy make
make
}
ebuild_compile() {
if [ ! -d "${SRCDIR}" ]
then
echo "${SRCDIR} nie istnieje - najpierw rozpakuj źródła."
exit 1
fi
cd ${SRCDIR}
user_compile
}
|
Możliwe, że nie jest w tym momencie do końca jasne dlaczego dokonaliśmy takiego
podziału, ale zaraz wszystko zostanie opisane. Podczas gdy powyższy kod działa
niemal identycznie jak w poprzedniej wersji, teraz możemy zrobić coś, czego nie
byliśmy w stanie zrobić wcześniej - możemy nadpisać funkcję user_compile,
tworząc jej nową wersję w pliku sed-3.02.ebuild. Więc jeśli
domyślne działania nie odpowiadają potrzebom danego programu, możemy zdefiniować
nową w pliku .ebuild, która będzie zawierać komendy potrzebne do
instalacji danej aplikacji. Poniżej znajduje się przykładowy plik ebuild dla
programu e2fsprogs-1.18, który wymaga nieco innego wywołania skryptu
./configure:
Listing 1.16: e2fsprogs-1.18.ebuild |
P=e2fsprogs-1.18
A=${P}.tar.gz
user_compile() {
./configure --enable-elf-shlibs
make
}
|
Teraz e2fsprogs zostanie skompilowany dokładnie tak jak powinien.
Dla większości pakietów pominiemy umieszczanie funkcji
user_compile() w pliku .ebuild i wykorzystana zosatnie
standardowa funkcja w skrypcie ebuild.
Skąd dokładnie skrypt ebuild wie którą wersję funkcji user_compile() ma
wykorzystać? Jest to całkiem proste. W skrypcie ebuild domyślna funkcja
user_compile jest zdefiniowana przez dołączeniem pliku
e2fsprogs-1.18.ebuild. Jeśli w pliku
e2fsprogs-1.18.ebuild znajduje się inna wersja funkcji
user_compile, to nadpisuje ona wcześniej zdefiniowaną. Jeśli nie -
domyślna funkcja jest jedyną jaka może zostać wykorzystana.
Podnieśliśmy znacznie elstyczność skryptu bez konieczności wprowadzania żadnego
skomplikowanego kodu. Choć nie zostanie to tutaj opisane, możliwe jest
wprowadzenie podobnych modyfikacji w funkcji ebuild_unpack(), co
pozwoliłoby na zmianę standardowego sposobu rozpakowywania źródeł. Będzie to
przydatne jeśli źródła jakiegoś programu znajdują się w kilku archwiach, a także
w wielu innych sytuacjach. Dobrym pomysłem jest również taka modyfikacja kodu
rozpakowującego, aby automatycznie rozpoznawał archiwa bzip2.
Pliki konfiguracyjne
Poznaliśmy już wiele przemyślnych technik programowania w bashu, a teraz
zapoznamy się z jeszcze jedną. Często przydatne jest aby program posiadał
globalny plik konfiguracyjny, rezydujący w katalogu /etc. Na
szczęście łatwo jest zrobić to korzystając z basha. Po prostu stwórzmy
następujący plik i zapiszmy go jako /etc/ebuild.conf:
Listing 1.17: /ect/ebuild.conf |
MAKEOPTS="-j2"
|
W powyższym przykładzie ujęliśmy tylko jedną opcję konfiguracyjną, ale możemya
dodać ich znacznie więcej. Wspaniają cechą basha jest to, że plik konfiguracyjny
może zostać wykorzystany poprzez zwykłe dołączenie go komendą source do
skryptu. Jest to wybieg, który działa w większości interpretowanych języków. Gdy
dołączymy plik /etc/ebuild.conf zmienna $MAKEOPTS zostanie
zdefiniowana wewnątrz skryptu ebuild. Będziemy ją wykorzystywać, aby pozwolić
użytkownikom na przekazywanie parametrów dla make. Zazwyczaj powyższa
przykładowa opcja jest przekazywana aby zezwolić na wykonywanie równoległych
wywołań make. Zostało to wyjaśnione poniżej.
Uwaga:
Czym są równoległe wywołania make? Aby przyspieszyć kompilację na
wieloprocesorowych komputerach, make dopuszcza równoległe kompilacje programu.
Oznacza to, że zamiast kompilować jeden plik źródłowy naraz, make kompiluje
ilość plików określoną przez użytkownika (dzięki czemu wykorzystywany jest
potencjał wieloprocesorowych maszyn). Kompilacje równoległe są możliwe poprzez
przekazanie opcji -j # do make, na przykład: make -j4 MAKE="make
-j4". Ten kod umożliwi kompilację czterech plików źródłowych równocześnie.
Argument MAKE="make -j4" nakazuje przekazywanie argumentu -j4 do
wszystkich podrzędnych wywołań make.
|
Oto ostateczna wersja skryptu ebuild:
Listing 1.18: Skrypt ebuild - wersja ostateczna |
#!/usr/bin/env bash
if [ $# -ne 2 ]
then
echo "Podaj nazwę pliku .ebuild oraz unpack, compile lub all"
exit 1
fi
source /etc/ebuild.conf
if [ -z "$DISTDIR" ]
then
DISTDIR=/usr/src/distfiles
fi
export DISTDIR
ebuild_unpack() {
cd ${ORIGDIR}
if [ -d ${WORKDIR} ]
then
rm -rf ${WORKDIR}
fi
mkdir ${WORKDIR}
cd ${WORKDIR}
if [ ! -e ${DISTDIR}/${A} ]
then
echo "${DISTDIR}/${A} nie istnieje. Najpierw pobierz źródła."
exit 1
fi
tar xzf ${DISTDIR}/${A}
echo "Wypakowano ${DISTDIR}/${A}."
}
user_compile() {
if [ -e configure ]
then
./configure --prefix=/usr
fi
make $MAKEOPTS MAKE="make $MAKEOPTS"
}
ebuild_compile() {
if [ ! -d "${SRCDIR}" ]
then
echo "${SRCDIR} nie istnieje - najpierw rozpakuj źródła."
exit 1
fi
cd ${SRCDIR}
user_compile
}
export ORIGDIR=`pwd`
export WORKDIR=${ORIGDIR}/work
if [ -e "$1" ]
then
source $1
else
echo "Plik ebuild $1 nie istnieje."
exit 1
fi
export SRCDIR=${WORKDIR}/${P}
case "${2}" in
unpack)
ebuild_unpack
;;
compile)
ebuild_compile
;;
all)
ebuild_unpack
ebuild_compile
;;
*)
echo "Podaj unpack, compile lub all jako drugi argument."
exit 1
;;
esac
|
Zwróćmy uwagę na fakt, że plik /etc/ebuild.conf jest dołączany na
początku skryptu. Zważmy również, iż używamy zmiennej $MAKEOPTS w
naszej domyślnej funkcji user_compile(). Być może nie jest do końca jasne
w jaki sposób to działa - w gruncie rzeczy odwołujemy się do $MAKEOPTS
przed dołączeniem pliku /etc/ebuild.conf, w którym zmienna ta jest
definiowana. Szczęśliwie dla nas, działa to poprawnie, ponieważ ekspansja
zmiennych zostaje przeprowadzona tylko kiedy wywołujemy funkcję
user_compile(). Gdy dokonujmy wywołania tej funkcji plik
/etc/ebuild.conf jest już dołączony i zmienna $MAKEOPTS
posiada prawidłowe wartości.
Potrafimy coraz więcej
Poznaliśmy w tym artykule wiele technik programowania w bashy, jednak w istocie
dotkneliśmy jedynie podstaw. Dla przykładu system ebuildów Gentoo poza
rozpakowywaniem i kompilowaniem programów potrafi również:
-
Pobierać źródła jeśli nie ma ich w katalogu $DISTDIR.
-
Weryfikować poprawność źródeł przy użyciu sum MD5.
-
Jeśli jest to wymagane, zapamiętywać wszystkie pliki instalowane w
systemie, w celu ich łatwej deinstalacji.
-
Jeśli jest to wymagane, pakować skompilowane aplikacje do tarball
(skomperowane tak, jak tego chcemy), co umożliwia ich późniejszą instalację
na innym komputerze lub w czasie instalacji systemu.
Dodatkowo posiada on wiele innych globalnych opcji konfiguracji, pozwalających
użytkownikowi na wybór flag optymalizacyjnych wykorzystywanych w czasie
instalacji i możliwości wsparcia dla innych programów - na przykład dla GNOME.
Oczywiste jest, że bash posiada znacznie bogatsze możliwości niż te, które
poznaliśmy w tej krótkiej serii artykułów. Nauczyliśmy się całkiem sporo,
więc korzystajmy niesamowitego narzędzia jakim jest bash, aby
przyspieszyć naszą codzienną pracę i usprawnić nasze projekty.
2.
Źródła informacji
Przydatne linki
|