rpm programmet har en build funktion, som bruges når man skal lave sine egne rpm filer. En 'build' består af flere faser
Herunder er der et antal under-directories:
Hele spec-filen ligger her, men lad os kigge på den i nogle mindre bidder.
Name: ssh
Summary: Secure Shell - secure network communications
Version: 1.2.25
Release: 2
Copyright: GPL
URL: http://www.cs.hut.fi/ssh/
Group: Utilities/Networking
Source: ftp://sunsite.auc.dk/pub/security/ssh/ssh-1.2.25.tar.gz
Patch: ssh-1.2.25-Makefile.patch
BuildRoot: /tmp/ssh-build
%description
Secure Shell enables you to communicate securely across on unsafe
network such as the Internet. Communication is transparently
encrypted, and thus secured against eavesdropping. The package
includes drop-in replacements for telnet, rlogin, rsh, rcp and
other standard networking tools.
Starten på sådan en spec-fil er ret standardiseret. Der
er en stribe tags som man skal angive - det er blandt andet al den
information om pakken, som rpm -i kommandoen skal levere.
Rækkefølgen af de enkelte tags er ligegyldig, bare de er der.
Patch tag'en er også vigtig - det er ændringer til de oprindelige sources (i form af patches) som skal installeres inden programmet kan oversættes. Disse skal også ligge i SOURCES directoryet. I eksemplet er der kun een patch; hvis man har flere, skal de nummereres, og så lister man dem et ad gangen (et patch uden nummer er automatisk nummer nul):
Patch: foo-Makefile.patch
Patch1: foo-glibc.patch
Patch2: foo-wtmpfix.patch
BuildRoot tag'en er ikke krævet, men anbefales. Det er
ikke det directory, hvori programmerne bliver oversat, men derimod
det top-level directory, hvori de oversatte programmer og øvrige
filer placeres i installations-fasen, inden de pakkes sammen i rpm-filerne.
Hvis ikke man bruger en BuildRoot tag er default at filerne placeres i
de "rigtige" directories - /usr/bin, /etc, /usr/lib o.s.v. Det gør
måske ikke noget, men hvis der er konfigurations-filer involveret
er det en rigtig god ide at bruge BuildRoot tag'en; ellers kan man nemt
risikere at komme til at overskrive sine egne omhyggeligt tilpassede konfigurations-filer
undervejs i build-processen, eller (måske endnu værre) komme
til at inkludere sine egne konfigurations-filer i rpm-pakken, som downloades
af tusindvis af brugere. (F.eks. havde jeg en overgang password-filerne
til min ISP liggende på ftp.sslug.dk, i en ppp RPM pakke). BuildRoot
tag'en er dog ofte lidt besværlig, da man næsten altid skal
rette i programmets 'Makefile' eller installations-script, for at de kan
finde ud af at installere pakkerne et andet sted end det normale. Men det
er ulejligheden værd.
%prep
i spec-filen, og så går det af sig selv.
%setup
%patch -p1
./configure --prefix=/usr
Denne fase skal gøre programmet klart til at blive oversat. Typisk skal der først installeres de forskellige patches som man har listet, og dernæst skal programmet måske konfigureres.
De linier, der står efter %setup er i virkeligheden almindelige shell kommandoer. Dog er der defineret nogle makroer, som rpm's build funktion håndterer, inden de overgives til kommando-fortolkeren - een af makroerne er %patch. Denne makro kører patch programmet, med patch nummer nul som input. For at apply'e patch nummer 1 skriver man %patch1, patch nummer 2 er %patch2 o.s.v. Rækkefølgen af de forskellige patches er ligegyldig, så længe patch-programmet kan finde ud af det. Man kan også sagtens springe patches over, f.eks. hvis de ikke er relevante for den platform man builder til.
Inden kommandoerne i setup-fasen afvikles, sættes default directory til /usr/src/redhat/BUILD/pakkenavn-version, d.v.s. /usr/src/redhat/BUILD/ssh-1.2.25 i eksemplet. Hvis source-arkivet ikke er blevet pakket ud til det directory navn (f.eks. bruger nogle source-arkiver en underscore i stedet for en bindestreg), så angiver man det rigtige directory navn på %setup linien, f.eks.
%setup -n foobar_1.17
hvis source-filerne er havnet i /usr/src/redhat/BUILD/foobar_1.17
Default directory er også vigtigt at kende, når man vælger hvilke options man giver til patch-programmet. I eksemplet kaldes patch med -p1 option, fordi patch-filen indeholder ssh_1.2.25 som første element i filnavnet. Men da default directory allerede er nede i ssh-1.2.25, bruges -p1 option for at fjerne det første directory-element fra filnavnet, inden patch leder efter de filer den skal ændre.
Konfiguration af programmet kan ske på mange måder - her er det et configure-script, som kaldes med en option om, at filerne skal bruge /usr som prefix (default er ofte /usr/local, som jeg foretrækker at reservere til ikke-rpm styrede programmer). Andre program-pakker konfigureres via en headerfil eller ved at ændre i Makefile - så må man lave en patch mellem den oprindelige fil og den rettede, og installere den som en patch i patch-listen.
Kommandoen rpm -bp specfile vil afvikle prep- og setup-fasen,
og kan bruges til at "teste" om alle ens patches nu også kan installeres
uden problemer.
%build
make CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="-s"
Her er der dog givet nogle parametre til make kommandoen. CFLAGS bliver
sat til $RPM_OPT_FLAGS - det er en environment variabel som rpm's build-funktion
giver med til alle kommandoerne i build-fasen, og som indeholder standard
"optimizer" indstillingerne for programmer, som oversættes med rpm.
Default er det "-O2 -m486 -fno-strength-reduce" på i386 platformen.
Kommandoen rpm -bc spefile vil først afvikle prep og setup faserne, og dernæst build-fasen. Hvis man har travlt og allerede har brugt rpm -bp til at afvikle prep og setup, kan man bruge rpm -bc --short-circuit specfile for bare at køre build-fasen.
Det er typisk under build-fasen, at man ramler ind i de fleste problemer.
Her kan det være nyttigt at glemme rpm et øjeblik, og i stedet
gå ned i build-directoryet og køre build-kommandoerne manuelt,
indtil man har fået rettet det hele og programmet kan oversættes.
Så laver man en patch-fil med sine ændringer, tilføjer
den til spec-filen (husk at få den med i %setup fasen!),
og går så tilbage til at builde med rpm.
Det er også vigtigt, at man sørger for at de installerede filer får korrekt ejer/gruppe attributter, og permissions.
ssh spec-filen er lidt mere kompliceret end normalt:
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT
make install
%post
if [ ! -f /etc/ssh_host_key ]; then
echo "Generating ssh host
key"
umask 022
/usr/bin/ssh-keygen -b 1024
-f /etc/ssh_host_key -N ''
fi
En del af kompleksiteten skyldes brugen af BuildRoot tag'en - inden filerne kan installeres, skal det sikres at det directory vi installerer i er tomt. Derfor slettes det først, og oprettes så bagefter igen, hvorefter 'make install' klarer resten. Det er dog ikke sket uden at jeg måtte ændre i Makefile - men det blev gjort med det patch, der blev installeret helt tilbage i setup-fasen.
Normalt vil 'make install' til ssh sørge for at generere filen
/etc/ssh_host_key, som er en del af ssh's krypterings-nøglesæt.
Men det vil jo ikke være smart at inkludere den fil i rpm-pakken;
så ville alle der brugte rpm-pakken jo have denne nøgle til
fælles. Derfor er denne del af installationen fjernet fra Makefile'n,
og i stedet lagt ud som et post-install script - det står
under %post.
Disse kommandoer vil blive afviklet når brugeren installerer
den færdige rpm-pakke, d.v.s. hver eneste gang ssh-pakken bliver
installeret på en PC. Derved får hver enkelt PC sin egen nøgle-fil.
%post bruges også til andre ting - hvis man laver en rpm-pakke med et shared library i, er det en god ide at køre /sbin/ldconfig i et post-install script; derved opdaterer man den dynamiske linker's tabel over, hvilke biblioteker der er installeret, og det kan så bruges med det samme (uden at man skal reboote systemet).
Der er andre af sådanne scripts, som man kan definere: %post-un afvikles når man af-installerer en rpm-pakke, og der er også pre-install (%pre) og pre-uninstall (%pre-un) scripts. De kan selvfølgelig kombineres.
Install-fasen køres med kommandoen rpm -bi specfile
- man kan også her bruge --short-circuit for kun at afvikle
denne fase.
%files
/usr/bin/make-ssh-known-hosts
/usr/bin/ssh
/usr/bin/ssh-add
%config /etc/ssh_config
%config /etc/sshd_config
%doc COPYING INSTALL OVERVIEW TODO
%doc README README.CIPHERS README.SECURERPC
README.SECURID README.TIS RFC TODO
Filerne listes blot med deres fulde path-navn (man ser bort fra evt. BuildRoot her). Hvis en fil er en konfigurations-fil, skal man skrive %config førend fil-navnet; det fortæller rpm-programmet, at denne fil ikke må slettes eller overskrives når man opdaterer pakken, men skal gemmes som en .rpmsave fil.
Dokumentations-filer listes med %doc - og dem behøver man ikke at bekymre sig om at skulle installere, de kopieres automatisk fra det directory, hvor source-arkivet er blevet udpakket. Dokumentations-filer placeres i /usr/doc/pakkenavn-version directoryet. Hvilke filer, man tager med som dokumentations-filer er selvfølgelig et skøn, men hellere lidt for mange end for få. (Når man installerer en rpm pakke, kan man bede om ikke at få dokumentations-filerne med - ved at bruge --excludedocs optionen).
Bemærk, at man-pages ikke regnes under dokumentation - de betragtes som en essentiel del af pakken, på lige fod med selve programmet.
Det er selvfølgelig vigtigt, at man får alle filerne med, som hører til pakken. Det kan være nyttigt at køre 'make -n install' for bare at se, hvad pakken foretager sig under installationen, og holde øje med hvilke filer der bliver hvorhen.
Hvis en pakke indeholder så mange filer, at de har deres eget subdirectory, kan man nøjes med at specificere directory'et - så følger alle filerne deri automatisk med. Det skal dog være et directory, der kun bruges af den pågældende pakke - ellers kan man få sig nogle overraskelser.
Det er også muligt at angive, at et tomt directory er en del af pakken - det vil typisk være et directory til f.eks. log-filer, som der jo ikke er nogen af når man laver rpm-filen, men som skal findes for at programmet kan køre. Det skal opremses i %files sektionen som
%dir /var/log/foobar
rpm -ba --clean specfile
Den kommando klarer det hele: Udpakning af sources, installering af
patches, konfiguration af programmet, oversættelse, installation,
sammenpakning i rpm-filer, og oprydning bagefter så BUILD directory'et
er pænt og ryddeligt.
Men min erfaring er, at den tid man bruger på at nørkle en ordentlig spec-fil sammen, er godt givet ud. Det er meget nemmere at holde styr på sin software, når man med en enkelt kommando kan få en oversigt over, hvad der er installeret, og hvilke filer hver pakke indeholder.
For nylig opgraderede jeg mit system fra RedHat 4.2 til 5.1. Det er en større opgradering, blandt andet fordi der skiftes fra de gamle libc (version 5) til det nye glibc (version 6). RedHat's installations-program klarede det meste af opgraderingen uden problemer, men jeg havde en del software pakker, som jeg selv havde lavet i rpm-format. Nu var det nemt at finde dem frem - jeg kunne bruge
rpm -qia | grep -v Manhattan
til at liste alle pakker på mit system, og filtrere RedHat's nye pakker fra. Det blev til en liste på 10-15 pakker, som jeg selv måtte stå for at opdatere til glibc - og fordi jeg havde installeret dem liggende som RPM pakker, kunne jeg nemt gentage build-processen, og rette de småting der skulle til for at de kunne oversættes med glibc. Selv programmer, jeg sidst havde haft fat i for 2 år siden kunne nemt gen-oversættes - fordi spec-filen indeholdt alle de oplysninger, der skulle til at lave programmet. Jeg behøvede ikke at granske hukommelsen for at komme i tanke om, hvordan det nu var jeg havde konfigureret programmet sidst.
Så bare klø på - det lønner sig.