ChangeBlog  •  Archiwum  •  Kategorie  •  Artykuły  •  Galeria  •  Czytelnicy  •  Rupieciarnia
RSS wpisów  |  RSS komentarzy
Multipackage

A teraz pora na zapoznanie się z bardzo przyjemną funkcją rpm-a, jaką jest tzw. budowanie multipackage. Polega ono na tym, że jeden pakiet źródłowy rpm (albo ogólniej jeden plik .spec) produkuje więcej niż jeden pakiet wynikowy. Tradycyjnie chodzi o to, by pliki powstałe w kompilacji jakiegoś programu rozbić na kilka pakietów, tak by użytkownik mógł nie instalować całości programu. O ile jest to oczywiście możliwe. Wtedy jeden program ma, z punktu widzenia systemu pakietów, budowę modularną i to końcowy użytkownik/administrator decyduje, które części są mu potrzebne. Albo mamy program złożony z paru komponentów, które można jednak wymieniać/aktualizować korzystając z innych źródeł - np. XFree86 instaluje libfreetype. Jeśli ją wydzielić do osobnego pakietu, to będzie potem ją można aktualizować bez ingerowania w pozostałe części XFree86. Brzmi to może bardzo skomplikowanie, ale jest w praktyce duużo prostsze od multisource.

Budowa specfile przeznaczonego do budowy "mnogopaków©" ;) nie różni się specjalnie od budowy zwykłego speca. Różnica polega na tym, że niektóre sekcje są replikowane dla każdego pakietu wynikowego, a więc np. jest kilka sekcji %files. Nic wielkiego. Czas na przykład, ale nie wiem co wybrać. O, mam: coreutils. Coreutils to połączenie sh-utils, textutils i fileutils w jedną dystrybucję. Wygodne, bo faktycznie te programy tworzą rdzeń każdego systemu więc nie ma sensu rozprowadzanie ich w osobnych paczkach. W każdym bądź razie coreutils to produkt GNU. Jako produkt GNU ma obszerną dokumentację w formacie Info oraz bardzo słabą dokumentację w postaci stron manuala. Stąd wniosek, że dokumentacja w formie stron manuala nie jest być może w ogóle przydatna, skoro równolegle jest dostępna dużo lepsza dokumentacja Info (naprawdę, strony manuala produkowane przy projektach GNU to zwykle coś w stylu "ls --help" - takie ostentacyjne olewanie manuali). Ale ja sam ciągle nie wiem, czy nie jestem tak przyzwyczajony do manuali że jednak chcę je mieć. Dlatego przy budowaniu coreutils powstaną dwa pakiety - jeden zawierający programy i dokumentację Info, oraz drugi zawierający tylko strony manuala. Ponieważ to są już dosyć specyficzne zmiany, więc zamieszczę cały plik .spec, oznaczając części charakterystyczne dla budowy mnogopaków.

Summary: Podstawowe programy GNU używane w linii poleceń
Name: coreutils
Version: 5.0
Release: 2
License: GPL
Group: System 
Source: %{name}-%{version}.tar.bz2

BuildRoot: /var/tmp/%{name}-%{version}
Obsoletes: sh-utils, fileutils, textutils, stat

%package manpages
Summary: Zbędne strony podręcznika dla coreutils
Group: Dokumentacja
Requires: %{name} = %{version}-%{release}

%description
Te programy to podstawowe polecenia ze skrzynki narzędziowej GNU. Pakiet
"coreutils" powstał w wyniku fuzji rozdzielnych dotąd pakietów GNU sh-utils,
GNU fileutils oraz GNU textutils.  Większość z tych programów jest
doskonalsza od swoich uniksowych odpowiedników - różnice to zwykle
zwiększona prędkość działania, dodatkowe opcje i funkcjonalność, jak również
zniesienie pewnych arbitralnych ograniczeń które występowały w oryginalnych,
uniksowych poleceniach..

%description manpages
Pakiet ten zawiera dokumentację GNU coreutils w formacie stron manuala.
Dokumentacja ta została wydzielona do osobnego pakietu, bo jest szczątkowa.
Strony manuali w coreutils powstają w wyniku przetworzenia wyjścia
"polecenie --help", nie zawierają żadnych dodatkowych informacji. Pełna,
prawdziwa dokumentacja składowana jest w postaci stron Info, instalowanych
razem z głównym pakietem coreutils

%prep
%setup -q

%build
%configure --disable-dependency-tracking --disable-assert --disable-nls
make

%install
rm -rf %{buildroot}
make install DESTDIR=%{buildroot}
mkdir %{buildroot}/bin

mv %{buildroot}%{_bindir}/{cat,chgrp,chmod,\
chown,cp,date,dd,df,echo,false,ln,ls,mkdir,\
mknod,mv,pwd,rm,rmdir,stty,sync,true,uname} %{buildroot}/bin/

rm %{buildroot}%{_infodir}/dir

#te trzy programy znajdują się już w innych pakietach (i są akurat lepsze od
#ich odpowiedników GNU, zwłaszcza "hostname" który w wersji GNU jest,
#powiedzmy to otwarcie, śmiechu warty)
rm %{buildroot}%{_bindir}/{hostname,kill,uptime}
rm %{buildroot}%{_mandir}/man1/{hostname,uptime,su}.1

%files
%defattr(0644,root,root,0755)
%attr(0755,root,root)%{_bindir}/*
%attr(0755,root,root)/bin/*
%{_infodir}/coreutils.info.gz

%files manpages
%defattr(0644,root,root,0755)
%{_mandir}/man1/*.gz

%clean
rm -rf %{buildroot} %{_builddir}/%{buildsubdir}

%post
%tidyinfo
%postun
%tidyinfo

Pakiet jest fajny, bo przy okazji używa paru miłych cech rpm-a - po pierwsze, zastępuje (Obsoletes:) te pakiety które teraz są częścią coreutils. Po drugie, jest prosty. Po trzecie, jest mnogopakowy. OK, jak widać oznaczone są trzy bloczki - dodatkowa sekcja %files, dodatkowa sekcja %description oraz coś nowego - sekcja %package, która wygląda trochę jak drastycznie okrojona preambuła. Zacznę od %package.

Jest to podstawowa sekcja która dochodzi w takich sytuacjach. Mówi ona, że będzie produkowany dodatkowy pakiet wynikowy. Obok wywołania %package podaje się od razu nazwę tego dodatkowego pakietu - a w zasadzie to nie pełną nazwę, bo "%package manpages" nie stworzy pakietu "manpages", ale %{name}-manpages. Po prostu podane słowo/słowa zostaną po łączniku doklejone do nazwy głównego pakietu. Sekcja %package to faktycznie mini-preambuła dla tego dodatkowego pakietu. Zawiera dużo mniej wpisów, bo większa część danych jest identyczna dla wszystkich budowanych pakietów, część jest nawet zbyteczna (jak np. Source:). Ale niektóre są obowiązkowe i trzeba je podać przy każdym kolejnym %package - będą to Summary: oraz Group:. Dodatkowo można podać też inne tagi jeśli to potrzebne, ja w tym przykładzie dodaję jeszcze Requires: uzależniając pakiet ze stronami manuala od obecności głównego pakietu coreutils. Tak że %package to taka malutka replika preambuły na potrzeby tych dodatkowych pakietów. Jeśli o czymś zapomnisz, to rpmbuild i tak ci przypomni.

Drugi bloczek to dodatkowa sekcja %description. Od oryginalnej różni się tym, że od razu podana jest nazwa podpakietu do którego się odnosi. Poza tym zachowuje się tak samo, jak zwykła sekcja %description.

Trzeci i ostatni tutaj bloczek to dodatkowa sekcja %files - jest ona znowu, tak jak %description, sekcją na takich samych prawach jak oryginalne %files, tyle że od razu zaznaczone jest, jakiego pakietu dotyczy. Zaczyna byc tu widoczny pewna regularność - jeśli nie jest powiedziane o jaki pakiet chodzi, to chodzi o pakiet podstawowy, domyślny. Jeśli w linii rozpoczynającej sekcję dopisze się coś jeszcze, to znaczy że sekcja ma dotyczyć jakiegoś pod-pakietu, zadeklarowanego poprzez odpowiednią sekcję %package. Jeśli ma powstać więcej pakietów, to odpowiednio deklaruje się więcej sekcji %package, %files, %description - każdą z unikatową nazwą pakietu. Bardzo proste. Są oczywiście sekcje, które nie odnoszą się do jakiegoś konkretnego pakietu (jak np. %clean), ale inne, jak %files lub %description są przypisane konkretnym pakietom i muszą być wymienione tyle razy, ile jest pakietów. No i oczywiście istnieją też sekcje, które są opcjonalne - jak np. sekcje skryptów postinstalacyjnych (w końcu jakiś pod-pakiet może mieć specjalne wymagania co do sekwencji okołoinstalacyjnej). Po zrozumieniu tego, że duplikuje się sekcje i dopisuje do nich nazwy pakietów (zdefiniowanych wcześniej za pomocą wywołań %package) robi się to całkiem zrozumiałe i intuicyjne. Tak mi się przynajmniej wydaje.

Tutaj uwaga co do nazewnictwa pakietów - jak powiedziałem, to co my podamy zostanie doklejone do nazwy głównego pakietu. Tak jest zwykle najwygodniej. Ale czasem może zajść potrzeba nazwania pakietu zupełnie inaczej i na szczęście rpmbuild na to pozwala. Wtedy wszędzie tam gdzie podaje się nazwę pakietu należy dodatkowo użyć opcji '-n'. Czyli np. '%package -n manpages' stworzy pakiet o nazwie 'manpages' - dosłownie. Opcji -n trzeba użyć wtedy jednak wszędzie - a więc również w '%files -n manpages', '%description manpages' itp.

I jeszcze jedna uwaga - coś, czego tutaj nie widać ale co pojawia się często w mnogopakach - współdzielenie. Czasem użyje się globbingu który "pokryje" te same pliki w kilku sekcjach %files - inaczej mówiąc, kilka pakietów będzie zawierało te same pliki. rpmbuild nie powie nic przy budowaniu pakietu, bo taki w końcu może być teoretycznie zamiar architekta paczki, ale zwykle jest to po prostu niedopatrzenie. Powiem to wprost: to, że załączam pliki w paczce "A" nie oznacza, że magicznie zostaną one wyłączone z pozostałych paczek. Nie, tak nie jest. Tutaj są tylko dwa w sumie wyjścia - albo uważnie konstruować wzorce - tak, by nie "łapały" więcej niż powinny (co często oznacza dosłowne wpisywanie nazw plików w %files), albo użyć makra %exclude. Makra tego używa się w sekcji %files w taki sam sposób, jak np. makr %dir czy %config, a jego zadaniem jest wykluczenie podanej pozycji z wynikowego pakietu. Brzmi idealnie, ale jest jeden hak - makro to co prawda wykluczy pliki z pakietu, ale rozmiar pakietu (zwracany np. przez "rpm -qi" będzie błędnie podawany - będzie taki, jak gdyby te pliki jednak wchodziły w skład pakietu. To oznacza, że rozmiar zwracany przez bazę pakietów a faktyczna zajętość na dysku będą dwoma różnymi liczbami - baza będzie kłamać. Nie mam pojęcia czy to jakiś błąd w moim rpm-4.1.0 czy też może tak właśnie ma działać to makro bo jego dokumentacji nie udało mi się nigdzie odszukać. Być może jest to jakieś zapomniane przez developerów polecenie, kto tam by to wiedział.

Ale to oznacza, że raczej będziesz zmuszony do korzystania ze sposobu pierwszego - uważnego pisania wzorców dopasowujących nazwy plików. Jakub Panachida, który od początków istnienia tych artykułów był nieocenioną pomocą w wyszukiwaniu błędów lub zachowań niezgodnych z dokumentacją przyglądał się wzorcom używanym przez rpmbuild i doszedł do wniosku, że jest to zasadniczo kod przeportowany z basha, używający jego najprostszego globbingu. Ale to oznacza również, że dostępna jest bashowa negacja wzorców, czyli coś w rodzaju "małego exclude". Nie jest ona zbyt potężna, nadal brakuje możliwości użycia prawdziwych wyrażeń regularnych, ale często bashowa negacja wzorca może być tym, co oszczędzi rzeźbienia kilkudziesięciu linijek dodatkowych wzorców - zainteresowani znajdą stosowne szczegóły w każdym manualu basha.

A teraz, na zakończenie, może jeszcze jeden przykład - tym razem coś z większą liczbą wynikowych pakietów, ale nadal prostego w swojej budowie - IceWM. Tutaj główny pakiet będzie zawierał binarki, dokumentacja wyląduje w osobnym pakiecie (bo pewnie wiele osób i tak z niej nie korzysta), no i w osobnych pakietach wylądują poszczególne wystroje. Do tego dzieki fikuśnym zależnościom instalowanie IceWM będzie wymagało równoczesnego zainstalowania któregoś z tematów - dowolnego, może nawet więcej niż jednego, ale przynajmniej jednego - tak, żeby zmusić użytkownika do zainstalowania któregoś z tematów ale pozostawić mu wolną rękę. A oto plik %spec, tym razem już bez oznaczania części specyficznych dla mnogopaków.

%define theme_dependency icewm-theme

Summary: Może i niewielki, ale obdarzony sporymi możliwościami WM
Name: icewm
Version: 1.2.7
Release: 1
License: GPL
Group: Powłoki
Source: %{name}-%{version}.tar.bz2
URL: http://www.icewm.org/
BuildRoot: /var/tmp/%{name}-%{version}
Requires: %{theme_dependency}

%package docs
Group: Dokumentacja
Summary: Dokumentacja dla IceWM w formie HTML
Requires: icewm

%package infadel2
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package gtk2
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package metal2
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package motif
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package nice
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package nice2
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package warp3
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package warp4
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package win95
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%package icedesert
Group: Powłoki
Summary: Dodatkowy temat dla IceWM
Requires: icewm
Provides: %{theme_dependency}

%description
Zarządca okien dla X Window System. Niewielki rozmiar, wbudowany taskbar
z zegarem i monitorkami CPU oraz sieci. Można zmieniać jego wygląd za pomocą
themes. Ogólnie dobre narzędzie, nie popada ani w skrajną prostotę, ani
patologiczną konfigurowalność.

%description docs
Dokumentacja IceWM w formie plików HTML.

%description infadel2
Dodatkowy temat dla IceWM.
Autor: xerithane@nerdfarm.org

%description gtk2
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description metal2
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description motif
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description nice
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description nice2
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description warp3
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description warp4
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description win95
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%description icedesert
Dodatkowy temat dla IceWM.
Autor: Marko Macek

%prep
%setup -q

%build
%configure --disable-nls --disable-sm \
--enable-shaped-decorations --enable-antialiasing \
--disable-xinerama --enable-x86-asm \
--with-libdir=%{_datadir}/icewm \
--with-cfgdir=%{_sysconfdir}/icewm \
--with-docdir=%{_docdir}

make

%install
rm -rf %{buildroot}
make install install-docs DESTDIR=%{buildroot}

%files
%defattr(0644,root,root,0755)
%attr(0755,root,root)%{_bindir}/*
%dir %{_datadir}/icewm
%{_datadir}/icewm/icons
%{_datadir}/icewm/keys
%{_datadir}/icewm/ledclock
%{_datadir}/icewm/mailbox
%{_datadir}/icewm/menu
%{_datadir}/icewm/preferences
%{_datadir}/icewm/programs
%{_datadir}/icewm/taskbar
%{_datadir}/icewm/toolbar
%{_datadir}/icewm/winoptions
%dir %{_datadir}/icewm/themes

%files docs
%defattr(0644,root,root,0755)
%{_docdir}/icewm-%{version}

%files infadel2
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/Infadel2

%files gtk2
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/gtk2

%files metal2
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/metal2

%files motif
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/motif

%files nice
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/nice

%files nice2
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/nice2

%files warp3
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/warp3

%files warp4
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/warp4

%files win95
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/win95

%files icedesert
%defattr(0644,root,root,0755)
%{_datadir}/icewm/themes/icedesert


%clean
rm -rf %{buildroot} %{_builddir}/%{buildsubdir}

Długie, ale łatwe do zrozumienia. Mam na szczycie zdefiniowane makro %{theme_dependency} - ono opisuje nazwę pewnej wirtualnej zależności która ma być spoiwem między pakietem z IceWM a pakietami z tematami. Wyrzuciłem ją do specjalnego makra, bo nie zastanawiałem się nad nazwą zbyt długo i wolałem mieć możliwość szybkiej tego zmiany. Każdy pakiet z tematem dostarcza tego "zasobu", a paczka z IceWM tego zasobu z kolei wymaga. Dlatego nieważne ile paczek z tematami zainstalujesz - IceWM będzie zawsze wmagał minimum jednej. Jeśli spaczkujesz jakieś zewnętrzne, niezależne tematy i też określisz by zapewniały ten określony "zasób", to będziesz mógł odinstalować wszystkie tematy fabryczne.

To nie jest ładny plik .spec, w idealnym przypadku każdy temat powinien sprawdzać przy instalacji/usuwaniu czy "domyślny" temat ustawiony w globalnej konfiguracji IceWM wskazuje na któryś z dostępnych tematów. To by oznaczało takie średnio skomplikowane sekcje post/postun, ale nie chciało mi się tego już pisać - IceWM tak naprawdę nie używam, więc nie miałem motywacji.

Hmm, chyba wszystko już powiedziałem co było do powiedzenia na ten temat. Reszta jest już w twoich rękach.