6301


Rozdział 27. Dystrybucja aplikacji

W tym rozdziale omówimy skrótowo przygotowanie własnej aplikacji do rozpowszechniania, tworzenie źródłowych i binarnych pakietów dystrybucyjnych oraz sposób reakcji na błędy dostrzeżone przez użytkowników. Będziemy więc:

Pisanie programów dla systemu Microsoft DOS jest bardzo proste, ponieważ program działający na jednej maszynie będzie prawdopodobnie działał także na innych. Windows wprowadza pewne ograniczenia, ponieważ trzeba pamiętać o różnych odmianach, takich jak CE (we wszelkiego rodzaju komputerkach podręcznych), NT, 9x i 2000. Pomimo tego, trzeba program skompilować dla każdej z tych platform i dostarczyć binarny plik wykonywalny.

Oprogramowanie o otwartych źródłach dostarcza nowych wyzwań, gdy dochodzi do dystrybucji ukończonych aplikacji. Ogólnie mówiąc, należy sprostać wymaganiom znacznie większej liczby platform sprzętowych i procesorów. Oprócz tego, po podjęciu decyzji o rozpowszechnianiu aplikacji jako wolnego oprogramowania należy udostępnić kod źródłowy.

Programując w systemie Linux, należy pamiętać o tym, że użytkownicy będą próbowali kompilować aplikacje na innych maszynach z systemami typu UNIX, np. FreeBSD, Solaris, HP-UX itp. Każdy z tych systemów czymś się różni od pozostałych. Często te różnice są tak duże, że uniemożliwiają skompilowanie dostarczonej aplikacji. Nawet różne dystrybucje Linuksa mają swoje pułapki, w które może wpaść nieuważny programista. Wystarczy powiedzieć, że Linux próbuje trafić na rynek i dlatego musi być adaptowany, używany i poszerzany przez innych. Dlatego właśnie należy dołożyć wszelkich starań, aby instalacja i aktualizacja utworzonej aplikacji przebiegała możliwie bez zakłóceń.

Jednym ze sposobów realizacji tego celu jest dostarczanie pakietów w postaci skompilowanej, które dają się łatwo zainstalować. Jeżeli dodatkowo dostarczony będzie pakiet źródłowy, to zainteresowani mogą przejrzeć i zmodyfikować kod. Wielu użytkowników Linuksa zna taki sposób dystrybucji oprogramowania w postaci pakietów. Jako przykład omówimy jedną z najpopularniejszych metod, a mianowicie pakiety RPM autorstwa firmy Red Hat. Przeanalizujemy te pakiety zarówno z punktu widzenia użytkownika, jak i z punktu widzenia programisty, który je musi utworzyć.

Możliwe, że opracowywana aplikacja jest budowana w sposób zależny od innych programów, na które programista nie ma wpływu. Na przykład interfejs graficzny dla debugera GDB będzie użyteczny tylko wtedy, gdy sam debuger zostanie zainstalowany. Nie tylko o to tutaj chodzi: może także wystąpić zależność od specyficznej wersji debugera.

Zamiast dołączać kopię GDB do swojej aplikacji, należy wprowadzić taką jawną zależność do pakietu binarnego. Dzięki temu użytkownik instalujący aplikację zostanie ostrzeżony, jeśli w jego systemie nie jest zainstalowany GDB lub jego wersja jest niedopasowana. W dalszej części tego rozdziału pokażemy, w jaki sposób rozwiązywane są takie zależności w pakietach RPM.

Instalowanie dostarczonej aplikacji może być tak proste i polegać np. na wstawieniu pliku binarnego do katalogu /usr/local/bin lub /opt. Musimy jednak pamiętać, że trzeba także uruchomić program konfiguracyjny, zainicjować bazę danych lub wykonać pewne czynności porządkujące przy instalacji pakietu lub przy jego usuwaniu. Pakiety w formacie RPM umożliwiają zautomatyzowanie tych wszystkich niezbędnych operacji.

Można nawet utworzyć własną dystrybucję systemu Linux, zbudowaną tak, aby pasowała i obsługiwała tylko rozpowszechnianą aplikację. Takie rozwiązanie spotyka się w praktyce w specjalistycznych aplikacjach, np. w serwerach komunikacyjnych.

Ponieważ spodziewamy się, że aplikacja rozprowadzana jako otwarte oprogramowanie będzie ulepszana przez społeczność użytkowników, to należy zastanowić się, jak wprowadzać takie modyfikacje, aby były zgodne z niezależnymi od producentów międzynarodowymi standardami, jak np. POSIX. Obsługa skomplikowanych wymagań narzucanych przez różnorodne platformy sprzętowe jest wspomagana przez dodatkowe narzędzia, dzięki którym program może działać na różnych maszynach — pokażemy tu więc zastosowanie poleceń configure i autoconf. Oczywiście, przestrzeganie standardów także może w tym wszystkim bardzo pomóc.

Istnieją wolne programy dla systemu Linux, które charakteryzują się nadzwyczaj wysoką jakością i z nimi należy konkurować. W rozdziale 2. przedstawiliśmy system CVS, który może być zastosowany w sieci do udostępniania kodu źródłowego. W tym rozdziale zapoznamy się z programem pomocniczym o nazwie patch, który może być użyty do dystrybucji poprawek kodu, zarówno niewielkich, jak i bardzo obszernych.

Popularne programy mogą budzić wielkie zainteresowanie objawiające się licznymi komentarzami na tematy ogólne, sugestiami ulepszeń i sygnalizowaniem kłopotów. Omówimy więc tu bardzo skrótowo system śledzenia błędów rozpowszechniany na zasadach GNU i noszący nazwę GNATS, wspomagający komunikację z użytkownikami.

Pakiety RPM

Pierwszy raz te pakiety zastosowano w dystrybucji Linuksa przygotowanej przez firmę Red Hat. Format RPM (skrót od Red Hat Package Manager) jest obecnie stosowany na szeroką skalę jako sposób rozprowadzania aplikacji, które mają być instalowane w systemie. RPM jest dostępny w różnych dystrybucjach, takich jak Red Hat (to oczywiste!), Mandrake (dystrybucja wywodząca się z Red Hat) i SuSE (dystrybucja niezależna). Ponieważ format RPM stał się znany i ma status wolnego oprogramowania, to można się spodziewać, że pewnego dnia będzie on obsługiwany w wielu innych dystrybucjach systemów Linux i UNIX.

Istnieją także pakiety o innych formatach, w szczególności należy tu wymienić pakiety DEB używane w dystrybucjach wywodzących się z dystrybucji Debian. Wiele z podanych w tym rozdziale reguł można odnieść także do pakietów DEB. W systemach korzystających z dystrybucji Debian należy wiec zapoznać się z dokumentacją programów dpkg i dselect. Jeżeli potrzeba, narzędzia RPM można także uruchomić w dystrybucji Debian.

Użytkownik RPM

Użytkownik Linuksa zazwyczaj spotyka się po raz pierwszy z pakietami RPM podczas instalacji systemu. Zarówno dystrybucja Red Hat, jak i SuSE rozpowszechniane są na płytach CD-ROM wypełnionych prawie całkowicie plikami w formacie RPM. Program instalacyjny zazwyczaj wyświetla menu z nazwami dostępnych pakietów (lub ich zbiorów) i instaluje wybrane z nich. Instalację pakietów RPM wykonuje program o nazwie rpm.

Po zakończeniu instalacji w wielu dystrybucjach można znaleźć graficzny instalator pakietów. W tej książce będziemy omawiać podstawowy instalator pakietów RPM, ponieważ można go stosować jeszcze przed instalacją i uruchomieniem X Window.

Program rpm jest stosowany wówczas, gdy trzeba zmodyfikować zainstalowany system, czyli w następujących okolicznościach:

Powyższe zadania nie są na ogół skomplikowane, lecz wymagają posiadania uprawnień superużytkownika, ponieważ podczas instalacji trzeba korzystać z obszarów systemowych w systemie plików (wyjaśnimy to za chwilę). Istnieją jednak operacje, które może wykonać zwykły użytkownik korzystający z rpm i od nich właśnie rozpoczniemy.

Program rpm może na pierwszy rzut oka onieśmielać. Po wpisaniu polecenia:

$ rpm --help

pojawi się dwustronicowa lista wszystkich opcji tego programu, przeznaczonych zarówno dla użytkownika instalującego gotowe pakiety RPM, jak i dla programisty tworzącego dystrybucyjne pakiety źródłowe lub binarne. Opiszemy tu kilka prostszych opcji, które pomagają zrealizować najczęściej spotykane zadania.

Program rpm może być uruchomiony w kilku trybach, zależnie od potrzeb użytkownika. Są to:

Do wyboru pakietu, który będzie używany jako przykład pokazujący instalację i aktualizację, użyjemy pierwszego z tych trybów. Tryb zapytań jest wywoływany za pomocą opcji -q.

Co naprawdę zostało zainstalowane?

Aby uzyskać listę wszystkich pakietów zainstalowanych przez program rpm, trzeba wywołać go w trybie zapytań z dodatkową opcją -a oznaczającą wszystkie pakiety:

$ rpm -q -a

aaa_base-99.11.11-2

aaa_dir-99.11.12-0

base-99.11.2-1

bash-2.03-26

bdflush-1.5-101

cpio-2.4.2-99

...

gnuchess-4.0.pl80-5

...

xboard-4.0.0-68

...

dia-0.81-1

pg_datab-6.5-21

pg_ifa-6.5.1-18

pg_iface-6.5.1-15

postgres-6.5.1-18

$

W dobrze wyposażonym systemie SuSE uzyskuje się w ten sposób listę zawierającą nazwy ponad tysiąca pakietów, które są zainstalowane. Kilka ostatnich podanych wyżej pozycji informuje, że baza danych PostgreSQL jest zainstalowana w najnowszej dostępnej wersji.

Nazwy pakietów mają następującą postać:

<nazwa_pakietu>-<wersja_pakietu>-<numer_wydania>

Nazwa pakietu jest zwykle nazwą głównej biblioteki lub programu zawartych w pakiecie. Wersja pakietu oznacza numer wersji aplikacji zawartej w tym pakiecie. Numer wydania jest powiększany za każdym razem przy budowie znowelizowanego pakietu RPM przeznaczonego do dystrybucji. Na przykład pakiet zawierający bazę danych PostgreSQL ma nazwę postgres-6.5.1-18. i jest osiemnastym kolejnym pakietem zawierającym bazę PostgreSQL w wersji 6.5.1.

Pakiety są przebudowywane z wielu powodów. Przeważnie decyduje o tym konieczność zmiany miejsca instalacji lub skryptów uruchamianych automatycznie podczas instalacji. Nowy pakiet zawierający nową wersję aplikacji zawsze ma numer wydania równy 1, tak jak w przykładowym pakiecie dia-0.81-1 na powyższej liście.

Baza danych RPM

Program rpm utrzymuje swoją bazę danych zawierającą informacje o pakietach, plikach znajdujących się w tych pakietach i ich wzajemnych zależnościach, aby zachować ślad wszystkich instalacji pakietów w systemie Linux. Baza ta jest na ogół przechowywana w katalogu /var/lib/rpm. Prawie wszystkie pliki w tym katalogu są plikami bazy danych (jest to baza typu dbm używana w systemach UNIX). Program rpm umożliwia obsługę tej bazy w różny sposób.

Na tym etapie wystarczy, aby Czytelnik zdawał sobie sprawę z tego, że każde dodanie, aktualizacja lub usunięcie pakietu powoduje aktualizację bazy danych.

Co znajduje się w pakiecie?

Kolejną informacją, którą może podać program rpm, jest lista plików zawartych w danym pakiecie. Użyjemy dwóch pakietów z podanej wcześniej listy: gnuchess i xboard (są to odpowiednio: program szachowy i jego interfejs graficzny).

$ rpm -q xboard gnuchess

xboard-4.0.0-68

gnuchess-4.0.pl80-5

$

Listę plików zawartych w pakiecie uzyskujemy, podając dodatkowo opcję -l:

$ rpm -q -l gnuchess

/usr/bin/game

/usr/bin/gnuan

/usr/bin/gnuchess

/usr/bin/gnuchessc

/usr/bin/gnuchessn

/usr/bin/gnuchessr

/usr/bin/gnuchessx

/usr/bin/postprint

/usr/lib/eco.pgn

/usr/lib/gnuchess.data

/usr/lib/gnuchess.eco

/usr/lib/gnuchess.lang

/usr/man/man6/game.6.gz

/usr/man/man6/gnuan.6.gz

/usr/man/man6/gnuchess.6.gz

/usr/man/man6/postprint.6.gz

$

Do wyszukania pakietu, w którym jest zawarty dany plik, należy w trybie zapytań użyć dodatkowej opcji -f:

$ rpm -q -f /usr/X11R6/bin/xboard

xboard-4.0.0-68

$

W zapytaniu można podać dowolną liczbę szukanych plików i wówczas rpm wyświetli listę wszystkich pakietów, w których są one użyte. Więcej informacji na temat użycia tych opcji można znaleźć na stronach podręcznika systemowego dotyczących programu rpm.

Usuwanie pakietu

Zmiany w instalacji systemu Linux może wprowadzać tylko superużytkownik. Korzystając z programu rpm jako superużytkownik, trzeba zachować wyjątkową ostrożność, ponieważ można bardzo łatwo zniszczyć działający system, usuwając przypadkowo jakiś pakiet. Przykładowo usuniemy więc program o mniejszym znaczeniu, czyli interfejs do programu szachowego o nazwie xboard.

Można podjąć próbę usunięcia pakietu, podając opcję -e (od słowa erase) w wywołaniu programu rpm i nazwę usuwanego pakietu. Długie nazwy pakietów RPM są często skracane i tutaj również należy podać tylko jej pierwszy człon, czyli samą nazwę bez numerów wersji i wydania. Można tak postąpić, ponieważ w systemie zazwyczaj nie mogą współistnieć dwie wersje tego samego pakietu. Takie skrócone nazwy były także używane w poprzednich przykładach pokazujących pracę w trybie zapytań.

$ su -

Password:

# rpm -e xboard

#

Przy próbie sprawdzenia obecności pakietu pojawi się komunikat, że nie jest on zainstalowany:

# rpm -q xboard

package xboard is not installed

#

Teraz spróbujemy usunąć sam program szachowy gnuchess:

# rpm -e gnuchess

error: removing these packages would break dependencies:

gnuchess is needed by glchess-0.10d-67

#

Komunikat wyświetlony w odpowiedzi oznacza, że istnieje jeszcze jeden zainstalowany pakiet o nazwie glchess, którego działanie zależy od obecności programu gnuchess. Możemy dokładnie sprawdzić, co to za pakiet.

Status pakietu

Informacje o pakiecie można uzyskać, podając w wywołaniu programu rpm w trybie zapytań dodatkową opcję -i (od słowa information):

$ rpm -q -i glchess

Name : glchess Relocation: (not relocateable)

Version : 0.10d Vendor: SuSE GmbH, Nuernburg, Germany

Release : 67 Build Date: Sat 13 Nov 1999 16:13:38 GMT

Install date: Sun 02 Jan 2000 17:50:14 GMT Build Host: stott.suse.de

Group : unsorted Source RPM: glchess-0.10d-67.src.rpm

Size : 171581 License: GPL

Packager : feedback@suse.de

Summary : 3D fronted for gnuchess

Description:

glchess is a fine 3D mesa fronted for gnuchess

Authors:

-------

Tomi.Sarvela@iki.fi

$

Widać więc, że pakiet glchess jest kolejnym interfejsem graficznym programu gnuchess wyświetlającym trójwymiarowy obraz. Przestanie on działać, jeśli usunęliśmy program gnuchess. Jeżeli trzeba usunąć z komputera wszystkie programy umożliwiające grę w szachy, to wśród nich musi się znaleźć także program glchess:

# rpm -e glchess gnuchess

#

Tym razem nie ma żadnych problemów. Przy jednym wywołaniu programu rpm usunięto jednocześnie dwa pakiety, podając ich nazwy w jednym poleceniu i nie spowodowało to wyświetlenia komunikatu o zakłóceniu zależności glchess od gnuchess.

Zagadnienie zależności między pakietami omówimy szerzej w dalszych częściach rozdziału.

Instalowanie pakietów

Jeżeli istnieje plik z pakietem RPM, który trzeba zainstalować, to należy użyć opcji -i (od słowa install) w wywołaniu programu rpm. W przypadku pakietów z dystrybucji Linuksa trzeba będzie zapewne znaleźć ten plik na płycie CD-ROM. Niestety, baza danych programu rpm nie zapisuje informacji o lokalizacji instalowanych pakietów.

Pokażemy tu sposób instalacji na przykładzie programów szachowych.

Najpierw należy odszukać pliki zawierające potrzebne pakiety. Ich lokalizacja zależy od wielu czynników, a głównie od dystrybucji i użytego nośnika danych. Jeżeli pakiet był pobrany ze strony internetowej, to do instalacji wystarczy podanie jego nazwy w poleceniu programu rpm. W naszym przykładzie będziemy instalować pakiet z płyty DVD dystrybucji SuSE:

# mount /cdrom

# cd /cdrom/suse/fun1

# ls

3d_chess.rpm figlet.rpm oonsoo.rpm xbl.rpm xpilot.rpm

3dpong.rpm fishtank.rpm pacman.rpm xblast.rpm xpinguin.rpm

INDEX flying.rpm pingus.rpm xboard.rpm xpuzzles.rpm

INDEX.english fortune.rpm pipeman.rpm xboing.rpm xracer.rpm

INDEX.german freeciv.rpm playone.rpm xbomb.rpm xroach.rpm

MD5SUMS frisk.rpm puzzle.rpm xbombs.rpm xrobots.rpm

TRANS.TBL frotz.rpm pysol.rpm xdemine.rpm xshogi.rpm

abuse.rpm glchess.rpm rockdiam.rpm xearth.rpm xskat.rpm

aleclone.rpm gnuchess.rpm sastroid.rpm xengine.rpm xsnow.rpm

anachron.rpm gnugo.rpm space.rpm xfact.rpm xsok.rpm

antipoli.rpm gshogi.rpm spellc.rpm xgammon.rpm xsol.rpm

asclock.rpm hextris.rpm tf.rpm xgas.rpm xspringi.rpm

astrolog.rpm imaze.rpm tfhelp.rpm xjewel.rpm xtacy.rpm

batalion.rpm lincity.rpm thrust.rpm xlife.rpm xtartan.rpm

battball.rpm maelstr.rpm tux_aqfh.rpm xlyap.rpm xteddy.rpm

bsdgames.rpm manix.rpm tuxeyes.rpm xmahjong.rpm xtetris.rpm

bzflag.rpm meltflip.rpm vgacard.rpm xmemory.rpm xthing.rpm

craft.rpm mirrma.rpm x3d.rpm xmine.rpm xtron.rpm

crafty.rpm moontool.rpm xabacus.rpm xmines.rpm xvier.rpm

crosfire.rpm net3d.rpm xancur.rpm xmaounts.rpm yahtzee.rpm

daliclck.rpm nethack.rpm xaos.rpm xmris.rpm

emiclck.rpm netmaze.rpm xball.rpm xpat2.rpm

empire.rpm oneko.rpm xbill.rpm xphoon.rpm

#

Widzimy tu bardzo wiele pakietów RPM, a wśród nich także gnuchess i xboard. Jeżeli spróbujemy zainstalować pojedynczo pakiet xboard, to tak jak należy oczekiwać, pojawi się komunikat o niespełnionych zależnościach:

# rpm -i xboard.rpm

error: failed dependencies:

gnuchess is needed by xboard-4.0.0-68

#

Można instalować wiele pakietów równocześnie (i tak trzeba postępować, jeśli są one od siebie nawzajem zależne), podając ich nazwy w tym samym wierszu poleceń:

# rpm -i xboard.rpm gnuchess.rpm

#

Aktualizacja pakietu

Jeżeli jest zainstalowana wcześniejsza wersja pakietu i chcemy ją zaktualizować, to w programie rpm zamiast opcji -i należy użyć opcji -U (od słowa upgrade). Opcja ta działa prawie tak samo jak opcja instalacyjna, z tą różnicą, że pliki są zastępowane ich nowszymi wersjami. Opcja -i nie pozwala na zainstalowanie innej wersji pakietu, jeżeli jakąś jego wersję zainstalowano już wcześniej.

Instalatory graficzne

Ponieważ instalacja pakietów RPM jest operacją wykonywaną dość często, powstało wiele programów pomocniczych wspomagających tę czynność. W środowisku GNOME jest stosowany program gnorpm, który umożliwia graficzny wybór pakietów, a następnie ich instalację lub usunięcie. W środowisku KDE można znaleźć podobne narzędzie o nazwie kpackage (wygląd okna tego programu pokazano na rysunku niżej). Starsze dystrybucje Red Hat zawierały program o nazwie glint. Poza systemem X Window spotyka się tego rodzaju programy z interfejsem znakowym, jak np. YaST z dystrybucji SuSE.

0x01 graphic

Takie narzędzia mogą być bardzo przydatnej w codziennych pracach utrzymaniowych, ale do dnia dzisiejszego żadne z nich nie zawiera pełnej funkcjonalności programu rpm.

Sprawdzanie zależności

Aby sprawdzić zależności istniejące między zainstalowanymi pakietami, należy w trybie zapytań programu rpm użyć dodatkowej opcji -R (lub --requires):

$ rpm -q -R xboard

gnuchess

/bin/sh

/usr/bin/perl

ld-linux.so.2

libICE.so.6

libSM.so.6

libX11.so.6

libXaw.so.6

libXext.so.6

libXmu.so.6

libXt.so.6

libc.so.6

libc.so.6(GLIBC_2.0)

$

Łatwo tu zauważyć, że pakiet xboard wymaga pakietu gnuchess i kilku innych elementów (czyli bibliotek X Window, programu perl oraz powłoki sh).

Każda z pozycji powyższej listy określa pewne właściwości. Każdy pakiet RPM zapewnia jedną lub więcej takich właściwości i przy instalacji może wymagać, aby w systemie były dostępne także inne właściwości. Sam plik RPM przechowuje te właściwości. Wzajemne zależności pakietów są po prostu odzwierciedleniem tych właściwości, których nie zawiera dany pakiet. Można sprawdzić, jakimi właściwościami dysponuje pakiet, podając w trybie zapytań dodatkową opcję --provides.

Zastosujemy teraz te opcje do zbadania biblioteki XML. Dzięki tej bibliotece (opisywanej w rozdziale 23.) programy mogą odczytywać i tworzyć pliki w formacie XML, coraz częściej stosowanym w wymianie danych.

Oto przykład sprawdzenia wersji:

$ rpm -q libxml

libxml-1.7.3-5

$

Następnie sprawdzamy, jakich właściwości dostarcza pakiet:

$ rpm -q --provides libxml

libxml

libxml.so.1

libxml.so.1(GCC.INTERNAL)

$

Możemy się przekonać, że badany pakiet udostępnia kilka możliwości. Na liście znajdują się zarówno właściwości ogólne, jak i właściwości specyficzne dla tego pakietu. Pakiet zawiera bibliotekę XML (libxml) w specyficznej wersji dzielonej (libxml.so.1).

Należy bardzo uważnie sprawdzać zależności między pakietami, ponieważ niektóre z nich wymagają specyficznych wersji jakichś właściwości (sama właściwość ogólna nie wystarcza).

Możemy odszukać pakiety, które dysponują określonymi właściwościami, używając w trybie zapytań dodatkowej opcji --whatprovides:

$ rpm -q --whatprovides libxml

libxml-1.7.3-5

$

Można szukać zależności odwrotnych i sprawdzać, który zainstalowany pakiet wymaga danej właściwości. Służy do tego dodatkowa opcja --whatrequires podana w trybie zapytań:

$ rpm -q --whatrequires libxml

libglad-0.7-5

libxmld-1.7.3-5

$

Widzimy, że kilka pakietów także wymaga obecności libxml, ale co można powiedzieć na temat aplikacji? Wymagają one zazwyczaj specyficznej wersji dzielonej biblioteki, co sprawdzamy w następujący sposób:

$ rpm -q --whatrequires libxml.so.1

gnorpm-0.9-3

gnprint-0.10-5

gnumeric-0.41-5

libglad-0.7-5

$

Widzimy tu, że instalator pakietów dla środowiska GNOME o nazwie gnorpm oraz kilka innych aplikacji jawnie wymagają obecności dzielonej biblioteki libxml w wersji 1.

Pomijanie zależności

Czasami dany pakiet jest zależny od innego pakietu, który nie został zainstalowany, albo zainstalowano go w odmienny sposób. Aby poradzić sobie w takiej sytuacji, można pominąć sprawdzanie zależności pakietów przez program rpm, podając w trybie instalacyjnym dodatkową opcję --nodeps:

# rpm -i xboard.rpm

error: failed dependencies:

gnuchess is needed by xboard-4.0.0-68

# rpm -i --nodeps xboard.rpm

#

Jeżeli chcemy zainstalować pakiet, który jest już zainstalowany, to program rpm na to nie pozwoli. Można ominąć takie zachowanie programu za pomocą dodatkowej opcji --force podanej w trybie instalacyjnym. Opcja ta bywa przydatna przy instalacji wcześniejszej wersji pakietu w sytuacjach, gdy została zainstalowana jego nowsza wersja.

Inne opcje

Istnieje kilka innych opcji przydatnych dla użytkowników pakietów RPM. Można np. wyświetlić skrypt uruchamiany przy instalacji lub usuwania pakietu, podając dodatkową opcję --scripts:

$ rpm -q --scripts postgres

postinstall script (through /bin/sh):

if [ -x bin/fillup ] ; then

bin/fillup -q -d = etc/rc.config var/adm/fillup-templates/rc.config.postgres

else

echo "ERROR: fillup not found. This should not happen. Please compare"

echo "etc/rc.config and var/adm/fillup-templates/rc.config.postgres and"

echo "update by hand."

fi

touch var/log/postgresl.log

if [ "$UID" = "0" ] ; then

chown postgres.daemon var/log/postgresl.log

fi

preuninstall script (through /bin/sh):

if [ -x sbin/init.d/postgres ] ; then

sbin/init.d/postgres stop

sleep

fi

$

W powyższym przykładzie można np. odczytać, że skrypt uruchamiany przed usunięciem pakietu PostgreSQL zatrzymuje przed wykonaniem tej operacji usługę postgres.

Jeżeli trzeba zapobiec uruchamianiu skryptów przy instalacji (-i) lub usuwaniu (-e) pakietu, należy użyć dodatkowo opcji --noscripts.

Sprawdzanie, czy instalacja pakietu odbędzie się poprawnie, odbywa się dla opcji --test. Wówczas nastąpi sprawdzenie zależności, lecz nie odbędzie się faktyczna instalacja plików z pakietu.

Dodatkowa opcja -v (od słowa verbose) powoduje wyświetlanie obszerniejszych komunikatów przy niektórych opcjach trybu zapytań.

# rpm -i -v -h xboard.rpm gnuchess.rpm

xboard ##############################################

gnuchess ########################

#

Opcje o nazwach jednoliterowych można ze sobą łączyć, więc -ivh oznacza to samo, co trzy oddzielnie podane opcje -i -v -h w powyższym przykładzie.

Program rpm może również instalować pakiety bezpośrednio z Internetu za pomocą protokołu FTP lub HTTP. Wystarczy wtedy jako nazwę pakietu podać jego pełny adres internetowy. Więcej informacji na temat użycia niestandardowych portów i serwerów pośredniczących w instalacji poprzez sieć można znaleźć na stronach podręcznika systemowego do programu rpm.

Baza danych RPM umożliwia sprawdzenie poprawności zainstalowanych pakietów. Jeżeli przypadkowo zostaną usunięte jakieś pliki i trzeba sprawdzić, co zostało zniszczone, należy posłużyć się opcją -V (od słowa verify).

# rm /usr/bin/gnuchess

# rpm -V gnuchess

missing /usr/bin/gnuchess

W powyższym przykładzie można stwierdzić, że zniszczona jest instalacja gnuchess, ponieważ brakuje głównego pliku programu.

Można zweryfikować (-V) poprawność instalacji wszystkich (-a) pakietów jednocześnie (przy dużych instalacjach trochę to potrwa). Każdy zainstalowany plik jest wówczas poddawany kilku testom. Wyświetlane są nazwy tych plików, które nie przejdą pomyślnie wszystkich testów, łącznie z wynikami testów:

# rpm -V -a

S.5....T c /etc/modules.conf

S.5....T c /etc/hosts

.....U.. /var/spool/fax

Unsatisfied dependencies for shlibs5-99.11.10-1: libgif.so

missing /var/catman

$

W każdym wierszu wyjściowym podawany jest ośmioznakowy wyniku testu — wskaźnik, czy dany plik jest lub nie jest plikiem konfiguracyjnym (c). Podawane są także niespełnione zależności i brakujące pliki. Wynik testu jest po prostu wynikiem porównania faktycznych atrybutów danego pliku z atrybutami zapamiętanymi w bazie danych RPM. Różniące się atrybuty są oznaczane w następujący sposób:

.

(kropka) pomyślny wynik testu

S

rozmiar pliku

M

uprawnienia do pliku

U

użytkownik

G

grupa

5

suma kontrolna MD5

T

data modyfikacji

L

dowiązanie symboliczne

D

urządzenie

Komunikaty pojawiające się podczas weryfikacji należy traktować z pewną rezerwą, ponieważ nie wszystkie nieudane testy oznaczają jakiś problem. Wiele plików zmienia się zgodnie z zasadami sztuki podczas użytkowania systemu, np. pokazany w powyższym przykładzie plik /etc/hosts, do którego zostały dopisane adresy komputerów z sieci lokalnej.

Pakiety, które nie są zainstalowane

Większość z dotychczas omówionych operacji przeprowadzanych w trybie zapytań dotyczyła pakietów, które są zainstalowane. Czasami jednak trzeba się dowiedzieć, które pakiety powinny zostać zainstalowane, aby uzyskać wymagane właściwości lub pliki. Aby uzyskać taką informację, należy użyć opcji -p.

Jeżeli musimy znaleźć pakiet, który zawiera specyficzny plik (np. /usr/bin/gnuchess) i nie mamy takiego pliku zainstalowanego, to tryb zapytań nie dostarczy takiej informacji. Zapytanie o właściwość gnuchess także nic nie da:

$ rpm -q -f /usr/bin/gnuchess

file /usr/bin/gnuchess: No such file or directory

$ rpm -q --whatprovides gnuchess

no package provides gnuchess

$

Musimy więc spowodować, aby pliki z pakietami RPM same dostarczały informacje o sobie. Można sprawdzać wersję, posiadane właściwości, pliki zawarte w pakiecie, skrypty oraz zależności:

$ cd <katalog z pakietami rpm>

$ rpm -q -p gnuchess.rpm

gnuchess-4.0.p180-5

$ rpm -q --provides -p gnuchess.rpm

gchess

gnuchess

$ rpm -q -l -p gnuchess.rpm

/usr/bin/name

/usr/bin/gnuan

/usr/bin/gnuchess

...

Niestety, nie jest możliwe użycie opcji --whatprovides lub --whatrequires dla grupy pakietów, które nie są zainstalowane. W takim wypadku trzeba więc sprawdzać oddzielnie każdy niezainstalowany pakiet:

$ for p in *.rpm

> do

> rpm -q -R -p $p | grep -s gnuchess

> if [ "$?" = "0" ]

> then

> echo $p

> fi

> done

glchess.rpm

xboard.rpm

$

Dopiero na podstawie powyższych komunikatów można stwierdzić, że spośród pakietów znajdujących się w danym katalogu jedynie glchess i xboard wymagają obecności gnuchess. Teraz można zlokalizować gnuchess i naprawić uszkodzoną instalację, instalując pakiet gnuchess — co wynikało z weryfikacji przeprowadzonej za pomocą opcji -V.

Anatomia pakietu RPM

Przyjrzymy się teraz typowemu pakietowi RPM. Oto postgres.rpm wzięty z dystrybucji SuSE:

$ ls -ls postgres.rpm

2844 -rw-r--r-- 1 neil users 2905041 Apr 16 13:09 postgres.rpm

$ file postgres.rpm

postgres.rpm: RPM v3 bin i386 postgres-6.5.1-18

$

Typ pliku jest rozpoznawany za pomocą polecenia file, ponieważ struktura tego pliku została dodana do bazy danych /etc/magic. Plik jest rozpoznawany dlatego, że rozpoczyna się od określonego nagłówka zawierającego informację, że jest to właśnie pakiet RPM. Nagłówek zawiera także magiczną liczbę (ang. magic number) oznaczającą, czy jest to plik binarny lub czy zawiera kod źródłowy. W przypadku plików binarnych odnotowany jest także rodzaj sprzętu użytego do kompilacji. Umieszczony jest tu również napis zawierający nazwę pakietu oraz numery wersji i wydania. Te wszystkie atrybuty nagłówka są wyświetlane za pomocą polecenia file.

W rzeczywistości każdy plik z pakietem RPM stanowi archiwum (podobnie jak tar lub cpio) zawierające pliki, które trzeba zainstalować. Pliki RPM są skompresowane i zwierają sumę kontrolną umożliwiającą sprawdzenie ich integralności.

Aby lepiej poznać wewnętrzną strukturę pakietu RPM, przekształćmy go na archiwum cpio za pomocą programu rpm2cpio. Program ten wymaga podania nazwy pakietu RPM jako argumentu w wierszu poleceń (lub ze standardowego wejścia), a następnie zapisuje archiwum cpio na standardowe wyjście:

$ rpm2cpio postgres.rpm > postgres.cpio

$

Listę plików zawartych w archiwum można uzyskać za pomocą polecenia cpio:

$ cpio -t <postgres.cpio

etc/profile.d/postgres.csh

etc/profile.d/postgres.sh

sbin/init.d/postgres

sbin/init.d/rc2.d/K15postgres

sbin/init.d/rc.2/S25postgres

sbin/init.d/rc3.d/K15postgres

sbin/init.d/rc3.d/S25postgres

usr/doc/packages/postgres

usr/doc/packages/postgres/COPYRIGHT

usr/doc/packages/postgres/CVS

...

Tę metodę przekształcania na archiwum cpio można nawet zastosować do uzyskiwania pojedynczych plików z pakietu RPM bez przeprowadzania instalacji całego pakietu.

Pakiety źródłowe

Niezależnie od tego, że wiele aplikacji rozprowadza się w postaci binarnej między innymi jako pakiety RPM, to czasem należy koniecznie zbudować program z plików źródłowych. Najnowsze wersje aplikacji nie zawsze są od razu udostępniane w postaci pakietów, a czasem trzeba także dopasować aplikację do lokalnego środowiska — a to wymaga kompilacji.

Możliwe jest utworzenie pakietu RPM zawierającego kod źródłowy. Często takie pakiety nazywane są skrótowo SRPM (od słów Source RPM) lub spm. Kody źródłowe są najczęściej rozprowadzane w postaci archiwum tar. Takie archiwum nazywane bywa potocznie tarball i przeważnie jest skompresowane. Oprócz kodu źródłowego może ono także zawierać specyfikację, którą można wykorzystać do budowy binarnego pakietu RPM. Źródłowe pakiety RPM zazwyczaj zawierają takie skompresowane archiwum z kodem źródłowym.

Użytkownicy posługujący się źródłowymi skompresowanymi archiwami przeprowadzają często kompilację i instalację w następujący sposób:

$ tar zxvf application.tar.gz

$ cd application

$ ./configure

$ make

$ su -

# make install

Czasami występuje jeszcze etap sprawdzania (make check), jeśli aplikacja została wyposażona w testujące programy lub skrypty.

Każdy, kto chociaż raz instalował oprogramowanie objęte nadzorem Free Software Foundation, od razu rozpozna powyższą sekwencję poleceń. Jest to standard opracowany dla projektu GNU, który znalazł wielu naśladowców. Celem tego standardu jest jak największe ułatwienie kompilacji i umożliwienie jej przeprowadzenia na wielu różnorodnych platformach sprzętowych. Przyjrzymy się teraz bliżej poszczególnym etapom.

Jeżeli spojrzymy na zawartość katalogu z aplikacją, przeważnie znajdziemy tam kilka pomocnych plików. Stanowią one części standardu budowania aplikacji i obejmują:

COPYING

Zawiera szczegóły licencyjne oraz warunki kopiowania

ChangeLog

Opisy ostatnich zmian

FAQ

Często zadawane pytania i udzielane odpowiedzi

INSTALL

Opis sposobu instalowania aplikacji

NEWS

Opis nowych właściwości

README

Opis aplikacji i jej zadania

TODO

Plany na przyszłość

Użycie tego rodzaju plików w aplikacji pomaga użytkownikowi znaleźć odpowiedzi na jego wątpliwości bez potrzeby wysyłania raportu o błędach.

configure, autoconf i automake

Istnieje kilka narzędzi wspomagających tworzenie standardowego katalogu z kodem źródłowym gotowego do dystrybucji. Są to configure, autoconf i automake. Pełny zakres zastosowań tych programów narzędziowych wykracza, niestety, poza ramy tego rozdziału. Wielu ekspertów może stwierdzić, że najlepszą metodą użycia tych narzędzi jest skopiowanie jakiejś działającej konfiguracji. Omówimy tu w skrócie niektóre pliki używane podczas tworzenia katalogu z kodem źródłowym oraz opiszemy konfigurację umożliwiającą utworzenie przenośnej aplikacji. Dalsze informacje można znaleźć na stronie info programów autoconf i automake.

Jak już wspomniano wcześniej, skrypt powłoki o nazwie configure stanowi ważną część standardowej dystrybucji źródeł aplikacji. Jest to elegancki skrypt, który może sprawdzić wersję aplikacji oraz obecność bibliotek i skonfigurować opcje używane przy tworzeniu pliku makefile.

Najczęściej używaną opcją podczas uruchamiania skryptu configure jest prawdopodobnie opcja --prefix. Definiuje ona katalog najwyższego poziomu dla instalacji aplikacji, która jest konfigurowana i dzięki temu pozwala użytkownikowi na podjęcie decyzji o zaakceptowaniu lub odrzuceniu wartości domyślnych. Zwykle skrypt konfiguracyjny konfiguruje wszystko w taki sposób, aby wynikowa aplikacja rezydowała gdzieś w katalogu /usr/local, binarne pliki programów były umieszczane w /usr/local/bin, zaś strony podręcznika systemowego w /usr/local/man itd. Zastosowanie opcji --prefix umożliwia zmianę domyślnej lokalizacji katalogu najwyższego poziomu (/usr/local) na coś innego (np. /opt lub coś związanego z numerem wersji, jak /usr/local/app-1.0). Inne aplikacje mogą mieć zdefiniowane własne skrypty konfiguracyjne umożliwiające np. budowę fragmentu całego zestawu aplikacji.

Sam skrypt configure przeważnie nie jest pisany ręcznie, ponieważ zawiera wiele powtarzalnych elementów, jest on natomiast generowany przez program autoconf. Skrypt utworzony za pomocą programu autoconf nie wymaga obecności tego programu podczas uruchamiania, ponieważ jest skryptem powłoki (zazwyczaj dosyć długim). Program autoconf tworzy taki skrypt na podstawie szablonu zawierającego informację o właściwościach lub innych pakietach wymaganych przez aplikację.

Zajmijmy się przykładem prostego użycia programu autoconf. Omawiany w książce testowy program dla aplikacji obsługującej wypożyczalnię płyt DVD korzysta z biblioteki GNU o nazwie readline obsługującej wprowadzane danych wejściowych. Jeżeli spróbujemy skompilować taką aplikację w systemie nie dysponującym biblioteką readline, to kompilacja się nie uda. Jest to wielka szkoda, ponieważ program testowy korzystający z readline nie zależy tylko od tej biblioteki. Jest ona używana tylko przy edycji wiersza poleceń i jej brak nie zmniejsza właściwości użytkowych samego programu. Najprostszym sposobem na uniknięcie takich kłopotów jest napisanie kodu w taki sposób, aby wywołania funkcji z biblioteki readline odbywały się warunkowo, np. za pomocą dyrektywy #define.

Najpierw należy utworzyć plik wejściowy, który będzie używany przez program autoconf. Plik ten nazywa się configure.in. Jeżeli dołączane są testy sprawdzające np. dostępność jakichś narzędzi lub bibliotek, można je włączyć w postaci skryptów powłoki, zapisywanych zazwyczaj w pliku o nazwie aclocal.m4. Program autoconf bardzo intensywnie korzysta z procesora makropoleceń m4, więc trzeba szerzej się z nim zapoznać, studiując jego strony info. Jeżeli potrzebny jest plik dołączany w języku C sterujący wykorzystaniem różnych właściwości przez aplikację, to trzeba utworzyć plik o nazwie config.h.in.

Program autoconf obsługuje bardzo wiele makropoleceń służących do testowania i prawdopodobnie wystarczą one dla zaspokojenia większości wymagań. Szczegóły można znaleźć w dokumentacji do tego programu.

Korzystając ze skryptu configure chcemy osiągnąć w naszej aplikacji dwa cele. Po pierwsze, chcemy wygenerować konfiguracyjny plik nagłówkowy, który będzie mógł przełączać nasz kod zależny od biblioteki readline. Po drugie — chcemy utworzyć plik makefile, który będzie wykorzystany do skonsolidowania aplikacji z odpowiednimi bibliotekami.

Plik nagłówkowy jest tworzony na podstawie następującego szablonu o nazwie config.h.in:

/*

config.h

Ustawienie opcji kompilacji

*/

/* Włączenie tej definicji, jeśli jest dostępna biblioteka readline */

#define HAVE_READLINE 0

Zmienna HAVE_READLINE zostanie przedefiniowana przez skrypt configure po jego uruchomieniu. Zbudujemy ten skrypt tak, aby zmiennej HAVE_READLINE nadawał wartość 1 albo 0, zależnie od tego, czy plik dołączany readline jest obecny w systemie, czy nie.

Oto przykład prostego pliku configure.in:

dnl Przetworzenie tego pliku przez autoconf daje skrypt configure.

AC_INIT(dvdstore.c)

AC_CONFIG_HEADER(config.h)

dnl Sprawdzenie obecności programów.

AC_PROG_CC

dnl Sprawdzenie obecności bibliotek.

dnl Sprawdzenie obecności plików nagłówkowych.

AC_HEADER_STDC

AC_CHECK_HEADERS(readline/readline.h, AC_DEFINE(HAVE_READLINE)

dnl Sprawdzenie definicji typów, struktur i charakterystyki kompilatora.

dnl Sprawdzenie obecności funkcji bibliotecznych.

AC_OUTPUT()

Wiersze rozpoczynające się od oznaczenia dnl są komentarzami, które makroprocesor m4 usuwa podczas pracy (dnl jest skrótem od „delete to new line”, czyli „usuń tekst aż do końca wiersza”). W pliku jest kilka wywołań makropoleceń, które mogą być umieszczane praktycznie w dowolnej kolejności. Jedynie wywołania AC_INIT i AC_CONFIG_HEADER muszą być umieszczone na początku, zaś AC_OUTPUT na końcu pliku. Pozostałe pokazane tu sekcje są w większości puste; ilustrują jedynie zalecaną kolejność testów. Testy mogące sprawić jakieś kłopoty zwykle są umieszczane wcześniej.

Makropolecenie AC_INIT jest używane przez skrypt configure do inicjacji. Przekazuje on nazwę pliku, który musi istnieć w katalogu zawierającym dane źródłowe. Skrypt sprawdza, czy ten plik istnieje i czy dzięki temu może dalej pracować we właściwej lokalizacji.

Makropolecenie AC_CONFIG_HEADER deklaruje nazwę konfiguracyjnego pliku nagłówkowego — w naszym przypadku jest to config.h.

Test AC_PROG_CC jest pierwszym testem uruchamianym przez skrypt configure. Sprawdza on obecność kompilatora języka C. Potem następuje test sprawdzający obecność standardowych plików nagłówkowych biblioteki języka C. Następnie dochodzimy do pierwszego zadania, które ma wykonać skrypt configure, czyli sprawdzenia obecności pliku nagłówkowego biblioteki readline. Jeżeli ten plik zostanie znaleziony, zdefiniowana zostanie zmienna HAVE_READLINE.

Na zakończenie makropolecenie AC_OUTPUT powoduje, że skrypt configure zaktualizuje swoje pliki wyjściowe (w tym przypadku będzie to plik config.h), wprowadzając do niego wymagane wyniki testów.

Przejdźmy teraz do praktyki. Najpierw uruchamiamy program autoconf, aby utworzyć skrypt konfiguracyjny:

$ autoconf

$

Następnie uruchamiamy ten skrypt w celu utworzenia pliku nagłówkowego:

$ ./configure

creating cache ./config.cache

checking how to run the C preprocessor... cc -E

checking for ANSI C header files... yes

checking for readline/readline.h... yes

updating cache ./config.cache

creating ./config.status

creating config.h

$

Przeglądając plik nagłówkowy, możemy dostrzec zmianę dyrektywy #define, odzwierciedlającą fakt, że w naszym systemie jest zainstalowana biblioteka readline:

/* config.h. Generated automatically by configure. */

/*

config.h

Ustawienie opcji kompilacji

*/

/* Włączenie tej definicji, jeśli jest dostępna biblioteka readline */

#define HAVE_READLINE 1

Inne wstępnie zdefiniowane makropolecenia skryptu konfiguracyjnego umożliwiają sprawdzenie obecności samego kodu biblioteki (a nie tylko jej pliku nagłówkowego) oraz tego, czy w tym kodzie istnieją funkcje wymagane przez naszą aplikację. Zakładamy tutaj, że jeśli istnieje plik nagłówkowy, to biblioteka readline także jest prawidłowa!

Można także sprawdzić, czy utworzony plik makefile poradzi sobie z brakiem biblioteki readline. W tym celu można utworzyć zmienną w skrypcie konfiguracyjnym, która umożliwi edycję pliku makefile w taki sam sposób, jak to się stało z plikiem config.h.

Musimy więc utworzyć szablon pliku makefile, który będzie modyfikował skrypt konfiguracyjny. W opisywanym przykładzie w pliku o nazwie Makefile.in używamy nazw zmiennych otoczonych znakami „@”:

RLIB = @RLIB@

dvdstiore: dvdstore.o

$(CC) -o dvdstore dvdstore.o dvd_pg.a $(RLIB)

Jest to bardzo prosty plik makefile utworzony tylko dla celów pokazowych. Chcemy, aby skrypt configure ustawiał zmienną RLIB, jeżeli istnieje możliwość skonsolidowania aplikacji z biblioteką readline, albo pozostawiał ją pustą, jeżeli biblioteka nie jest dostępna.

Musimy więc wprowadzić pewne zmiany do pliku configure.in, aby działało to w pożądany sposób:

...

dnl Sprawdzenie obecności funkcji bibliotecznych.

AC_CHECK_LIB(readline, rl_bind_key,

RLIB="-lreadline -lncurses",

[],

-lncurses)

AC_SUBST(RLIB)

AC_OUTPUT(Makefile)

Makropolecenie AC_CHECK_LIB sprawdza, czy można skonsolidować testowy program wywołujący funkcję rl_bind_key (jest to jedno z wywołań użyte w programie). Makropolecenie to używa następujących parametrów:

<biblioteka>, <funkcja>, <działanie-jeśli-znaleziona>, <działanie-jeśli-nie-znaleziona>, <inne-biblioteki>

Jeżeli kompilacja programu testowego z opcją -lreadline przebiega poprawnie, to makropolecenie ustawia zmienną powłoki RLIB. W opisywanym przypadku potrzebna jest także konsolidacja z biblioteką curses, na co wskazuje obecność członu <inne-biblioteki>. Puste nawiasy kwadratowe oznaczają, że nie jest podejmowane żadne działanie, jeżeli ta biblioteka nie zostanie znaleziona.

Przy wyszukiwaniu błędów w skrypcie configure warto oczyścić bufor konfiguracyjny. Jest to plik o nazwie config.cache, używany przez configure do przechowywania zmiennych między uruchomieniami kolejnych testów. Można usunąć go bez żadnych skutków ubocznych, wymuszając w ten sposób ponowne uruchomienie wszystkich testów przez skrypt configure. Takie postępowanie jest zalecane po zmianie pliku configure.in i ponownym uruchomieniu programu autoconf.

$ rm config.cache

$ autoconf

$ ./configure

creating cache ./config.cache

checking how to run the C preprocessor... cc -E

checking for ANSI C header files... yes

checking for readline/readline.h... yes

checking for rl_bind_key in -lreadline... yes

updating cache ./config.cache

creating ./config.status

creating Makefile

creating config.h

config.h is unchanged

Widzimy teraz, że plik makefile o nazwie Makefile został utworzony po wywołaniu AC_OUTPUT(Makefile) i zawiera odpowiednie definicje bibliotek:

# Generated automatically from Makefile.in by configure.

RLIB = -lreadline -lncurses

dvdstore: dvdstore.o

$(CC) -o dvdstore dvdstore.o dvd_pg.a $(RLIB)

Podobnie jak program autoconf, program automake także generuje standardowy plik Makefile.in na podstawie szablonu Makefile.am. Celem takiego podejścia jest stworzenie możliwości zastosowania standardowych makroinstrukcji i reguł w plikach makefile. Więcej informacji na temat szczegółów można znaleźć na stronach info programu automake.

Dzięki zastosowaniu programów autoconf i automake można utworzyć przenośny kod źródłowy, który może być dostarczany użytkownikom z nadzieją, że będą oni mogli posługiwać się aplikacją w wielu odmiennie skonfigurowanych systemach.

Pakiety źródłowe RPM

Jak już wspomniano wcześniej, źródłowy pakiet RPM jest szczególnym rodzajem pakietu zawierającym kod źródłowy aplikacji, poprawki wprowadzone przez twórcę pakietu podczas jego konfiguracji oraz specyfikację pozwalającą zbudować aplikację i utworzyć binarny pakiet RPM.

Podczas instalacji źródłowego pakietu RPM kod źródłowy (na ogół w postaci skompresowanego archiwum) jest umieszczany przeważnie w katalogu /usr/src/packages/SOURCES, zaś plik ze specyfikacją w /usr/src/packages/SPECS. Dokładna lokalizacja zależy od rodzaju dystrybucji i często spotyka się np. lokalizację /var/lib/rpm i podrzędne katalogi.

Jako przykład źródłowego pakietu RPM pokażemy aplikację XBoard przygotowaną dla dystrybucji SuSE 6.3. Pakiet ten ma nazwę xboard.spm.

Jeśli sprawdzimy zawartość pakietu za pomocą programu rpm, zobaczymy kod źródłowy, łatki i specyfikację:

$ rpm -q -l -p xboard.spm

xboard-4.0.0.dif

xboard-4.0.0.tar.gz

xboard.spec

$

Te pliki można rozpakować (np. do /usr/src/packages/SOURCES lub tam, gdzie wskazuje konfiguracja programu rpm), instalując po prostu pakiet:

$ rpm -i xboard.spm

Budowanie pakietu RPM

Pakiet RPM jest idealnym rozwiązaniem dla użytkowników chcących rozprowadzać swoją aplikację. Mając taki pakiet, można z łatwością zainstalować aplikację, odinstalować ją, korzystać z trybu zapytań i sprawdzać zależności. Opiszemy więc, w jaki sposób utworzyć własny pakiet RPM.

Najprostszą metodą utworzenia własnego pakietu RPM jest małe oszustwo. Twórca pakietu RPM ma do dyspozycji bardzo wiele opcji, ale większość z nich rzadko jest używana. Zgodnie z ideą otwartego oprogramowania można „pożyczyć” specyfikację i metody używane w innym pakiecie i zastosować je w swoim.

Ponieważ tworzenie pakietu RPM może być zadaniem bardzo skomplikowanym (można na ten temat napisać całą książkę), w tym rozdziale podamy tylko prosty przykład. Powinien on wystarczać do rozpowszechniana niewielkiej aplikacji w postaci źródłowej lub binarnej. Bardziej egzotyczne opcje i obsługę łatek w pakiecie pozostawiamy bardziej dociekliwym Czytelnikom. Pomocne mogą być tu strony podręcznika systemowego dla programu rpm oraz plik RPM HOWTO (znajdujący się przeważnie w katalogu /usr/doc).

Utworzymy pakiet RPM dla naszej aplikacji dvdstore obsługującej wypożyczalnię płyt DVD.

Motorem operacji tworzenia pakietu RPM jest plik spec, który nazwiemy dvdstore.spec. Plik specyfikacji składa się z wielu sekcji opisujących sposób budowy aplikacji, jej instalowanie oraz zależności z innymi plikami.

W pracy programu rpm podczas tworzenia pakietu można wyróżnić kilka etapów, które można w pewien sposób kontrolować. Wykorzystamy do tego poszczególne sekcje w pliku specyfikacji.

Ogólnie mówiąc, do przeprowadzania swoich operacji program rpm korzysta z drzewa katalogów /usr/src/packages (lub /var/lib/rpm). Skompresowane archiwa z kodem źródłowym będą przechowywane w katalogu SOURCES, pliki specyfikacji w SPECS, źródłowe pakiety RPM będą tworzone w SRPMS, zaś binarne pakiety RPM w katalogu RPM. Zbudowane aplikacje będą umieszczane w podkatalogach BUILD.

Dla danego pliku specyfikacji program rpm będzie szukał skompresowanych źródeł w katalogu SOURCES, rozpakuje je do podkatalogu w BUILD, przejdzie do tego podkatalogu, zbuduje aplikację, zainstaluje ją i utworzy pakiety RPM.

Pokażemy, w jaki sposób ten cały proces jest kontrolowany przez plik specyfikacji.

Pierwsza część tego pliku zawiera pozycje opisujące aplikację, czyli to, co ona zapewnia i czego wymaga do swojego działania:

#

# spec file for package dvdstore (Version 1.1)

#

Vendor: Wrox Press

Distribution: Any

Name: dvdstore

Release: 1

Packager: neil@tilde.co.uk

Copyright: 2000 by Wrox Press

Group: Applications/Media

Provides: dvdstore

Requires: postgres-6.5

Autoreqprov: on

Version: 1.1

Summary: DVD Rental Store Application

Source: dvdstore-1.1.tar.gz

Większość pozycji z powyższej listy jest zrozumiała sama przez się. Pakiety RPM mają nazwy w następującej postaci:

Nazwa-Wersja-Wydanie.architektura.rpm

Jako architektura występuje src dla źródłowych pakietów RPM, noarch dla pakietów binarnych, które nie są zależne od platformy lub i386 dla pakietów binarnych przygotowanych dla komputerów z procesorami firmy Intel. W systemach Linux działających na innych platformach sprzętowych używane są inne oznaczenia, np. sparc dla procesorów SPARC firmy Sun. Niektóre pakiety zawierają aplikacje skompilowane specjalnie dla jakiegoś rodzaju procesora i wówczas może się tu znaleźć wyróżniające się oznaczenie. Jako przykład można podać jądro skompilowane dla procesora Pentium firmy Intel, dla którego pakiety będą oznaczane jako i586.

Pozycja Group jest używana przez graficzne instalatory pakietów. Umożliwia ona grupowanie aplikacji o określonych właściwościach.

Pozycja Autoreqprov umożliwia programowi rpm dodawanie swoich własnych zależności, jeżeli jest to konieczne. Przykład zastosowania tej właściwości będzie pokazany dalej.

Następna (obowiązkowa) część specyfikacji zawiera opis aplikacji podawany w swobodnym formacie. Często podaje się tutaj dane o autorze.

%description

DVD Rental Store Application

An application to manage a DVD rental store, including membership, rental and return of titles and reservations.

This version requires PostgreSQL 6.5.

Authors: Neil Matthew and Richard Stones

Kolejna sekcja zawiera polecenia używane przez proces build programu rpm, mające za zadanie przygotowanie kodu źródłowego do kompilacji, kompilację i następnie instalację aplikacji:

%prep

%b

%build

make

%install

make install

Sekcja %prep służy do przygotowania kodu źródłowego do kompilacji. Może się tu także odbywać wprowadzanie poprawek (łatek). Istnieje makropolecenie (%setup), które rozpakowuje skompresowane archiwum z kodem źródłowym — ta informacja jest wystarczająca do zbudowania naszej przykładowej aplikacji.

Sekcja %build zawiera instrukcje dotyczące budowania aplikacji. W przypadku naszej przykładowej aplikacji wystarcza tu zwykłe polecenie make. Przy aplikacjach bardziej skomplikowanych można wywołać skrypt configure z odpowiednimi parametrami (jeżeli np. mamy zamiar budować binarny pakiet RPM ze specjalnym zestawem opcji).

Sekcja %install zawiera instrukcje dotyczące lokalnej instalacji.

Każda z sekcji %prep, %build oraz %install jest właściwie skryptem powłoki i dlatego może zawierać dowolne polecenie powłoki, łącznie z poleceniami warunkowymi.

Jeżeli zażyczymy sobie zbudowania pakietu RPM, to program rpm będzie uruchamiał kolejno poszczególne sekcje. Nazwy opcji kontrolujących budowanie pakietu zaczynają się od litery -b.

-bp

Uruchomienie sekcji %prep

-bc

Uruchomienie sekcji %build

-bi

Uruchomienie sekcji %install

-bs

Budowa pakietu źródłowego (po %prep, %build i %install)

-bb

Budowa pakietu binarnego (po %prep, %build i %install)

-ba

Budowa zarówno pakietu źródłowego, jak i pakietu binarnego

Do utworzenia binarnego pakietu RPM program rpm wymaga informacji o tym, które pliki będą instalowane w procesie instalacji. Pliki te trzeba wskazać w sekcji %files w pliku specyfikacji:

%files

/usr/local/lib/dvd_pg.a

/usr/local/include/dvd.h

/usr/local/man/man3/dvd3

Aby sprawdzić, czy podane na tej liście pliki istnieją, stosujemy w programie rpm opcję -bl (sprawdzenie listy):

$ rpm -bl dvdstore.spec

Processing files: dvdstore

File not found: /usr/local/man/man3/dvd3

Provides: dvdstore

Requires: postgres-6.5

$

Po upewnieniu się, że nasza aplikacja będzie zbudowana i zainstalowana z plików źródłowych, oraz sprawdzeniu poprawności listy plików można przystąpić do budowy pakietów RPM. Oczywiście, do instalacji wymagane są odpowiednie uprawnienia superużytkownika. Podane niżej komunikaty pojawiające się podczas tych operacji są skrócone z powodu braku miejsca:

$ rpm -ba dvdstore.spec

Executing: %prep

+ umask 022

+ cd /usr/src/packages/BUILD

+ cd /usr/src/packages/BUILD

+ rm -rf dvdstore-1.1

+ /bin/gzip -dc /usr/src/packages/SOURCES/dvdstore-1.1.tar.gz

+ tar -xvvf -

drwxr-xr-x neil/users 0 2000-04-25 10:54 dvdstore-1.1/

-rw-r--r-- neil/users 1093 2000-04-25 10:54 dvdstore-1.1/Makefile

-rw-r--r-- neil/users 5391 2000-04-08 20:23 dvdstore-1.1/pg_disk.pgc

-rw-r--r-- neil/users 6889 2000-04-08 20:23 dvdstore-1.1/p_title.pgc

...

+ STATUS=0

+ '[' 0 -ne 0 ']'

+ cd dvdstore-1.1

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

++ /usr/bin/id -u

+ '[' 500 = 0 ']'

+ /bin/chmod -Rf a+rX,g-w,o-w .

+ exit 0

Executing: %build

+ umask 022

+ cd /usr/src/packages/BUILD

+ cd dvdstore-1.1

+ make

gcc -Wall -g -I/usr/lib/pgsql/include -c dvd_gen.c -o dvd_gen.o

ecpg -t -I/usr/lib/pgsql/include pg_util.pgc

gcc -Wall -g -I/usr/lib/pgsql/include -c pg_util.c -o pg_util.o

ecpg -t -I/usr/lib/pgsql/include pg_functional.pgc

gcc -Wall -g -I/usr/lib/pgsql/include -c pg_functional.c -o pg_functional.o

ar -r dvd_pg.a dvd_gen.o pg_util.o pg_functional.o pg_member.o pg_lookup.o

pg_title.o pg_disk.o

+ exit 0

Executing: %install

+ umask 022

+ cd /usr/src/packages/BUILD

+ cd dvdstore-1.1

+ make install

cp dvd.h /usr/local/include

cp dvd_pg.a /usr/local/lib

+ exit 0

Processing files: dvdstore

Finding provides...

Finding requires...

Provides: dvdstore

Requires: postgres-6.5

Wrote: /usr/src/packages/SRPMS/dvdstore-1.1-1.src.rpm

Wrote: /usr/src/packages/RPMS/i386/dvdstore-1.1-1.i386.rpm

$

Tak utworzone źródłowe i binarne pakiety RPM można już rozsyłać do użytkowników.

Jeżeli w momencie instalowania lub usuwania aplikacji należy uruchomić jakiś skrypt, to można go dodać do pliku specyfikacji. Szczegółowe informacje na ten temat można znaleźć w pliku HOWTO. Jako przykład podamy tu prosty skrypt wysyłający wiadomość do superużytkownika po instalacji pakietu. Skrypt ten powinien być umieszczony w sekcji %post (od słów post-install) pliku specyfikacji:

%post

mail root -s "DVD installed - please register" </dev/null

Teraz przy budowaniu pakietu RPM można zauważyć, że program rpm dodaje swoje własne zależności, czyli /bin/sh, ponieważ są one wymagane do uruchomienia skryptu „poinstalacyjnego”, który został ostatnio dodany:

$ rpm -bb dvdstore.spec

...

Finding requires...

Provides: dvdstore

Prereqs: /bin/sh

Requires: postgres-6.5

Wrote: /usr/src/packages/RPMS/i386/dvdstore-1.1-1.i386.rpm

$

Zbudowany pakiet RPM można sprawdzić w trybie zapytań, aby się upewnić, czy po instalacji zostanie uruchomiony dodany skrypt:

$ rpm -q --scripts -p /usr/src/packages/RPMS/i386/dvdstore-1.1-1.i386.rpm

postinstall script (through /bin/sh):

mail root -s "DVD installed - please register" </dev/null

$

W podobny sposób można dodawać inne skrypty, które mają być uruchamiane w wybranych momentach czasu.

Łatki

Decydując się na rozpowszechnianie kodu źródłowego w postaci spakowanego archiwum (lub źródłowego pakietu RPM), można także rozpowszechniać niewielkie poprawki do tego kodu (zwane łatkami). Łatka (ang. patch) jest po prostu różnicą dwóch wersji pliku lub zestawu plików. Jeżeli kod był tworzony np. pod kontrolą CVS, to można mieć pewność, że każde wydanie było oznaczone. Dzięki temu można dokładnie wiedzieć, które wersje kodu źródłowego (i innych plików) wchodzą do każdego wydania aplikacji.

Aby nie zmuszać użytkowników do pobierania kompletnego zestawu kodów źródłowych przy każdym wydaniu nowej wersji, można publikować łatki, dzięki którym będzie można aktualizować posiadane kopie plików.

Program patch (opracowany przez Larry'ego Walla i stanowiący obecnie część standardu POSIX) umożliwia automatyczne dodawanie łatek do kodu źródłowego. Mechanizm ten jest szeroko wykorzystywany w kodzie źródłowym jądra Linuksa, ponieważ cały kod ma rozmiar większy niż dziesięć megabajtów. Typowe poprawki związane ze zmianą podrzędnego numeru wersji jądra liczą zaledwie kilkadziesiąt kilobajtów nowego kodu. Łatki stanowią bardzo efektywny sposób rozpowszechniania poprawek i aktualizacji plików wśród programistów.

Tworzenie łatki

Łatka najczęściej powstaje w wyniku działania programu diff wywołanego z kilkoma specjalnymi opcjami wspomagającymi wykrywanie błędów.

Przede wszystkim należy utworzyć podkatalogi zawierające ostatnio wydaną wersję (starą wersję) i najnowszy kod (nową wersję). Następnie należy uruchomić program diff porównujący zawartości tych katalogów i tworzący listę wykrytych różnic.

Należy zwrócić szczególną uwagę na to, aby punkt wyjściowy (czyli stara wersja) był taki sam, jak wersja posiadana przez użytkowników, którzy będą stosowali łatkę. Natychmiast po operacji tworzenia różnic należy zachować nową wersję jako kolejne wydanie, aby stała się ona odniesieniem dla przyszłych łatek.

Strona podręcznika systemowego programu patch zawiera zalecaną procedurę postępowania, dzięki której z największym prawdopodobieństwem można uzyskać pomyślny wynik. Program diff przy tworzeniu łatki należy wywoływać z następującymi opcjami:

$ LC_ALL=C TZ=GMT0 diff -Naur old new

Zmienna środowiskowa LC_ALL ustawia środowisko językowe dla programu diff. Wartość tej zmiennej w powyższym przykładzie zabrania stosowania lokalnych tłumaczeń formatów daty, czasu, komunikatów itd., ponieważ nie muszą one występować w komputerze użytkownika.

Zmienna TZ uzyskuje wartość GMT0, co oznacza, że czasy i daty używane w danych wyjściowych programu diff są odniesione do czasu UTC (co ułatwia w razie konieczności kontrolę łatek).

W wywołaniu programu diff dozwolone jest użycie następujących opcji:

-N

Traktowanie plików znalezionych tylko w jednym z katalogów jako istniejące, zaś w innym — jako puste. Spowoduje to, że powstanie łatka tworząca nowe pliki, jak jest to wymagane, ponieważ różnicą będzie po prostu cała zawartość istniejącego pliku.

-a

Traktowanie wszystkich plików jako tekstowych i porównywanie ich wiersz po wierszu.

-u

Generacja danych wyjściowym w zunifikowanym formacie zawierającym pewne informacje na temat kontekstu różnic, co pomaga programowi patch znaleźć odpowiednie miejsce do zastosowania poprawek.

Ta opcja może nie być dostępna we wszystkich wersjach programu diff w systemach nielinuksowych. Jeśli opcja nie występuje w danej wersji, to należy spróbować opcji -c dla utworzenia różnic kontekstowych programu diff lub zainstalować GNU diff!

-r

Podczas porównywania katalogów stosowane jest rekurencyjne przeszukiwanie podkatalogów.

Sprawdźmy to wszystko w działaniu, tworząc łatkę dla wersji 1.0 naszej aplikacji dla wypożyczalni płyt DVD, zmieniającą ją w wersję 1.1. Najpierw utworzymy katalogi zawierające tylko źródłowe pliki każdej wersji.

Często przydaje się użycie polecenia distclean w pliku „makefile” w celu usunięcia wszystkich przejściowych plików powstałych w procesie budowania aplikacji. Takie polecenie usuwa pliki obiektowe, biblioteki, kopie zapasowe plików utworzone przez edytor oraz pliki binarne aplikacji. Pozostawiane są jedynie pliki tekstowe i kod źródłowy, które są gotowe do dystrybucji lub wykonania łatki.

$ ls -F

dvd_app_1.0/ dvd_app_1.1

Utwórzmy teraz łatkę opisującą różnice dwóch wersji aplikacji. Pokazany niżej wynik działania programu diff został skrócony z powodu braku miejsca:

$ LC_ALL=C TZ=GMT0 diff -Naur dvd_app_1.0 dvd_app_1.1

diff -Naur dvd_app_1.0/makefile dvd_app_1.1/Makefile

--- dvd_app_1.0/Makefile Sat Apr 8 14:09:21 2000

+++ dvd_app_1.1/Makefile Tue Apr 25 07:42:49 2000

@@ -39,3 +44,7 @@

rm -f *~

rm -f core

+distclean:

+ rm -f *.o *~ core test_pg dvd_pg.a dvd_app final_file

+ rm -f pg_member.c pg_util.c pg_functional.c

+ rm -f pg_lookup.c pg_title.c pg_disk.c

diff -Naur dvd_app_1.0/pg_lookup.pgc dvd_app_1.1/pg_lookup.pgc

--- dvd_app_1.0/pg_lookup.pgc Sat Apr 8 19:23:56 2000

+++ dvd_app_1.1/pg_lookup.pgc Tue Apr 25 07:43:14 2000

@@ -135,7 +135,7 @@

sprintf(db_text, "Unknown Error: %d", err_number);

pg_print_debug(__FILE__, __LINE__, sqlca, "Bad err code");

}

- strcpy(*message_to_show, db_text);

+ *message_to_show = db_text;

exec sql COMMIT WORK;

} /* pg_get_err_text */

...

$

Widzimy, że został zmieniony plik Makefile (dodano polecenie distclean) oraz poprawiono błąd w pliku pg_lookup.pgc w pobliżu wiersza 135.

Aby opublikować tę łatkę, trzeba przechwycić wynik działania programu diff, poddać go kompresji i udostępnić użytkownikom:

$ LC_ALL=C TZ=GMT0 diff -Naur dvd_app_1.0 dvd_app_1.1 | gzip > patch-1.0-1.1.gz

Skompresowany plik zawierający łatkę ma rozmiar ok. 1000 bajtów, a więc niewiele w porównaniu z pełnym kodem o długości ponad 100 kilobajtów.

Użycie łatki

Gdy użytkownik otrzyma naszą łatkę, będzie mógł dokonać aktualizacji swojej kopii kodu źródłowego. Służy do tego polecenie patch, ale należy przy tym pamiętać o kilku sprawach.

Każda różnica w utworzonej łatce odnosi się do plików umieszczonych w podkatalogach dvd_app_1.0 oraz dvd_app_1.1. Użytkownik może przetrzymywać pliki źródłowe w innych katalogach niż katalogi stosowane podczas tworzenia łatki.

Program patch umożliwia zignorowanie jednego lub więcej członów nazwy pliku podczas aplikowania łatki. Najczęściej właściwość ta jest wykorzystywana w przypadku problemów z nazwą katalogu najwyższego poziomu. Należy poinstruować użytkownika, aby przeszedł do katalogu z kodem źródłowym aplikacji i użył polecenia:

$ patch -Np1

Jako dane wejściowe musi być wówczas użyty nieskompresowany plik z łatką. Można to wszystko uzyskać w następujący sposób:

$ ls -F

dvd_app/ patch-1.0-1.1.gz

$ cd dvd_app

$ gzip -dc ../patch-1.--1.1.gz | patch -Np1

patching file Makefile

patching file dvd_gen.c

patching file pg_lookup.pgc

patching file pg_util.pgc

$

Opcje programu patch są następujące:

-p<numer>

Odcięcie pierwszego członu nazwy pliku zarejestrowanego w łatce. W naszym przykładzie zamiast dvd_app_1.0/Makefile pojawiłoby się więc Makefile, co da prawidłowy wynik, jeśli polecenie patch jest uruchamiane w katalogu najwyższego poziomu.

-N

Wskazanie, że łatka jest normalna (a nie odwrotna). Program patch umożliwia wycofanie wprowadzonych łatek (czyli użycie tzw. łatek odwrotnych), jeśli wykryje, że dana łatka była już użyta. Opcja -N blokuje takie działanie, dzięki czemu przypadkowe powtórne użycie łatki nie spowoduje cofnięcia wprowadzonych poprawek.

GNATS

Po wydaniu aplikacji trafi ona do rąk wielu różnych użytkowników, zyska wiele zastosowań i spowoduje wiele problemów. Niektórzy użytkownicy będą sygnalizowali problemy autorom, prosząc o pomoc w ich pokonaniu. Jeżeli aplikacja stanie się popularna, to autorzy mogą otrzymywać bardzo wiele żądań poprawek, aktualizacji i wprowadzenia nowych właściwości.

Aplikacja GNATS jest bazą danych śledzącą błędy i warto się jej bliżej przyjrzeć. Pakiet instalacyjny tej bazy i wiele informacji na jej temat można znaleźć na stronie firmy Cygnus pod adresem http://www.cygnus.com/projects.html.

System GNATS korzysta z bazy danych do rejestracji stanu śledzonych błędów. Proces serwera oczekuje na nadchodzące raporty o błędach, które mogą docierać kilkoma drogami. System przyjmuje raporty nasyłane jako:

Razem z nadzorowaną aplikacją rozsyłany jest prosty program o nazwie send-pr przeznaczony dla systemu UNIX. Konfiguruje on wysyłanie raportów do systemu GNATS. Jeżeli problemy mają być zgłaszane za pomocą poczty elektronicznej, to należy także skonfigurować proces, który będzie te wiadomości odbierał i przetwarzał. Sygnalizacja błędów może być przypisana do programistów, mogą być także generowane raporty o awariach.

Opracowano także interfejs WWW dla systemu GNATS (o nazwie WebGNATS). Jest on rozpowszechniany razem z kodem źródłowym GNATS.

Podsumowanie

W tym rozdziale przedstawiono dość szeroko program RPM służący do zarządzania pakietami. Pokazano sposób użycia tego programu do kontroli pakietów oprogramowania w systemie Linux na przykładzie instalacji, usuwania i trybu zapytań. Pokazano także sposób tworzenia własnych pakietów RPM zawierających wersję źródłową i binarną aplikacji.

Omówiono także zastosowanie łatek zamiast dystrybucji kompletnego kodu źródłowego.

Podano skrótową informację o systemie GNATS służącym do śledzenia błędów i wspomagającym kontrolę problemów pojawiających się w aplikacji.

2 Część I Podstawy obsługi systemu WhizBang (Nagłówek strony)

2 D:\1-dokumenty\Word\Zaawansowane programowanie w systemie Linux\R-27-05.doc



Wyszukiwarka

Podobne podstrony:
6301
6301
6301
6301
6301
6301
6301
katalog 6301
6301
6301
6301

więcej podobnych podstron