Tworzymy paczkę
Budowanie pakietów (nie tylko) dla początkujących
Tekst ukazał się w numerze specjalnym Linux+ wraz z dystrybucją
Debian GNU/Linux (Woody). W roku 2006 w dalszym ciągu jest
w miarę aktualny.
Kiedy ponad rok temu przygotowywałem swój pierwszy w życiu pakiet dla
Debiana, rzucił mi się w oczy brak polskiego tekstu opisującego cały
proces budowy paczki debianowej. Konkretnie - brak tekstu dla
początkujących, gdyż w poświęconym Debianowi Potato numerze Linux+
pojawił się artykuł przeznaczony raczej dla zaawansowanych użytkowników
dpkg. Mam nadzieję, że ten tekst pomoże zapełnić tę lukę w literaturze.
W katalogu /usr/share/docs/ można znaleźć kilka dokumentów, które przydadzą się przy tworzeniu oficjalnych pakietów i z częścią nich powinni się zapoznać wszyscy przyszli developerzy Debiana. Jeśli chcecie stworzyć pakiet dla własnego użytku, poniższy artykuł powinien wam wystarczyć, jednak mimo wszystko dobrze jest zapoznać się z następującymi dokumentami (w nawiasie podaję pakiet, w którym znajduje się każdy tekst):
Debian New Maintainer's Guide (maint-guide) - chyba najlepszy
istniejący podręcznik tworzenia pakietów dla Debiana. Napisany z myślą o
początkującym developerze, prowadzi go praktycznie krok po kroku od momentu
przygotowywania źródeł do spakowania, aż do uploadu gotowego pakietu na
serwer oraz jego późniejszych aktualizacji.
Debian Policy Manual (debian-policy) jak również wszystkie dokumenty
z pakietu debian-policy są opisem standardów stosowanych przez
wszystkich twórców Debiana i każdy pakiet, który ma trafić do dystrybucji,
powinien być zgodny z opisanymi w tych dokumentach założeniami.
Debian Packaging Manual (packaging-manual) - opis technicznej
części budowy pakietów, w którym można znaleźć specyfikację plików
kontrolnych, a także instrukcja obsługi niektórych narzędzi niezbędnych
przy pracy nad tworzeniem plików .deb.
Debian Developer's Reference (developers-reference) - dokument
przeznaczony głównie dla developerów i kandydatów na developerów, w którym
można znaleźć informacje na temat sposobu uploadowania gotowych pakietów
do dystrybucji, informacje na temat obsługi błędów, sposób zarządzania
kluczem gpg itp.
Jak głosi rzymskie przysłowie (przytoczone zresztą przez Josepha Rodina we wstępie do Debian New Maintainer's Guide), najprościej uczyć na przykładach. W tym celu stworzyłem prosty pakiet składający się z jednego pliku wykonywalnego, hello, makefile-a oraz krótkiej dokumentacji -- strony manuala, pliku README oraz changelog. Oznacza to, że w jego skład wchodzą wszystkie podstawowe elementy spotykane w zaawansowanych programach.
Do tworzenia pakietu Debiana wykorzystamy narzędzia debhelper oraz dh_make, które zostały stworzone z myślą o ułatwieniu całego procesu. Są one wykorzystywane również przez twórców Debiana, tak więc nie ma obawy, że pakiet wykonany przy ich pomocy mógłby mieć problemy ze znalezieniem się w oficjalnej wersji Debiana.
Pierwszym narzędziem, po które sięgniemy, jest dh_make - narzędzie, które
rozpakuje nam kod źródłowy opracowywanego przez nas oprogramowania, a także
założy strukturę plików wymaganą podczas budowania pakietu. Załóżmy, że
oprogramowanie skopiowane przez nas ze stron producenta jest spakowane do
pliku hello_0.02.tar.gz. Zakładamy sobie katalog ~/debian,
w którym będziemy trzymać nasze pakiety, a w nim podkatalog
hello-0.02. Jego nazwa powinna składać się z samych małych liter,
a numer wersji musi być oddzielony znakiem minus. Jeśli autor oryginalnego
oprogramowania nie numeruje wersji w sposób XX.YY.ZZ, lecz na
przykład wstawia tam datę, musimy przekształcić proponowaną przez niego
nazwę w coś o kształcie nazwa-0.0.20011218. Do tak utworzonego
podkatalogu rozpakowujemy plik ze żródłami.
Do katalogu debian/ kopiujemy plik z kodem źródłowym, wchodzimy
do uprzednio założonego podkatalogu i wykonujemy komendę dh_make -e
moj_adres@mojekonto.pl -f ../hello_0.02.tar.gz. Zostaniemy zapytani o
to, czy pakiet będzie biblioteką, programem z jedną lub wieloma binarkami.
Najczęstszą odpowiedzią będzie tu s, nawet jeśli nasze
oprogramowanie udostępnia więcej niż jeden plik wykonywalny - możliwość
m (multiple binary) przydaje się przy tworzeniu dużych
pakietów, które będą się później składać z wielu plików .deb.
Po potwierdzeniu naszego wyboru, w katalogu debian/hello-0.02
zostanie utworzony podkatalog debian, w którym znajdują się
wszystkie pliki wykorzystywane przy budowie pakietu .deb. Jak się
za chwilę okaże, część z nich można usunąć bez obaw o konsekwencje -
dh_make tworzy ich tyle, ile możemy potrzebować, rzadko jednak zdarza
wszystkie wykorzystamy.
Pierwszą rzeczą, na którą musimy zwrócić uwagę, jest lokalizacja plików
powstałych po kompilacji oprogramowania. Zwykle - choć nie zawsze - są
one skonfigurowane tak, by pliki należące do programu lądowały w
podkatalogach /usr/local/.
Pakiety Debiana powinny kopiować pliki binarne do /usr/bin/,
manuale do /usr/share/man/, a dokumentację - do
/usr/share/doc/.
Dlatego też musimy poprawić plik Makefile naszego przykładowego
pakietu w taki sposób, żeby był dopasowany do wymagań stawianych przez
Debian Policy. W tym celu modyfikujemy wszystkie ścieżki w sekcji
install. Trzeba pamiętać, że w przypadku programów wykorzystujących
programy typu automake czy autoconf, edycja wynikowego
Makefile na wiele nam się nie przyda, gdyż będzie on za każdym razem
generowany na nowo. Dlatego do przygotowywania pakietów z takim
oprogramowaniem przydaje się znajomość struktury plików
Makefile.am i Makefile.in.
W chwili, kiedy rozpoczynamy generowanie pakietu, na dysku zakładany jest
katalog tymczasowy, w którym odwzorowana jest struktura plików tworzonych
podczas kompilacji. Dlatego w wykorzystywanym później do budowy pakietu
pliku Makefile przed każdą ścieżką powinniśmy dodać zmienną ustawianą przez
builder. Zmienna o nazwie DESTDIR wymagana jest tylko przy programach nie
korzystających z autoconfa, gdyż w ich przypadku odpowiednie modyfikacje
zostaną automatycznie wprowadzone przez dh_make.
Tak więc na początku naszego przykładowego Makefile-u pojawi się teraz nowa
linijka: DESTDIR =, a przed każdą ścieżką docelową -
$(DESTDIR). Ostateczny wygląd pliku Makefile przedstawiony jest
na rysunku 2.
Bardzo ważne jest pamiętanie, że zmiana katalogu z danymi, z których
obrabiany przez nas program korzysta dopiero podczas uruchomienia, wymaga
nie tylko zmian w Makefile-u, lecz również ingerencji w sam kod źródłowy,
ewentualnie pliki konfiguracyjne. Nie jest do tego wprawdzie potrzebna
doskonała znajomość języka, w którym stworzono dane oprogramowanie, jednak
jeśli nie jesteśmy pewni, czy sobie dobrze poradziliśmy z modyfikacją
źródeł warto poświęcić więcej niż zwykle czasu na testowanie finalnego
pakietu.
Przyszedł czas na rzecz najważniejszą - edycję plików umieszczonych przez
dh_make w podkatalogu debian/. Pierwszym z nich jest
control, w którym umieszczane są informacje o autorze pakietu,
jego nazwie, architekturach, na których działa, a także jego krótki opis.
Pierwotnie plik ten wygląda w następujący sposób:
Source: hello Section: unknown Priority: optional Maintainer: Debian User <honey@debian.org> Standards-Version: 3.0.1 Package: hello Architecture: any Depends: ${shlibs:Depends} Description: <insert up to 60 chars description> <insert long description, indented with spaces>
Opcja Priority określa, jak ważny jest nasz program dla całości
dystrybucji - w związku z tym, że nie straci ona na stabilności i
użyteczności bez niego, zostawiamy tam wpis optional.
Pod Priority powinniśmy wpisać oprogramowanie, które nie znajduje
się w standardowym Debianie, a które jest wymagane do kompilacji naszego
pakietu. Podczas jego budowy wykorzystamy możliwości dawane przez pakiet
debhelper, dlatego dodajmy tam linijkę o treści Build-Depends:
debhelper.
Kolejne pola są miejscem na wpisanie naszych danych, wersji Debian-Policy z którą nasz pakiet jest zgodny, nazwy pakietu binarnego oraz architekturę (zwykle any). Ostatnie trzy pola posłużą nam na ustawienie zależności (wpis ${shlibs:Depends} zwykle wystarczy), krótkiego opisu wyświetlanego np podczas listowania pakietów komendą dpkg -l oraz dłuższego opisu, który pojawi się na przykład podczas przeglądania dostępnych pakietów programem dselect.
Oczywiście nie są to wszystkie możliwe opcje, które mogą się znaleźć w tym pliku, jednak te wystarczają do stworzenia większości pakietów. Wygląd pliku control po wprowadzeniu odpowiednich modyfikacji znajdziecie na rysunku 3.
Innym dość ważnym dla dystrybucji i samego pakietu jest copyright, który zwykle zastępuje plik z licencją dołączaną do oprogramowania. Umieszcza się w nim dane dotyczące autora pakietu, autora oryginalnego oprogramowania, a także adres pakietu źródłowego oraz krótką informację o licencji - ewentualnie, jeśli jest to licencja niestandardowa (nieznajdująca się w /usr/share/common-licenses/) - jej pełną treść. Dzięki temu unika się istnienia na dysku kilku tysięcy jednakowych kopii pliku z treścią GNU GPL, a pojawia się standardowe miejsce, w którym można znaleźć informacje o sposobie licencjonowania danego pakietu.
Kiedy tworzymy pakiet, często nieuniknione są poprawki w jego źródła - czy
to zmiany w Makefile, czy też poprawione drobne błędy, które w nim się
pojawiły. Do tego, a także do informowania o różnicy pomiędzy kolejnymi
wersjami pakietów, służy plik changelog. Umieszczany później pod nazwą
changelog.Debian, jest nierzadko podstawowym źródłem informacji przy
podejmowaniu decyzji o ewentualnej aktualizacji. Jeśli tworzymy nową
wersję pakietu tylko dlatego, że pojawiła się nowa wersja oprogramowania,
umieszczamy tu linijkę w stylu New upstream release, jeśli jest to
jego pierwsza wersja - pierwszym wpisem powinno być Initial
Release..
Informacje zawarte w tym pliku - a konkretnie numer wersji pakietu
umieszczony w nawiasach przy jego nazwie - służy do ustalenia ostatecznej
nazwy pakietu .deb. Ostateczna zawartość debian/changelog nie jest
tu prezentowana, jednak zmodyfikowany plik znajdziecie wraz z resztą
pakietu na stronie, której adres podano na rysunku 1.
Jeśli nasz pakiet - co nie zachodzi w tym przypadku - posiada jakiekolwiek pliki konfiguracyjne, powinniśmy je wpisać wraz z pełną ścieżką do debian/conffiles. Dzięki temu podczas aktualizacji pakietu zostaniemy zapytani, czy chcemy zastąpić poprzednią konfigurację - nową, a przy usuwaniu pakietu komendą dpkg --remove ustawiona przez nas konfiguracja nie zostanie stracona.
Jak już uprzednio wspomniałem, podczas budowy pakietu na dysku tworzony
jest katalog tymczasowy mający odwzorować późniejszą strukturę plików w
pakiecie. Do automatycznego stworzenia wszystkich katalogów, które nie są
budowane przez Makefile, wykorzystywana jest zawartość pliku
debian/dirs. Standardowo znajdziecie w nim wpis zakładający
usr/bin i usr/sbin, który powinien wystarczyć w
większości mało zaawansowanych programów.
W związku z tym, że z pliku Makefile nie usunęliśmy komend kopiujących
strony manuala oraz dokumentację (choć pakiet debhelper daje możliwość
automatyzacji tych procesów), musimy tu dodać wpisy zakładające
usr/share/doc oraz usr/share/man/man1
Jeśli chcemy, żeby nasz pakiet po instalacji pojawił się w menu po uruchomeniu X Window System, musimy zmienić nazwę debian/menu.ex na debian/menu, a także odpowiednio go zmodyfikować. W tym celu warto zapoznać się z dokumentacją do pakietu menu, a także stanowiącym część pakietu debian-policy dokumentem Debian Menu sub-policy.
Najważniejszym plikiem, który zarządza budową pakietu, jest
debian/rules, który jest niczym innym jak skryptem wykonywanym
przez program make. Znajdziecie w nim wywołanie wszystkich poleceń
używanych do stworzenia pakietu. Postaram się tu pokrótce opisać te
najważniejsze, pełną instrukcję ich obsługi możecie znaleźć wśród stron
manuala.
Sekcja build odpowiada za kompilację pakietu - tu znajduje się
wywołanie make, tu też możecie dopisać informację o komendach, które
powinny być wydane w celu skompilowania pakietu
Poniżej znajduje się clean, który jest wywoływany zawsze przed
budową pakietu. Sekcja ta odpowiada za usunięcie wszystkich plików
mogących być pozostałością po poprzednich konfiguracjach, podobnie jak
install, zwykle nie wymaga większych modyfikacji.
Kolejna sekcja - install - jest dokładnym zapisem kolejnych etapów
kompilacji - tu znajdują się wywołania programów odpowiedzialnych za
założenie katalogu debian/tmp/ (a w nim całego drzewa katalogów
używanych przez tworzony właśnie pakiet), wyczyszczenie kodu źródłowego
z niepotrzebnych plików i wreszcie samego make z odpowiednimi
parametrami.
Wreszcie - binary-arch, czyli oprogramowanie odpowiedzialne za
poskładanie zainstalowanego chwilę wcześniej do katalogu
debian/tmp/ programu w jeden pakiet. Każde z nich posiada własną
stronę manuala, ja opiszę tylko najważniejsze:
dh_testroot - sprawdza, czy procedura tworzenia pakietu została
uruchomiona z konta root. Pakiety Debiana muszą być tworzone przez
użytkownika z uprawnieniami administratora... lub przez osobę korzystającą
z programu rfakeroot, który potrafi oszukać dużą część programów
sprawdzających prawa uruchamiającego.
dh_installdocs - kopiuje dokumentację programu - w tym pliki
debian/changelog oraz - ewentualnie -
debian/README.Debian i debian/TODO.Debian do katalogu
/usr/share/doc/nazwapakietu/. Jeśli utworzyliśmy plik
debian/docs, w którym znajduje się lista innych plików należących
do dokumentacji, również zostaną one skopiowane.
dh_installmanpages odpowiada za skopiowanie wszystkich stron
manuala, które znajdą się w katalogu źródłowym, do odpowiednich katalogów w
/usr/share/man/. Może być zastąpiony odpowiednim wpisem do
pliku Makefile.
dh_md5sums generuje sumy kontrolne wszystkich plików wchodzących
w skład pakietu.
dh_gencontrol tworzy katalog DEBIAN, w którym umieszcza
opis pakietu i sumę kontrolną wszystkich plików w nim zawartych.
Te informacje można obejrzeć wchodząc do dowolnego
pakietu .deb przy pomocy Midnight Commandera.
dh_builddeb buduje pakiet.
Wśród innych programów, które mogą tu być wywołane, są odpowiadające za aktualizację crona (dh_installcron), menu X Window System (dh_installmenu) czy tworzenie linków symbolicznych (dh_link). Warto się zapoznać z opisem wszystkich programów wchodzących w skład pakietu debhelper, gdyż często mogą one znacznie ułatwić pracę przy tworzeniu pakietu.
Kiedy już będziemy gotowi do zbudowania naszego pakietu, cofnijmy się o jeden katalog do góry (czyli po prostu do głównego katalogu ze źródłami) i wydajmy komendę dpkg-buildpackage -rfakeroot. Jesli chcemy, żeby część plików była podpisana naszym kluczem gpg, dodajmy do tego jeszcze opcję -sgpg. Po chwili - jeśli nie zrobiliśmy żadnych błędów - w katalogu nadrzędnym do aktualnego pojawi się plik o nazwie hello_0.02-1_i386.deb. Możemy go już zainstalować w systemie, jednak lepszym pomysłem jest jego uprzednie sprawdzenie na zgodność ze standardami Debiana. Służy do tego pakiet Lintian.
Lintiana wywołujemy podając jako parametr plik .deb, co zaowocuje wygenerowaniem raportu tylko dla gotowego pakietu, albo .changes - wówczas Lintian sprawdzi wszystkie pliki, które są w nim wymienione. Przy budowaniu pierwszych pakietów, kiedy jeszcze nie jesteśmy nie mamy wprawy ich przygotowywaniu, pomocna może się okazać opcja -i, która spowoduje, że Lintian poza wyświetleniem suchej informacji o niezgodności z Policy spróbuje naprowadzić nas na rozwiązanie problemu.
Kiedy nasz pakiet jest na takim etapie, że Lintian nie wyświetla w odpowiedzi żadnego komunikatu, prawdopodobnie jest on zbudowany z zachowaniem wszelkich reguł sztuki. Oznacza to też, że pora na jego dokładne przetestowanie. W tym celu spróbujmy kilkukrotnie zainstalować i odinstalować nasz pakiet, jeśli jest to już jego kolejna wersja - próby upgrade'u również nie zaszkodzą. Dopiero kiedy mamy pewność, że nie ma w nim żadnego błędu, możemy go wysłać na serwer Debiana, ewentualnie - jeśli nie jest on przygotowywany do oficjalnej wersji tej dystrybucji - rozpocząć jego rozpowszechnianie. Niestety, jak się okazuje nie wszyscy przestrzegają tej prostej, wydawałoby się, reguły, a przekonali się o tym wszyscy użytkownicy wersji unstable, którzy przez błąd w jednym z pakietów nie mieli możliwości zalogowania się na własne komputery. No, ale to już są uroki korzystania z niestabilnych wersji Debiana ;)
Po pewnym czasie, który możemy przeznaczyć albo na pracę nad nowymi pakietami, albo na robieniu tego, co robić lubimy najbardziej, znienacka dopadnie nas informacja o pojawieniu się nowej wersji oprogramowania, którym się opiekujemy. Nie oznacza to oczywiście, że pora na panikę - nie, nie czeka nas już tyle pracy, co nad stworzeniem pakietu od podstaw. Życie ułatwi nam należący do pakietu devscripts program uupdate. Chociaż do dobrych nawyków należy czytanie dokumentacji, to jednak w jego wypadku możecie tego nie robić - cała jego obsługa sprowadza się do wydania jednego polecenia.
Nim to jednak nastąpi, musimy skopiować nowy plik ze źródłami (na przykład hello_0.03.tar.gz) do katalogu ~/debian/. Następnie wchodzimy do katalogu, w którym stworzyliśmy poprzednią wersję pakietu (czyli wydajemy komendę cd ~debian/hello-0.02/ i wpisujemy polecenie uupdate -u hello_0.03.tar.gz. Trzeba pamiętać, żeby nazwa pliku podana jako parametr była identyczna, jak nazwa pliku z nowymi źródłami, który jest umieszczony katalog wyżej. Po chwili na dysku pojawi się ~debian/hello-0.03/, a w nim wszystkie pliki potrzebne do budowy pakietu. Spróbujmy go teraz zbudować poleceniem dpkg-buildpackage -rfakeroot -sgpg, a pliki wynikowe sprawdzić podobnie jak sprawdzaliśmy poprzednią wersję pakietu - przy pewnej dozie szczęścia aktualizacja ograniczy się do konieczności wydania tylko tych kilku poleceń i skopiowaniu nowej wersji pakietu na serwer.
Ramki towarzyszące artykułowi:
rys. 1
Potrzebne narzędzia
pakiet debhelper
pakiet dh-make
pakiet lintian
pakiet fakeroot
pakiet devscripts
rys. 2
DESTDIR= CC=gcc CFLAGS= all: hello hello.c install: cp hello $(DESTDIR)/usr/bin/ cp hello.1 $(DESTDIR)/usr/share/man/man1/ mkdir $(DESTDIR)/usr/share/doc/hello cp docs/* $(DESTDIR)/usr/share/doc/hello/ clean: rm hello
Source: hello Section: misc Priority: optional Maintainer: Lukasz Jachowicz <honey@debian.org> Build-Depends: debhelper Standards-Version: 3.5.6.0 Package: hello Architecture: any Depends: ${shlibs:Depends} Description: Pakiet z nieprawidlowym - bo polskim - opisem Krociutki pakiet stworzony przez honeja po to, zeby pokazac czytelnikom miesiecznika Linux+ sposob tworzenia plikow .deb. A warto je robic, bo sa fajne i juz.