Preambuła to tylko opis, charakterystyka. Składa się z pojedynczych tagów oraz bardziej wylewnego opisu zawartości pakietu. Opis ten jest obowiązkowy, tagi już niekoniecznie (część obligatoryjna, część fakultatywna). Każdy z tagów jest definiowany w pojedynczej linii, w prostej formie ,,Tag: wartość''. Proste, prawda? No to może polecę z opisem dostępnych tagów:
Name:
Nazwa dla pakietu. To było łatwe do przewidzenia :)
Name: mutt
Version:
Wersja oprogramowania zawartego w pakiecie.
Version: 1.4i
Release:
Wersja, ale tym razem pakietu. Generalnie pakiety numeruje się poczynając od jedynki, a numer wersji podwyższa się przy każdym przebudowywaniu pakietu. Tak przynajmniej jest w dystrybucjach. W warunkach domowych warto też podwyższać te numerki, bo mówią one rpm-owi że pakiet jest ,,nowszy'', i można ,,gładko'' robić upgrade pakietów zawierających oprogramowanie w tej samej wersji. Nie żeby to była jedyna możliwość, ale odrobina porządku nigdy nie zaszkodzi.
Release: 3
Epoch:
Jest to bardzo rzadko używany tag, a w hierarchii tagów ,,wersjonujących'' stoi najwyżej, tworząc łańcuch epoch:version-release. Można go użyć gdy pakiet zmienia system numerowania wersji, np. przechodzi z układu numerowania za pomocą dat na ,,zwykły'' system numerków. Jako że tag ten jest naprawdę, naprawdę rzadko używany, to chyba nic złego się nie stanie jeśli poprzestaniemy na wyjaśnieniu, że Epoch: również określa wersję i jest bardziej znaczący od Version:, nie wspominając już o Release:. Nie jest wymagany, domyślnie ma wartość ,,0'', a jego przełączenie na wyższy numerek oznacza jakieś naprawdę przełomowe zmiany w dotychczasowej numeracji lub właściwościach pakietu. Muszą to być zmiany, których nie dałoby się jednoznacznie opisać za pomocą tagów Version: i Release.
Epoch: 1
License:
Licencja. Jeśli kod jest na ,,wielokrotnej licencji'' (zdarza się), to podaje się wszystkie dostępne do wyboru licencje, po przecinku. A, wcześniej istniał (i nadal istnieje) bliźniaczy tag ,,Copyright:'', ale obecnie jest on porzucany - wspominam o tym na wypadek, gdyby ktoś natknął się na ,,Copyright:'' w starszych specach.
License: GPL, BSD
Group:
Grupa do której ,,należy'' pakiet. Zwyczajowo używa się tutaj notacji foo/bar, gdzie należy myśleć o foo jako kategorii ,,nadrzędnej'', a bar to jakaś podkategoria w obrębie foo. Np. ,,Applications/Internet''. Co ważne: nie ma jednolitego standardu nazewnictwa. Powiem więcej - burdel jest. Każda dystrybucja używa innych określeń, a ja w swoim QuaTrin używam notacji ,,prostej'', bez podkategorii (które uważam za bzdurne), czyli np. po prostu ,,Internet''. Tag ten nie ma absolutnie żadnego znaczenia :) Jedyna jego rola, oprócz dostarczania jakiejś tam informacji o zawartości pakietu, została ukuta z myślą o jakichś nakładkach na rpm - dzięki kategoriom można dzielić pakiety w gałęzie, podgałęzie itp. Można śmiało tworzyć bzdurne nazwy dla kategorii, z chwilą zainstalowania takiego pakietu pojawi się nowa kategoria. Gdy odinstaluje się ostatni pakiet w jakiejś kategorii, to taka kategoria zniknie. Proste i niepotrzebne jeśli nie korzysta się z nakładek na rpm które sortują pakiety w grupy.
Group: Aplikacje/Multimedia
Source:
Ten tag mówi RPM-owi skąd ma brać źródła programu. Źródła będą wyszukiwane w podkatalogu SOURCES drzewka ,,budowlanego'' naszego rpm. W tagu tym baaardzo często używa się URL-i, w formie np. ftp://foo.bar.com/app/%{name}-%{version}.tar.gz, przy czym rpm zignoruje wszystko aż do ostatniego ukośnika, więc w tym przykładzie zrozumie tylko fragment %{name}-%{version}.tgz. Te zmienne których użyłem w zapisie to wygodny sposób na odwołanie się do zawartości tagów Name: i Version: - dzięki takiemu odwoływaniu do tagów przy zmianie np. wersji programu wystarczy gdy zmienię tylko tag Version: - a tag Source: zmieni się ,,automagicznie''. Tak więc rola tego wpisu jest podwójna - z jednej strony mówi on, gdzie w sieci można znaleźć pakiet ze źródłami (choć sam rpm na swoje potrzeby zignoruje wszystko aż do ostatniego ukośnika), z drugiej strony wskazuje mechanizmowi RPM nazwę pliku ze źródłami, który ten ma pobrać z katalogu SOURCES przy budowaniu. To oznacza, że wcale nie trzeba się bawić z notacją URL-ową, można po prostu podać nazwę pliku... Mam nadzieję, że to zrozumiałe.
Mała uwaga: jeden spec może wykorzystywać więcej niż jedną paczkę ze źródłami. Używa się wtedy wielu wpisów, numerowanych, np. Source0:, Source1:, Source2: itp. Source: oznacza to samo, co Source0:
Źródła powinny być dostarczane w postaci paczek tar skompresowanych programem gzip lub bzip2.
Source0: ftp://sunsite.unc.edu/pub/Linux/utils/console/%{name}-%{version}-src.tar.gz
Source1: ftp://sunsite.unc.edu/pub/Linux/utils/console/%{name}-%{version}-extra-src.tar.gz
Patch:
Tutaj podaje się listę patchy zawartych w pakiecie. Powinny się one znaleźć w tym samym katalogu co paczka ze źródłami, a listę ich podaje się podobnie do listy wielokrotnych źródeł, czyli Patch0:, Patch1: itd. Zrozumiałe?
Patche mogą być skompresowane programem gzip lub bzip2, w razie potrzeby rpm je sobie automatycznie rozpakuje.
Patch0: foo.patch
Patch1: bar.patch.bz2
NoSource:
Tag ten odgrywa rolę tylko przy budowaniu pakietów źródłowych. Jest swego rodzaju uzupełnieniem dla tagów SourceX:, bo jako argument NoSource: podaje się właśnie numer ,,X'' któregoś z wymienionych wcześniej w preambule tagów Source:. Aby włączyć ten tag np. dla źródła z linii Source3: wpisuje się ,,NoSource: 3''.
Kod źródłowy oznakowany tym tagiem nie zostanie włączony do pakietu .src.rpm, więc potem do przebudowania takiego pakietu trzeba sobie będzie ,,zorganizować'' ten brakujący kod z jakiegoś zewnętrznego źródła. Ma to swoje zastosowanie, np. wyłączenie fragmentów kodu które nie są OpenSource i nie można ich umieścić/dystrybuować w pakietach rpm, albo gdy potrzebny do kompilacji kod jest ogólnie dostępny wszystkim ,,adresatom'' pakietu i nie opłaca się go wpychać w paczkę. W zasadzie tak zbudowane pakiety źródłowe nie są zwykle niczym więcej jak opakowanymi w paczkę rpm plikami .spec (no, chyba że NoSource: nie wymieni wszystkich numerów tagów Source:).
NoSource: 0
NoSource: 2
NoPatch:
Ma się tak samo do Patch:, jak NoSource: do Source:
NoPatch: 1
NoPatch: 5
BuildRoot:
Można tutaj wskazać katalog ,,fake root'', czyli ten do którego będą ,,instalowane'' źródła w sekcji %install.
BuildRoot: /var/tmp/%{name}-%{version}
BuildArch:
Określenie architektury. Ma to pewien ;) wpływ na budowany pakiet jeśli używa się domyślnych ustawień RPM-a, dodatkową rolą jest zadecydowanie o tym, do jakiego podkatalogu w obrębie katalogu RPMS powędruje gotowy pakiet. Można używać nazwy architektury, np. ,,i686'', można też użyć ,,noarch'' na określenie pakietu niezależnego od architektury.
BuildArch: i586
URL:
A ten tag z kolei ma wskazać zwykle położenie strony domowej lub dokumentacji spakietowanego oprogramowania. Nie jest obowiązkowy, ale w dystrybucjach powinno się go używać (aby użytkownik mógł łatwo znaleźć stronę domową jakiegoś projektu).
URL: http://www.mplayerhq.hu/
Distribution:
Nazwa dystrybucji. Fakultatywna.
Distribution: Yesod
Vendor:
Ten tag oznacza, hmm, jak by to ująć... osobę lub firmę która rozprowadza pakiet. To wcale nie jest jednoznaczne z osobą która stworzyła pakiet ani z konkretną dystrybucją. To spore rozdrobnienie, ale niech będzie. Ten tag też jest nieobowiązkowy.
Vendor: Yesod Software
Packager:
Osoba, która stworzyła pakiet. Nie nazwa dystrybucji, nie dystrybutor pakietu, nie autor oprogramowania, ale osoba która stworzyła speca oraz pakiet.
Packager: <wodnik@szuwarek.net>
Summary:
Skrótowy, jednolinijkowy opis (a w zasadzie to tylko lakoniczna charakterystyka) dotycząca zawartości pakietu.
Summary: Prosty klient poczty używający gtk+
%description
To nie jest tak w zasadzie ,,zwykły'' tag, bo po pierwsze nie zajmuje jednej linii, po drugie jego definicja znajduje się pod nim samym, a po trzecie nie używa się kończącego dwukropka, za to konieczne jest prefiksowanie znakiem procenta. Tutaj zamieszcza się wielolinijkowy opis pakietu, rozciąga się on od wpisu %description aż do wystąpienia następnej sekcji/tagów. A więc nie ma on jasnego końca - kończy się tam, gdzie zaczyna się coś nowego :) Dawnymi czasy istniał tag Description:, ale obecny format pozwala na więcej. Dlatego też wydawać się może, że %description nie pasuje do reszty preambuły, ale to po prostu dlatego, że jest to ,,wyewoluowany'' tag.
%description
A tutaj umieszcza się jakiś prosty, fikcyjny opis.
Może mieć wiele wierszy tekstu, można też

wstawiać całkowicie puste wiersze. Można tworzyć opisy
zajmujące linijkę, można też ,,popłynąć'' na dziesiątki linii.
Provides:
Ten tag pozwala określić czego ,,dostarcza'' budowany pakiet. Standardowo pakiet może dostarczać różnych rzeczy - programów, bibliotek, modułów perla, a nawet tzw. ,,wirtualnych'' zasobów, czyli takich które fizycznie nie mają swojej jednoznacznej reprezentacji. Np. sendmail może dostarczać zasobu zwanego ,,mail daemon''. I zwykle używa się Provides: tylko w tym celu właśnie - aby powiedzieć, że pakiet dostarcza jakiejś ,,wirtualnej'' zależności. Bo wszystkie inne są automatycznie(!) wykrywane przy budowaniu pakietu. Np. rpm normalnie (w przypadku standardowego budowania) wylistuje sobie automatycznie wszystkie biblioteki czy programy zawarte w pakiecie, oraz doda do tego jedną wirtualną zależność nazwaną tak samo, jak pakiet (czyli po prostu dla pakietu xmms-1.2.5 ,,dostarczy'' wszystkich bibliotek, pluginów, no i wirtualnego zasobu ,,xmms''). Bardzo proste, bardzo zautomatyzowane, bardzo fajne.
Ale wracając do tematu: tag Provides: pozwala nam dodać coś do listy oferowanych przez pakiet zasobów. Zwykle używa się tego w dystrybucjach, np. można sprawić by zarówno sendmail, jak i postfix dostarczały zasobu zwanego ,,mailserver'' - i uzależnić programy klienckie od właśnie tego zasobu. Sprawi to, że obojętnie czy użytkownik zainstaluje sendmaila czy postfiksa to program kliencki będzie zadowolony - ale będzie wymagał obecności któregoś z nich. I to użytkownik będzie miał prawo wyboru który serwer zainstalować. Jak widać, tag ten nie znajduje pewnie zbyt często zastosowania. Aha, można podać więcej niż jeden zasób używając listy rozdzielanej przecinkami lub spacjami (lub nawet jednym i drugim naraz)
Provides: wwwserver
Requires:
Tutaj można podać pakiety, od których budowany pakiet ma zależeć. Zwykle jest tak, że nie ma potrzeby tego robić ręcznie - przy budowaniu pakietu sam rpm przeskanuje biblioteki i pliki wykonywalne, skrypty shellowe oraz perlowe i inne takie, po czym samodzielnie zestawi listę wymaganych bibliotek, interpreterów, czy nawet modułów perla. Dlatego tag Requires: zwykle używany jest tylko wtedy, gdy chce się wymusić zależność od konkretnego innego pakietu, albo od wirtualnej zależności. A więc jest to lustrzane odbicie Provides:, z tym że znajduje częściej zastosowanie. A dlaczego częściej? Bo uzależnia się często od siebie pakiety które mają zależność logiczną, ale niekoniecznie binarno-linkerowo-whateverową ;) Prosty przykład: Program ViM. Zwykle jest dzielony na kilka paczek - jedną zawierającą dane używane ,,runtime'', czyli np. zestawy kolorów do podświetlania różnych składni, jedną zawierającą zwykłego ViM-a i jedną zawierającą gViM-a. Nazwijmy te paczki ,,vim-shared'', ,,vim'' oraz ,,gvim''. Teraz tak: ,,vim-shared'' zawiera wszystkie dane, oprócz binariów. ,,vim'' zawiera zwykłą wersję vim-a, a ,,gvim'' jego wersję z GUI. Należy uzależnić pakiety ,,vim'' i ,,gvim'' od ,,vim-shared'', ale RPM nie zrobi tego automatycznie, bo nie posiada przecież sprawności wróżki :). Dlatego w pakietach ,,vim''/,,gvim'' człowiek je tworzący powinien zamieścić ,,Requires: vim-shared''.
Tutaj jeszcze jedna sprawa: Można przy zależnościach mówić o numerach wersji. Np. jeśli powiem, że vim-6.1 wymaga po prostu ,,vim-shared'', to rpm pozwoli również na zainstalowanie np. dużo starszej (i pewnie niekompatybilnej) wersji ,,vim-shared-5.0''. Fajnie by było, gdyby można było jakoś wymusić dozwalony numer wersji. I faktycznie można. Np. ,,Requires: vim-shared = 6.1''. Można też trochę rozluźnić rygor i powiedzieć np. ,,Requires: vim-shared >= 6.1''. To chyba zrozumiałe?
Jest jeszcze jedno dosyć częste zastosowanie tej funkcji: Można uzależnić pakiet nie tylko od biblioteki, ale także od konkretnej nazwy pakietu. O co mi chodzi? O to, że oprócz tego że program zgv zależy od libvga.so.1 to można go uzależnić od pakietu tę bibliotekę dostarczającego, czyli svgalib. Ale po co, mógłby ktoś zapytać? Przecież zależność już istnieje, poprzez libvga.so.1? To prawda, samemu systemowi RPM nie jest to potrzebne. Ale może to być wygodne dla użytkownika - jeśli spróbuje zainstalować zgv nie posiadając svgalib, to zobaczy że zgv wymaga takich to a takich bibliotek, oraz czegoś zwanego ,,svgalib''. Będzie mu łatwiej znaleźć potrzebne pakiety. Ale takie praktyki są moim zdaniem na wymarciu. Kiedyś uważało się je za znak wysokiego dopracowania pakietów, jeśli faktycznie oprócz wymagania libgtk.so.1 wymagały także ,,gtk+ >= 1.4.10''. Obecnie jednak takie rzeczy potrafią załatwić za człowieka automaty w stylu programu ,,Poldek'' czy innych. Bo nie wolno zapominać, że wprowadzanie takich ,,fikcyjnych'' zależności zmniejsza przenośność pakietu. Wystarczy, że w jednej dystrybucji pakiet zawierający libvga.so.1 będzie nazywał się ,,svgalib'', w drugiej ,,SVGAlib'', w trzeciej ,,libsvga'' i już nie będzie przenośności między nimi, bo pakiet wymaga koniecznie obecności zasobu ,,svgalib''. Warto to wziąć pod rozwagę...
Requires: svgalib >= 1.9.14
Autoreq:
Ten tag pozwala wyłączyć automatyczne wyszukiwanie zależności przez RPM. Wtedy trzeba je wszystkie podać poprzez tag Requires:
Autoreq: 0
Autoprov:
Podobnie, z tym że wyłącza się automatyczne wykrywanie tego, co dany pakiet dostarcza. Wtedy cała robota spada na autora speca i linijkę Provides:
Autoprov: 0
Autoreqprov:
A to po prostu połączenie obydwu powyższych tagów. Wyłącza od razu wszystkie mechanizmy automagicznego wykrywania zależności.
Autoreqprov: 0
BuildRequires:
Ten tag określa pakiety/biblioteki potrzebne do przebudowania pakietu. Są to zależności które trzeba podać ,,ręcznie''. Jeśli program np. używa ncurses, to w BuildRequires: należałoby wpisać ,,ncurses-devel''. Nie ma to wielkiego wpływu na samo budowanie pakietu, ale użytkownik przynajmniej dowie się od razu, że czegoś mu brakuje do skompilowania pakietu - jeśli nie będzie posiadał ncurses-devel, to rpm nawet nie zacznie budowania pakietu, a od razu się poskarży. Tag ten nie ma zastosowania w ,,domowej'' produkcji pakietów na własne potrzeby, ale przy szerszej dystrybucji należy uwzględnić tutaj każdy wykorzystywany pakiet - oszczędzaj ewentualnych odbiorców swoich pakietów ;).
BuildRequires: flex
BuildConflicts:
A ten tag z kolei pozwala ,,zablokować'' przebudowywania pakietu jeśli jest obecny w systemie jakiś konkretny pakiet. Jeśli wiadomo, że obecność jakiegoś pakietu by nie pozwoliła wyprodukować poprawnych binarek, np. można się zabezpieczyć w ten sposób przed użyciem jakiejś starej, wadliwej wersji binutils. Rzadko używany tag, ale z przyzwoitości muszę o nim wspomnieć.
BuildConflicts: gcc = 2.96.1
Obsoletes:
Pakiety wymienione tutaj jako argumenty zostaną usunięte przy instalacji nowo utworzonego pakietu. Tzn. gdy zainstalujesz ten pakiet, to wszystkie wymienione w Obsoletes: zostaną automatycznie usunięte. Przydatne jeśli przygotowywany pakiet ma za zadanie całkowicie zastąpić jakichś swoich poprzedników (np. noszących inne nazwy). Można np. uznać, że pakiet slrn-pl jest w stanie zastąpić slrn, albo że elinks może zastąpić linksa. Albo że nowy pakiet fvwm powinien zastępować fvwm2.
Obsoletes: slrn, slrnpull
PreReq:
Tag ten działa podobnie do Requires:, z tym że zależność ta konieczna jest do poprawnej instalacji pakietu. Normalne Requires: oznacza, że pakiet potrzebuje innego do swojej pracy. PreReq: oznacza, że pakiet potrzebuje innego pakietu/zasobu nie tyle do swojej pracy, co do swojej instalacji. Potrzebuje czegoś, aby w ogóle poprawnie się zainstalować/odinstalować. Chodzi tu głównie o polecenia shella użyte w sekcjach %pre czy %post
PreReq: /sbin/install-info
BuildPreReq:
Dodatek do PreReq:. Działa tak samo jak PreReq:, z tym że obowiązuje tylko podczas budowania pakietu. Bardzo rzadko używany, pewnie dlatego, że funkcjonalnie pokrywa się z BuildRequires :)
BuildPreReq: perl
DistURL:
Tag jeszcze nie występujący w pakietach. W zamierzeniu miałby wskazywać na stronę dystrybucji, ale jego standardyzacja nie dobiegła jeszcze końca.
???
Icon:
Tutaj określa się ,,namiar'' na plik z ikoną. Jedyne tego zastosowanie to fakt, że niektóre graficzne package-managers będą w stanie pokazać tę ikonkę jako ,,ikonkę pakietu''. Ikonka powinna być formatu GIF lub XPM (zalecany to XPM), z przezroczystym tłem (żeby ikonka porządnie wyglądała w takim np. ,,gnorpm'')
Icon: czaderska_ikonka_pakietu.xpm
Conflicts:
Proste - wskazuje coś, co po prostu nie może koegzystować w systemie z naszym pakietem. Np. program ,,masqmail'' nie powinien być instalowany równolegle z sendmailem, bo obydwa robią to samo. No dobra, przykład głupi, ale nic innego mi do głowy nie przychodzi :)
Conflicts: sendmail
ExcludeArch:, ExcludeOS:, ExclusiveArch:, ExclusiveOS:
Wymieniam je hurtem, bo są nieczęsto używane, powiązane ze sobą i mają w miarę opisowe nazwy. Regulują ,,dostępność'' pakietu w zależności od architektury lub systemu operacyjnego. Opcje Exclude* zabraniają budowania pakietu na określonej architekturze/systemie operacyjnym, a opcje Exclusive* z kolei zezwalają na budowę tylko i wyłącznie na podanych architekturach/systemach. Te opcje to coś w stylu ,,Nie zbudujesz tego pakietu na...'' oraz ,,Zbudujesz ten pakiet tylko na...''. Kwestia architektury jest jasna - można np. zabronić budowania jakiegoś programu uzależnionego od instrukcji mmx na maszynach które tego nie potrafią, można też np. wyłączyć całą rodzinę x86 jeśli program jest przeznaczony dla komputerów Alpha. Zdziwienie może budzić tylko uzależnianie od systemu operacyjnego - ale to się da łatwo wyjaśnić: RPM ma ambicje stania się uniwersalnym systemem pakietowania. Jeśli będzie popularny na większej ilości systemów operacyjnych, to oczywiście konieczne stanie się odróżnianie pakietów przeznaczonych dla Linuksa od tych zrobionych specjalnie dla Hurda.
ExcludeOS: irix
Prefix:
Definiuje prefiks, czyli początkowy fragment ścieżki, używany przy instalacji pakietu. Pole to można przedefiniować przy instalacji pakietu, co spowoduje że pliki wywędrują do innej niż domyślna lokacji. Jeśli program składa się raptem z kilku binarek i stron manuala, to można stworzyć taki ,,relokowalny'' pakiet, który użytkownik będzie potem mógł zainstalować albo w /usr, albo w /usr/local, albo w /opt, albo w /usr/X11R6 - wedle życzenia. Oczywiście nie zawsze da się coś takiego zrobić, niektóre programy szukają swoich danych w ściśle określonych miejscach.
Prefix: /opt
Pominąłem kilka już zupełnie rzadkich (lub słabo udokumentowanych) tagów...