Creare pacchetti HOWTO
Questa pagina descrive in dettaglio i meccanismi di base su come creare un pacchetto RPM specificatamente per Fedora (in particolare, come creare un file. Spec). Vengono dati anche alcuni avvisi pratici su cosa non funziona, che possono farvi risparmiare ore del vostro tempo.
Questa pagina non mostra le linee guida ufficiali sulla creazione dei pacchetti di Fedora (per questo, vedere la [Packaging:Guidelines| Packaging Guidelines]] e Package Naming Guidelines). Questa paginadovrebbe, comunque, essere compatibile con loro. Questa pagina non va in profondità su alcune questioni, ma vi rimanda ad altri documenti che lo fanno. A differenza di molti documenti Howto su RPM, questo documento illustra le specifiche per Fedora (con un sacco di link alle linee guida specifiche di Fedora) e tende ad essere più aggiornato (perché è mantenuto attraverso il wiki di Fedora).
Per esempio, mette in guardia dall' impatto dei cambiamenti che sono entrati in vigore dalla versione 4.4.2.x di RPM. Nonostante la sua attenzione a Fedora, la maggior parte di questo documento si applica anche ad altre distribuzioni basate su RPM. Se siete impazienti, potreste iniziare con How_to_create_a_GNU_Hello_RPM_package, che è un breve tutorial sulla creazione di un pacchetto RPM (ma non scende molto nel dettaglio come questa pagina fa).
Se si prevede di creare un pacchetto RPM per il repository di Fedora, seguite il processo Come diventare manutentori dei pacchetti Fedora Collection, insieme alle varie linee guida di Fedora.
Impostazione sistema ed account
Prima di creare pacchetti RPM in Fedora, bisogna installare alcuni strumenti di sviluppo e settare l'account (o gli account) che si userà. Come root (non digitare il '#' !)
# yum install @development-tools # yum install fedora-packager
E' possibile creare un "utente dedicato" appositamente per costruire pacchetti rpm. In questo modo, se qualcosa dovesse andare male, il programma o il processo di costruzione non cancellerà dati personali, o non invierà file o chiavi private al mondo esterno.
E' possibile creare un nuovo utente chiamato semplicemente "makerpm", impostarne la password eseguendo:
# /usr/sbin/useradd makerpm # passwd makerpm
Poi loggarsi come utente speciale (makerpm).
Una volta loggatosi, si dovrà creare una struttura nella propria cartella home eseguendo (non digitare il '$'):
$ rpmdev-setuptree
Il programma "rpm-setuptree" creerà una cartella ~/rpmbuild. All'interno di "rpmbuild" ci sono una serie di sottocartelle (come SPECS e BUILD) che si useranno per creare i propri pacchetti.
"rpm-setuptree" inoltre creerà un file ~/.rpmmacros che verrà usato da rpm e rpmbuild quando necessario.
Le linee guida per il packaging raccomandano l'uso di comandi che preservano il timestamps dei file; è possibile farlo automaticamente usando wget o curl per procurarsi i file sorgente. Se si usa wget assicurarsi che nel file ~/.wgetrc sia presente il comando "timestamping = on", allo stesso modo se si usa curl, nel file ~/.curlrc dev'essere presente il testo "-R".
Una volta fatto questi passaggi per la creazione dell'account, normalmente non sarà necessario rifarli ancora.
Le basi della creazione di pacchetti RPM
Per creare un pacchetto RPM, è necessario creare un file di testo ".spec" che fornisce informazioni sul software che viene pacchettizzato. Quindi si esegue il comando "rpmbuild" sul file spec, che completa una serie di passi per produrre il pacchetto.
Normalmente si opera collocando il sorgente originale (incontaminato), ad esempio un file tar.gz degli sviluppatori originali, in "~ /rpmbuild/SOURCES". Si consiglia di inserire il vostro file .spec in "~/rpmbuild/SPECS" chiamandolo "NAME.spec" , dove NAME è il nome base del pacchetto. Per creare tutti i pacchetti (sia binari che pacchetti sorgenti), si dove passare alla directory "~/rpmbuild/SPECS" ed eseguire:
rpmbuild -ba NAME.spec
Quando viene richiamato in questo modo rpmbuild legge il file .spec e tenta di passare attraverso le seguenti fasi (in questo ordine; i nomi che iniziano con % sono macro predefinite come descritto di seguito e le directory che ogni fase normalmente legge e scrive sono elencati di seguito):
Fase | Letture | Scritture | Azioni |
---|---|---|---|
%prep | %_sourcedir | %_builddir | Legge i sorgenti e le patch nella directory %_sourcedir (di solito ~/rpmbuild/SOURCES). Questa fase scompatta il sorgente in una sotto-directory inferiore alla directory di build %_builddir (di solito ~/rpmbuild/BUILD/) e applica le patch. |
%build | %_builddir | %_builddir | Compila i file nella directory sotto quella di build %_builddir (normalmente ~/rpmbuild/BUILD/). Di solito si possono implementare qui alcune variazioni di "./configure ; make". |
%check | %_builddir | %_builddir | Verifica che il software funziona propriamente. Fase implementata per eseguire alcune variazioni di "make test". Molti pacchetti non implementano questa fase. |
%install | %_builddir | %_buildrootdir | Questa fase legge i file nella directory sotto quella di build %_builddir (normalmente ~/rpmbuild/BUILD/) e scrive in una directory sotto la root build directory %_buildrootdir (normalmente ~/rpmbuild/BUILDROOT). I file che sono scritti è supposto che saranno installati quando il pacchetto dei binari viene installato dall'utente finale. Attenzione alla strana terminologia: La directory build root not è la stessa della build directory. Questa fase è implementata da "make install". |
bin | %_buildrootdir | %_rpmdir | Legge la directory sotto la build root directory %_buildrootdir (normalmente ~/rpmbuild/BUILDROOT/) per creare un pacchetto RPM binario sotto la directory RPM %_rpmdir (normalmente ~/rpmbuild/RPMS/). All'interno della directory RPM vi è una directory per ogni architettura, ed una denominata "noarch" per pacchetti che si possono applicare a molte architetture. Questi file RPM sono i pacchetti che gli utenti andranno ad installare. |
src | %_sourcedir | %_srcrpmdir | Questa crea un pacchetto sorgente RPM (.src.rpm) all'interno della directory RPM sorgente %_srcrpmdir (normalmente ~/rpmbuild/SRPMS). Questi file sono necessari per una revisione e un aggiornamento del pacchetto. |
Come si può vedere, alcune directory hanno scopi particolari per rpmbuild. Queste sono:
Nome della Macro | Nome | Di solito | Scopo |
---|---|---|---|
%_specdir | directory della Specifica | ~/rpmbuild/SPECS | file di specifica RPM (.spec) |
%_sourcedir | directory Source | ~/rpmbuild/SOURCES | Pacchetto dei sorgenti incontaminati (es: tarballs) e patch |
%_builddir | Build directory | ~/rpmbuild/BUILD | Source files are unpacked and compiled in a subdirectory underneath this. |
%_buildrootdir | directory root di Build | ~/rpmbuild/BUILDROOT | I file vengono installati qui durante la fase %install. |
%_rpmdir | directory dei binari RPM directory | ~/rpmbuild/RPMS | Binari RPM sono creati e immagazzinati qui sotto. |
%_srcrpmdir | directory dei Sorgenti RPM | ~/rpmbuild/SRPMS | Il sorgente RPM sono creati e immagazzinati qui sotto. |
Se una fase si interrompe prematuramente, è necessario guarda l'output per capire perch+ è fallita, cambiare il file di .spec (o altri file di input) a seconda delle necessità.
Prepararsi per pacchettizzare un programma in particolare
Se ci sono programmi speciali richiesti per costruire o avviare il programma da pacchettizzare, installarli e prendere nota di cosa sono (queste informazioni serviranno).
Per pacchettizzare un programma per i repository Fedora, si devono pacchettizzare i sorgenti incontaminati (originali), insieme a patch e istruzioni di costruzione; non va bene cominciare con codice precompilato. Salvare il file con il sorgente originale (solitamente un file .tar.gz) nella cartella "~/rpmbuild/SOURCES" (dell'utente costruttore di rpm).
Leggere dal manuale le istruzioni d'installazione del programma; si deve rendere automatizzato il tutto editando uno ".spec" file, quindi capire cosa si deve fare prima. Probabilmente è meglio fare una prova di compilazione attraverso la procedura di costruzione/installazione senza usare l'RPM per prima (è consigliato specialmente se non si ha dimistichezza con gli rpm). Con qualche eccezione, tutti i programmi binari e le librerie incluse nei pacchetti Fedora devono essere costruiti dal codice sorgente contenuto nei pacchetti sorgente.
Suddividere il programma
Il codice sorgente delle applicazioni è spesso rilasciato con il codice sorgente di librerie esterne incorporate. Non incorporare insieme librerie esterne e applicazione che le usa in un singolo pacchetto. Al contrario separarle in più pacchetti.
Licenza
Solo software che può essere pacchettizzato legalmente.
Come scritto nella sezione legal delle linee guida, se si intende destinare i propri rpm ai repository Fedora, assicurarsi di rispettare le linee guida Licensing:Main e Packaging:LicensingGuidelines. In generale, serve ai soli pacchetti software rilasciati come open source software (OSS) con una licenza approvata (così come le GNU GPL, GNU LGPL, BSD-new, MIT/X o Apache 2.0). Assicurarsi che il software sia realmente licenziato in questo modo (ad esempio controlli casuali del codice sorgente degli header, README file e così via). Se ci sono pacchetti di librerie, assicurarsi che anch'esse siano OSS.
Riusare informazioni esistenti
Provare a riutilizzare quello che si può. Ovviamente, assicurarsi che non si stia pacchettizzando qualcosa che già esiste; nella Fedora Package Collection Fedora Package Database c'é una lista dei pacchetti esistenti. Inoltre controllare la In Progress Review Requests (per pacchetti in fase di revisione) e la lista Retired Packages. In caso, vedere se qualcuno non abbia già iniziato a pacchettizzare lo stesso software per Fedora. Google con "NomeProgramma Fedora rpm" o qualcosa del genere ... forse può aiutare. E' possibile usare http://pkgs.fedoraproject.org/gitweb/ per vedere direttamente gli .spec file (e patch) di qualsiasi pacchetto esistente in Fedora.
E' possibile scaricare gli RPM sorgenti usando un programma del yum-utils, con:
Da notare: Bisogna aver installato yum-utils prima di poter eseguire yumdownloader
$ yum -y install yum-utils
Poi:
$ yumdownloader --source sourcepackage-name
In alternativa, un rpm sorgente può essere recuperato manualmente visitando la pagina web Fedora mirror http o ftp, selezionando releases/release/Everything/source/SRPMS (rimpiazzare release con la versione di Fedora desiderata), e scaricare l'rpm sorgente voluto (il nome termina con .src.rpm).
Ottenuto l'rpm sorgente, con il seguente comando se ne avvìa l'installazione:
$ rpm -ivh sourcepackage-name*.src.rpm
che piazza lo .spec file nella cartella ~/rpmbuild/SPECS ed altri sorgenti e patch in ~/rpmbuild/SOURCES.
E' possibile inoltre depacchettizzare il .src.rpm in una directory con rpm2cpio:
$ mkdir PROGRAMNAME_src_rpm $ cd PROGRAMNAME_src_rpm $ rpm2cpio ../PROGRAMNAME-*.src.rpm | cpio -i
Qualche volta è più facile iniziare con un pacchetto esistente, per poi ripulirlo per Fedora; RPM Find potrebbe aiutare a trovare RPM per sistemi non-Fedora (si possono installare rpm sorgenti di altri sistemi come in Fedora). In caso, si potrebbe vedere per pacchetti sorgente (non pacchetti .deb binari) per Ubuntu o Debian (pacchetti sorgente sono degli standard tarball con una sottocartella debian/, possibilmente associata con delle patch). Se FreeBSD ports collection dovesse averlo, si potrebbe scaricare il FreeBSD ports tarball e vedere se le loro informazioni di pacchettizzazione possono aiutare come inizio. Tuttavia, questo potrebbe non essere di aiuto a tutti. Differenti distribuzioni hanno differenti regole e quello che fanno potrebbe essere inappropriato per Fedora.
Creare un file spec
E' necessario creare ora il file ".spec" nella directory "~/rpmbuild/SPECS". E' consigliato dare al file il nome del programma, es: "programma.spec". Usa il nome dell'archivio oppure il nome sostenuto dall'autore del programma dove possibile, ma assicurati di rispettare le Linee guida per il Naming dei pacchetti.
Creare un file di spec vuoto
Quando crei uno spec file per la prima volta, è possibile usare la versione iniziale emacs o vim (dalla 7.1.270-1) che creano automaticamente un template per voi, ES.:
$ cd ~/rpmbuild/SPECS $ vi program.spec
Di seguito un esempio di questo template:
Name: Version: Release: 1%{?dist} Summary: Group: License: URL: Source0: BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: Requires: %description %prep %setup -q %build %configure make %{?_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} %clean rm -rf %{buildroot} %files %defattr(-,root,root,-) %doc %changelog
Puoi avere $RPM_BUILD_ROOT al posto di %{buildroot}; basta che sia consistente.
Puoi usare il comando rpmdev-newspec
per creare un file di spec per te. rpmdev-newspec NOME-DEL-NUOVO-PACCHETTO
crea un file spec iniziale per un nuovo pacchetto, su misura per vari tipi di pacchetti. Il programma individuerà il tipo di template da usare dal nome del pacchetto, o puoi specificare un particolare tipo di modello; controlla /etc/rpmdevtools/spectemplate-*.spec
per consultare i template disponibili. Controlla rpmdev-newspec --help
per maggiori informazioni. Per esempio, per creare un nuovo file di spec per un modulo python:
cd ~/rpmbuild/SPECS rpmdev-newspec python-antigravity vi python-antigravity.spec
Un esempio: eject
Di seguito un esempio, un pacchetto per Fedora 9 per il programma "eject":
Summary: A program that ejects removable media using software control Name: eject Version: 2.1.5 Release: 11%{dist} License: GPL Group: System Environment/Base Source: http://metalab.unc.edu/pub/Linux/utils/disk-management/%{name}-%{version}.tar.gz Source1: eject.pam Patch1: eject-2.1.1-verbose.patch Patch2: eject-timeout.patch Patch3: eject-2.1.5-opendevice.patch Patch4: eject-2.1.5-spaces.patch Patch5: eject-2.1.5-lock.patch Patch6: eject-2.1.5-umount.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root URL: http://www.pobox.com/~tranter ExcludeArch: s390 s390x BuildRequires: gettext BuildRequires: automake BuildRequires: autoconf BuildRequires: libtool %description The eject program allows the user to eject removable media (typically CD-ROMs, floppy disks or Iomega Jaz or Zip disks) using software control. Eject can also control some multi-disk CD changers and even some devices' auto-eject features. Install eject if you'd like to eject removable media using software control. %prep %setup -q -n %{name} %patch1 -p1 -b .versbose %patch2 -p1 -b .timeout %patch3 -p0 -b .opendevice %patch4 -p0 -b .spaces %patch5 -p0 -b .lock %patch6 -p1 -b .umount %build %configure make %install rm -rf %{buildroot} make DESTDIR=%{buildroot} install # pam stuff install -m 755 -d %{buildroot}/%{_sysconfdir}/pam.d install -m 644 %{SOURCE1} %{buildroot}/%{_sysconfdir}/pam.d/%{name} install -m 755 -d %{buildroot}/%{_sysconfdir}/security/console.apps/ echo "FALLBACK=true" > %{buildroot}/%{_sysconfdir}/security/console.apps/%{name} install -m 755 -d %{buildroot}/%{_sbindir} pushd %{buildroot}/%{_bindir} mv eject ../sbin ln -s consolehelper eject popd %find_lang %{name} %clean rm -rf %{buildroot} %files -f %{name}.lang %defattr(-,root,root) %doc README TODO COPYING ChangeLog %attr(644,root,root) %{_sysconfdir}/security/console.apps/* %attr(644,root,root) %{_sysconfdir}/pam.d/* %{_bindir}/* %{_sbindir}/* %{_mandir}/man1/* %changelog * Wed Apr 02 2008 Zdenek Prikryl <zprikryl at, redhat.com> 2.1.5-11 - Added check if device is hotpluggable - Resolves #438610
Spec file pieces explained
The RPM Guide, section on creating RPMs, describes the details of how to fill in a spec file. The developerWorks series "Packaging software with RPM" Part 1, Part 2, and Part 3 is also handy. Maximum RPM has the most complete information, but is dated.
You will need to follow the Fedora guidelines, such as the Package Naming Guidelines, Packaging Guidelines, and Package review guidelines.
You can insert comments with a leading "#" character, but don't insert potentially-multiline-macros (words beginning with "%") in a comment (macros are expanded first); if you're commenting out a line, double the percent signs ("%%"). Also, don't use inline comments ("#") on the same line after a script command.
Here are the major fields/areas that you will need to fill in:
- Name: The (base) name of the package. It must follow the Package Naming Guidelines. In many cases, this will be in all lower case. Elsewhere in the spec file, you can refer to the name using the macro %{name} - that way, if the name changes, the new name will be used by those other locations. This name should match the spec file name.
- Version: The upstream version number. See Packaging/Naming guidelines - package version for more information. If the version is non-numeric (contains tags that are not numbers or digits), you may need to include the additional non-numeric characters in the release field. If upstream uses full dates to distinguish versions, consider using version numbers of the form yy.mm[dd] (so a 2008-05-01 release becomes 8.05). Elsewhere in the spec file, refer to this value as %{version}.
- Release: The initial value of the release should normally be "1%{?dist}". Then, increment the number every time you release a new package for the same version of software. If a new version of the software being packaged is released, the version number should be changed to reflect the new software version, and the release number should be reset to 1. See Name Guidelines - package release for more. Packaging/DistTag describes the "dist" tag, which isn't required but can be useful. Use %{release} to reuse this value.
- Summary: A brief, one-line summary of the package. Use American English, and do not end in a period.
- Group: This needs to be a pre-existing group, like "Applications/Engineering"; run "less /usr/share/doc/rpm-*/GROUPS" to see the complete list. If you create a sub-package "...-doc" with documentation, use the group "Documentation".
- License: Its license; for software, this must be an open source software license. Use a standard abbreviation, e.g., "GPLv2+". Try to be specific, e.g., use "GPLv2+" (GPL version 2 or greater) instead of just "GPL" or "GPLv2" where it's true. See Licensing and the Licensing Guidelines for more information. You can list multiple licenses by combining them with "and" and "or", e.g., "GPLv2 and BSD". Call this tag "License"; don't use the older, inaccurately named tag "Copyright".
- URL: The URL for more information about the program, e.g., the project website. Note: This is NOT where the original source code came from, see "Source" (next!).
- Source0: The URL for the compressed archive containing (original) pristine source code, as upstream released it. "Source" is synonymous with "Source0". If you give a full URL (and you should), its basename will be used when looking in the SOURCES directory. If possible, embed %{name} and %{version}, so that changes to either will go to the right place. Warning: Source0: and URL: are different - normally they are both URLs, but the "URL:" entry points to the project website, while the "Source0:" entry points to the actual file containing the source code (and is typically a .tar.gz file). As noted in the guidelines, "When downloading sources, patches etc, consider using a client that preserves the upstream timestamps. For example wget -N or curl -R. To make the change global for wget, add this to your ~/.wgetrc: timestamping = on, and for curl, add to your ~/.curlrc: -R." If there is more than one source, name them Source1, Source2, and so on. If you're adding whole new files in addition to the pristine sources, you can list each of them as sources as well, but list them after the pristine sources. A copy of each of these sources will be included in any source package you create (unless you specially direct otherwise). See Packaging/SourceURL for more information on special cases (using revision control, when upstream uses prohibited code, etc.).
- Patch0: The name of the first patch that you will apply to the source code. If you need to patch the files after they've been uncompressed, you should edit the files, save their differences as a "patch" file in your ~/rpmbuild/SOURCES directory. Patches should make only one logical change, so it's quite possible to have multiple patch files.
- BuildArch: If you're packaging files that are architecture-independent (e.g., shell scripts, data files, etc.), then add "BuildArch: noarch". The architecture for the binary RPM will then be "noarch".
- BuildRoot: This is where files will be "installed" during the "%install" process (which happens after the %build compilation process). Normally you should just leave this line alone; under the usual Fedora setup, this will be a macro that will create a new special directory under /var/tmp. Newer versions of RPM will ignore this value, and instead place the build root in "%{_topdir}/BUILDROOT/".
- BuildRequires: A comma-separated list of packages required for building (compiling) the program. These are not automatically determined, so you need to include everything needed to build the program. There are a few packages that are so common in builds that you don't need to mention them, such as "gcc"; see the Packaging Guidelines for the complete list of the packages you may omit. You can also specify minimum versions, if necessary, like this: "ocaml >= 3.08". You can have more than one line of BuildRequires (in which case they are all required for building). If you need file /EGGS, you can get its package by running "rpm -qf /EGGS"; if EGGS is a program, you determine its package quickly by running "rpm -qf
which EGGS
". Try to specify only the minimal set of packages necessary to properly build the package, since each one will slow down a "mock"-based build (e.g., try to use sed instead of perl if you don't really need perl's abilities). Watch out: Some applications permanently disable functions if their package isn't detected during the build; in those cases you may need to include those additional packages. If you have trouble figuring out this list, the "auto-br-rpmbuild" command (from the auto-buildrequires package) may be helpful. - Requires: A comma-separate list of packages that are required when the program is installed. Note that the list of packages for Requires (what's required when installing/running) and BuildRequires (what's required to build the binary RPM) are independent; a package may be in one list but not the other, or it could be in both. The dependencies of binary packages are in many cases automatically detected by rpmbuild, so it is often the case that you don't need to specify the Requires tag at all. But if you want to highlight some specific packages as being required, or require a package that rpm can't detect should be required, then add it here.
- %description - A longer, multi-line description of the program. Use American English. All lines must be 80 characters or less. "Blank lines are assumed to separate paragraphs. Some graphical user interface installation programs will reformat paragraphs... (lines that) start with whitespace, such as a space or tab, will be treated as preformatted text and displayed as is, normally with a fixed-width font." (per the RPM Guide).
- %prep - Script commands to "prepare" the program, that is, to uncompress it so that it will be ready for building (compiling). Typically this is just "%setup -q" or some variation of it; a common variation is "%setup -q -n NAME" if the source file unpacks into NAME. See the "%prep" section below for more.
- %build - Script commands to "build" the program, that is, to compile it and get it ready for installing. The program should come with instructions on how to do this. See the "%build" section below for more.
- %check - Script commands to self-test the program. This is run after %build and before %install, so you should place it there if you have this section. Often it simply contains "make test" or "make check". This is separated from %build so that people can skip the self-test if they desire. This isn't documented in many places.
- %install - Script commands to "install" the program. The commands should copy the files from the "build directory" %{_builddir} (which would be under ~/rpmbuild/BUILD) into the buildroot directory, %{buildroot} (which would normally be under /var/tmp). See the "%install" section below for more.
- %clean - instructions to clean out the build root. Typically:
rm -rf %{buildroot}
- %files - the list of files that will be installed. See the "%files" section below for more.
- %changelog - Changes in the package. Use the format example above.
- ExcludeArch: If the package does not successfully compile, build or work on an architecture, then those architectures should be listed in the spec in an ExcludeArch tag.
- You can add sections so that code will run when packages are installed or removed on the real system (as opposed to just running the %install script, which only does a pseudo-install to the build root). These are called "scriptlets", and they are usually used to update the running system with information from the package. See the "Scriptlets" section below for more.
Don't use the tags "Packager" or "Vendor". Don't use "Copyright" - use "License" instead. Don't create a "relocatable" package - they don't add value in Fedora yet they make things more complicated.
RPM supports subpackages, that is, a single spec file can generate many binary packages. For example, if the documentation is very large, you might generate a separate "-doc" subpackage. See below for more.
%prep section
The "%prep" section describes how to unpack the compressed packages so that they can be built. Typically, this is a set of "%setup" and/or %patch commands, which reference the Source0:, Source1:, etc. lines above. See the Maximum RPM section on %setup and %patch for more details.
Warning: In spec files, don't use in-line comments (a "#" comment on the same line after a command), and don't put macros (words beginning with "%") in a comment unless you quote the "%" as "%%". Macros can cause failures if they are in a comment, because they are always expanded (even when in a comment) and they can expand to multiple lines. This is true for %prep, %build, and so on.
The new RPM 4.4.2.x series adds two new macros, %{patches} and %{sources}, so you can do things like:
for p in %{patches}; do ... done
These new macros can be very useful if you have a large list of patches or sources. However, keep in mind that using these will make your spec incompatible with the rpm used in Fedora 9 and earlier, RHEL, and many other RPM-based distros.
%prep section: %setup command
The "%setup" command unpacks a source package, and takes several switches. Normally you should use "-q" (quiet) to prevent setup from babbling about every file it unpacks. Here are a few switches besides -q:
- -n name: If the name of the rpm is something other than what the Source unpacks to, use this switch to state the name it unpacks to. E.G., if the tarball unpacks into a directory MYNAME, use %setup -q -n MYNAME
- -c name: If the tarball doesn't unpack into a single directory, this creates a directory named name and then unpacks into it. Useful if you have one of those annoying tarballs that doesn't have a single common subdirectory embedded in it.
There are more %spec options if you are unpacking multiple files, which is primarily useful if you are creating subpackages (see below). The key ones are:
-a number | Only unpack the source directive of the given number, such as –a 0 for source0:, after changing to the directory. |
-b number | Only unpack the source directive of the given number, such as –b 0 for source0:, before changing to the directory. |
-D | Do not delete the directory before unpacking. |
-T | Disable the automatic unpacking of the archives. |
%prep section: %patch commands
The "%patch0" command applies patch 0 (similar for 1, 2, etc.). Patches are the normal way to change to the source code if necessary to package it. The normal "-pNUMBER" option applies, which simply passes that argument on to patch.
Patch file names often look like "telnet-0.17-env.patch", that is, %{name}-%{version}-patch_purpose.patch (some people omit -%{version}). Patch files are typically the result of a "diff -u"; if you do this from the subdirectory of ~/rpmbuild/BUILD, you won't have to specify a -p level later. You can use all the normal ways of creating a patch file.
If you're creating a patch file a single file FILENAME, a common way is to copy it to FILENAME.orig, modify it, and then save the results of "diff -u FILENAME.orig FILENAME". If you change directory to "~/rpmbuild/BUILD/NAME", you could create a patch file to change a single file by doing:
cp X/Y.Z X/Y.Z.orig vim X/Y.Z diff -u X/Y.Z.orig X/Y.Z > ~/rpmbuild/SOURCES/PKGNAME.REASON.patch
If you're going to edit many files, one easy method is to copy the whole subdirectory underneath BUILD, and then do subdirectory diffs; once you change directory to "~rpmbuild/BUILD/NAME", you can:
cp -pr ./ ../PACKAGENAME.orig/ ... many edits ... diff -u ../PACKAGENAME.orig . > ~/rpmbuild/SOURCES/NAME.REASON.patch
If you edit many files in one patch, you can also copy the original files using some consistent ending such as ".orig" before editing them. Then, you can use "gendiff" (in the rpm package) to create a patch with the differences. Do "man gendiff" for more information.
Try to ensure that in your patch the "context" matches exactly. In old versions of Fedora, the default "fuzz" value was 2, which meant that imprecise matches were acceptable. However, the version of RPM used by Fedora 10 and later have a default fuzz to 0, requiring that matches be exact. You can work around this by adding "%global _default_patch_fuzz 2", but it's better to not have the problem by making the patch match the context exactly.
As explained in Packaging/PatchUpstreamStatus, all patches in Fedora spec files SHOULD have a comment above them about their upstream status. This should document the upstream bug/email that includes it (including the date), or if it's Fedora-unique, why it is unique. The Fedora Project focuses, as much as possible, on not deviating from upstream in the software it includes in the repository - see Staying close to upstream projects for more about why it's important to do this.
%prep section: Unmodified files
Sometimes, you'll package just a straight file that doesn't need to be uncompressed, e.g., a "Source1:" that is just a simple PDF file. These might not be from external sources, e.g., perhaps you've had to create a few additional files that weren't in the original sources so that the package cleanly installs in Fedora. You can "prep" those into the build directory by doing this (replace "1" with whatever number it is):
cp -p %SOURCE1 .
%build section
The "%build" section is sometimes complicated; here you configure and compile/build the files to be installed.
Many programs follow the GNU configure approach (or some variation). By default, they will install to a prefix of "/usr/local" (/usr/local/bin, /usr/local/lib, etc.), which is a reasonable default for unpackaged files. However, since you are packaging it, you will want to change the prefix to "/usr", since this is now a package maintained by the system itself. If there are any libraries, they'll need to be installed in the right directory, which is either /usr/lib or /usr/lib64 depending on the architecture (the actual value is in %{_libdir}).
Since the GNU "configure" system is so common, rpm pre-defines a macro named "%configure", which invokes GNU configure with the right options (e.g., it changes --prefix to /usr). This means that some variation of this will often work as a build command:
%configure make %{?_smp_mflags}
Sometimes you'll want to override the variables of a makefile; you can easily do that by passing them as parameters to make, like this:
make %{?_smp_mflags} CFLAGS="%{optflags}" BINDIR=%{_bindir}
If you need to do something complicated with GNU-generated configure, take a look at "GNU autoconf, automake, and libtool". A good presentation on these as well as "make" is "Open Source Development Tools: An Introduction to Make, Configure, Automake, Autoconf" by Stefan Hundhammer.
Some programs use Cmake. See Packaging/cmake for some suggestions.
If you include some self-tests (and that's a good idea), put them in a separate "%check" section that immediately follows the "%build" area, instead of including them in %build. That way, it will be easy for the system to skip unnecessary self-tests.
%check section
The "%check" section does testing, often it's "make test". This is not documented in many other sources of RPM info.
%install section
The "%install" section is a set of script commands to "install" the program. The commands in this section should copy the files from a directory inside the "build directory" %{_builddir} (normally ~/rpmbuild/BUILD/something) into the build root directory, %{buildroot} (normally /var/tmp/something), creating the directories inside %{buildroot} as necessary.
Watch out: Some of the terminology is very misleading:
- The build directory (under which compilations occur during %build) and the build root (where files are copied into during the %install process) are different. The point of the %install process is to copy files, such as those under the build directory, to the right place in the build root. Perhaps "buildroot" should be called "installroot", but it's too late now, the terminology is entrenched.
- The build directory is normally ~/rpmbuild/BUILD, while the build root (where files get installed to during %install) is normally ~/rpmbuild/BUILDROOT. The %prep stage will normally create a subdirectory underneath the build directory as part of %setup, and populate the build directory with files (based on the source information in %_sourcedir, which is typically in ~/rpmbuild/SOURCES). During %build, the current directory will actually start at %{buildsubdir}, that newly-created subdirectory under the build directory. Typically %{buildsubdir} is something like ~/rpmbuild/BUILD/%{name}-%{version}.
- The "%install" script is not used when the binary rpm package is installed by the end-user!! The term "%install" is misleading, in fact, the script must not install the programs in the REAL final locations (e.g., in /usr/bin), but under the buildroot %{buildroot}.
Normally, the install script would first erase the %{buildroot} directory, and then do some variation of "make install" (ideally using DESTDIR=%{buildroot}, if the program supports it). Here's an example of an %install section:
%install rm -rf %{buildroot} make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install
Ideally, every program would have a "make install" command that supported the DESTDIR convention. If the program includes a "make install" that supports DESTDIR, where possible, use it. The DESTDIR convention supports redirecting file installations to descend from a specific directory, which is exactly what we want during %install.
Installing a program that does not support DESTDIR can be much harder, and no option is as good as native DESTDIR support. Consider these alternatives:
- Patch the makefile so that it does support DESTDIR. Create directories inside DESTDIR where necessary (feel free to use "mkdir -p", the "-p" option of mkdir is now standard and widely supported). Be sure to submit the patch upstream.
- Use "%makeinstall". Many older RPM documents suggest using "%makeinstall", which might work if "make install" doesn't support DESTDIR. However, as noted in the Fedora guidelines, the %makeinstall macro "must NOT be used when make install DESTDIR=%{buildroot} works. %makeinstall is (merely) a kludge that can work with Makefiles that don't make use of the DESTDIR variable...". Unfortunately, this sometimes has subtle failures, which is why %makeinstall should not be used if DESTDIR works. The reason is based on how %makeinstall works. The "%makeinstall" macro expands to something like "make prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir} ... install". Many programs will quietly recompile or change parts of the program when values like prefix are changed, resulting in an incorrect installation. See the Fedora guidelines if you want the details on why this approach can fail. You will probably need to create appropriate directories inside %buildroot before calling %makeinstall (e.g., mkdir -p %{buildroot}%{_bindir}/).
- Consider using the auto-destdir package. This requires "BuildRequires: auto-destdir", and changing "make install" to "make-redir DESTDIR=%{buildroot} install". This only works well if the installation uses only certain common commands to install files, like cp and install; see "man make-redir" for details.
- Do the installation "by hand", that is, instead of invoking a build system, copy the files to the correct locations. Basically, this would be a sequence that would create directories that weren't already created by the "BuildRequires" packages (typically using install -d or mkdir -p), followed by copying of files from the current directory (inside the build directory) into the buildroot directory (typically using "cp -p" and/or "install -p"). Running "make -n install" may make it easy to determine what this sequence should be. Be sure to create directories inside %buildroot where necessary. One serious problem with this approach is that it's easy to fail to install new or renamed files during an update—so if there's a better approach, use it instead. If you do perform the installation "by hand", be especially careful with updates when using this approach. For example:
%install rm -rf %{buildroot} mkdir -p %{buildroot}%{_bindir}/ cp -p mycommand %{buildroot}%{_bindir}/
As noted in the packaging guidelines' timestamp section, "when adding file copying commands in the spec file, consider using a command that preserves the files' timestamps, eg. cp -p or install -p". So, if the makefile lets you override the install command (typically named INSTALL), you might want something like INSTALL="install -p" CP="cp -p" as make parameters, like this:
make INSTALL="install -p" CP="cp -p" DESTDIR=%{buildroot} install
%files section
The %files section identifies what files and directories were added by the package - and thus, which files and directories are owned by the package. Ownership is important - when you type "rpm -qif blah", you'll see who owns blah. This section is used when performing the bin stage, to determine which files are placed into each binary RPM file.
%files Basics
The %files section normally begins with a %defattr line which sets the default file permissions. The format of this is %defattr(<file permissions>, <user>, <group>, <directory permissions>), that is, one can specify the permissions to apply to files and directories in the %files section. The fourth parameter is often omitted. Usually one uses %defattr(-,root,root,-), where "-" means "use the default permissions".
This is followed by names or patterns of the directories or files to be installed and owned by this package. You should use macros for directory names, e.g., use %{_bindir}/myfile instead of /usr/bin/myfile, and %{_sbindir}/killaccount instead of /usr/sbin/killaccount. If a name or pattern begins with "/" when expanded, then it is presumed to have been copied into the %{buildroot} followed by that pattern; when installed on the final system, it will be copied into that name without the buildroot prefix. If you don't precede the pattern with "/", then it is presumed to be in the current directory (e.g., inside the build directory) - this is used for "documentation" files. So if your package just installs /usr/sbin/mycommand, then your %files section could simply say:
%files %defattr(-,root,root,-) %{_sbindir}/mycommand
Any file or directory identified in the %files section is owned by the defining package. You should make sure that you declare ownership of every new file or directory the package creates. You can use wildcards (*) which match a set of files - this makes the package less sensitive to changes. For example, you can declare that all the files that were copied into %{buildroot}/usr/bin are owned by this package by declaring:
%{_bindir}/*
Note that "%{_bindir}/*" does not claim that this package owns the /usr/bin directory - it claims that all the files that were installed inside the build root 's /usr/bin are owned by the package. If you list a directory in the %files section, then you are claiming that this package owns that subdirectory and all files and directories in it, recursively (all the way down) if they are present in the build root. Do not list the "/usr/bin" or "%{_bindir}" directories directly in your %files list, because that would claim ownership of /usr/bin and everything inside it. Claiming ownership of "%{_bindir}/*" is fine, though; that just claims ownership of the subdirectories and files you placed under %{buildroot}/%{_bindir}. If you create a subdirectory such as %{_datadir}/%{name}, (/usr/share/NAME), you should include that directory in the %files list:
%{_datadir}/%{name}/
It's usually easier to use wildcards for filenames, and that's also better at coping with changes in upstream. Older RPM documentation typically shows long lists under %files with individual names, such as /usr/bin/program1 followed by /usr/bin/program2. Because of the way Fedora now uses buildroots, that is no longer necessary.
It's an error if no file matches the wildcard of a line, so only note the directories that actually matter. Also, you can't identify the same file or directory more than once. Finally, it's an error to have something in the buildroot and not listed under %files; the whole point of copying something into the buildroot is because you intend to have it installed in the final system. If you don't intend that, remove those files during the %install process.
It is also possible to exclude files from a previous match by using a %exclude glob. This can be useful for including "almost all" of the files that match a different glob. However, note that, like any other file glob, even a %exclude glob will fail if it matches nothing. (This might be considered counterintuitive, as the whole point is essentially to ensure that a certain file ISN'T there, so this rule is especially important to remember.)
%files prefixes
You may need to add one or more prefixes to a %files entry (if more than one, use a space to separate them).
Typically there is a "%doc" entry with a list of documentation files that didn't get copied into the buildroot; usually there is at least a README and LICENSE file. You must include the license file, if there is one. You may prefix some of these with %attr(mode, user, group) to set the file permission mode, user, or group. You don't need to claim ownership of the /usr/share/doc/%{name} directory, that's automatic if there's a %doc entry. Any %doc entry must not affect the runtime of the application (if it is in %doc, the program must run properly if it is not present).
There is a potential 'gotcha' with %doc entries: if you have a %doc entry, then you can't use commands during %install to copy files into the documentation directory descending from %_defaultdocdir. That's because if there's a %doc entry, rpmbuild will automatically remove the docdir files created by %install before installing the files listed with %doc. This can hit you if, for example, you want an "examples" subdirectory in the documentation directory. In this case, don't use "%doc" to mark documentation. Instead, create the directories and copy the files into %{buildroot}%{_defaultdocdir}/%{name}-%{version}/ during %install, and make sure that %files includes an entry for "%{_defaultdocdir}/%{name}-%{version}/". They will still be correctly marked as documentation.
If you save configuration files (under /etc - don't put them under /usr), you should normally prefix them with %config(noreplace) unless this program version uses a non-backwards-compatible configuration format (in which case, prefix them with %config).
Prefixing a %files entry with "%attr(mode, user, group)" lets you set the permissions for particular file(s), e.g., "%attr(0644, root, root)". A "-" means "use the default".
If a file is in particular natural language, use %lang to note that. E.G.:
%lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*
Programs using Locale files should follow the recommended method of handling the i18n files:
- find the filenames in the
%install
step:%find_lang ${name}
- add the required build dependencies:
BuildRequires: gettext
- use the found filenames:
%files -f ${name}.lang
Some documentation claims that %license and %readme are valid prefixes; they are not valid in Fedora. Use %doc instead.
%files and Filesystem Hierarchy Standard (FHS)
You should follow the Filesystem Hierarchy Standard (FHS), i.e., ordinary application executables go into /usr/bin, global configuration files go into /etc, ordinary libraries go into /usr/lib, and so on, with one exception: executables that should not normally be executed directly by users or administrators should go into a subdirectory of /usr/libexec; usually you'd refer to the necessary directory as "%{_libexecdir}/%{name}".
You shouldn't be installing files under /usr/local; that is where unpackaged files go. Typically there will be a "prefix" attribute that lets you set the prefix to be "/usr" instead of "/usr/local".
Unfortunately, many programs' "normal" installation routines do not follow the FHS. In particular, many programs normally place architecture-independent libraries under /usr/lib, instead of under /usr/share as the FHS requires. The FHS /usr/lib section says that /usr/lib is for architecture-dependent data (e.g., ELF files like .so files), while /usr/share is for architecture-independent data. That way, systems with different CPUs can share /usr/share. There are many exceptions to this rule in Fedora (e.g., Python and Perl), but Fedora applies this rule more strictly than some distributions. Note, for example, that rpmlint will complain if you put just about anything other than ELF files into /usr/lib.
%files example
Here's a simple example of a %files section:
%files %defattr(-,root,root,-) %doc README LICENSE %{_bindir}/* %{_sbindir}/* %{_datadir}/%{name}/
Finding duplicates
The Fedora guidelines require that "A Fedora package must not list a file more than once in the spec file's %files listings."
You can list any duplicates of two binary packages by doing:
cd ~/rpmbuild/RPMS/ARCH # Substitute "ARCH" for your architecture rpm -qlp PACKAGE1.*.rpm | sort > ,1 rpm -qlp PACKAGE2.*.rpm | sort > ,2 comm -12 ,1 ,2
Scriptlets
You can add sections so that code will run when packages are installed or removed on the real system (as opposed to just running the %install script, which only does a pseudo-install to the build root). These are called "scriptlets", and they are usually used to update the running system with information from the package.
The scriptlets in %pre and %post are run before and after a package is installed (respectively). The scriptlets %preun and %postun are run before and after a package is uninstalled. The scriptlets %pretrans and %posttrans are run at start and end of a transaction. See Packaging/ScriptletSnippets for more examples and details. For example, every binary RPM package which stores shared library files (not just symlinks) in any of the dynamic linker's default paths, must call ldconfig in %post and %postun (post-install and post-uninstall). If the package has multiple subpackages with libraries, each subpackage should also have a %post/%postun section that calls /sbin/ldconfig. For example:
%post -p /sbin/ldconfig %postun -p /sbin/ldconfig
Beware: The "-p" option specifies what command processor to use for the commands on the following lines. If there are no following lines, then using /sbin/ldconfig as the "command processor" is a minor efficiency improvement compared to putting "/sbin/ldconfig" on the next line, and letting the shell invoke it. That's because by using "-p", the shell isn't invoked simply to invoke a single program. But if you have multiple shell commands, don't use "-p" or /sbin/ldconfig after it! Instead, leave it blank, and include the shell commands under it.
If you are going to run programs in scriptlets, they must be installed before you run them. You have to use special variants of the "Requires:" tag, so that the program will be installed before you try to use it. These are of the form "Requires(CONTEXT):", e.g., "Requires(post)".
Most scriptlets (%pre, %post, %preun, and %postun) provide an argument you can use, accessed via $1, which is the number of packages of this name which will be left on the system when the action completes. Don't compare for equality with 2; check if they are greater than or equal than 2, since users can arrange to have multiple versions of a package installed simultaneously. For %pretrans and %posttrans, $1 is always 0.
For example, after adding an info manual to the system the dir file which indexes the info manuals should be updated. Basically, after you install the info manual, you need to run the program install-info. That's fine, except that install-info is part of package info, and there's no guarantee that info is installed unless we require it. Also, if "install-info" fails, we don't want to fail all processing. Here's one way to do that:
Requires(post): info Requires(preun): info ... %post /sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || : %preun if [ $1 = 0 ] ; then /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || : fi
There is another glitch related to installing info files. The install-info
command will update
the info directory, but we have to prevent the install of a useless, empty directory file from the
RPM_BUILD_ROOT environment, by deleting it in the %install
section:
rm -f $RPM_BUILD_ROOT%{_infodir}/dir
Another scriptlet-like abilility are triggers. You can define triggers for when other packages are installed or uninstalled. See Maximum RPM for more information about triggers.
Macros
Spec files may contain "macro" references (text beginning with "%"), which are replaced with other values. You can follow % by a word, e.g., "%name", but just like shell variables you must bracket the name with {...} if letters or digits immediately follow, e.g., "%{name}".
As noted in the Packaging Guidelines, There are two styles for referring some values such as the rpm Build Root and Optimization Flags:
- "macro style": %{buildroot}, %{optflags}
- "variable style": $RPM_BUILD_ROOT, $RPM_OPT_FLAGS
Pick a style and use it consistently throughout your packaging; this document uses "macro style".
Here are some typical macros:
Macro | Typical Expansion | Meaning |
---|---|---|
%{_bindir} | /usr/bin | Binary directory (where executables are usually stored) |
%{_builddir} | ~/rpmbuild/BUILD | Build directory; files are compiled a subdirectory of the build directory. See %buildsubdir. |
%{buildroot} | ~/rpmbuild/BUILDROOT | Build root, where files are "installed" during %install. The %install stage copies files from a subdirectory of %{_builddir} to a subdirectory of %{buildroot}. Historically %{buildroot} was in "/var/tmp/". |
%{buildsubdir} | %{_builddir}/%{name} | Build subdirectory, where files are compiled during %build. It's under %{_builddir}, set after %setup. |
%{_datadir} | /usr/share | Share directory. |
%{_defaultdocdir} | /usr/share/doc | Default documentation directory. |
%{dist} | .fcNUMBER | Distribution+version short name (e.g., ".fc9") |
%{fedora} | NUMBER | Number of fedora release (e.g., 9) |
%{_includedir} | /usr/include | |
%{_infodir} | /usr/share/info | |
%{_initrddir} | /etc/rc.d/init.d | |
%{_libdir} | /usr/lib | |
%{_libexecdir} | /usr/libexec | |
%{_localstatedir} | /var | |
%{_mandir} | /usr/share/man | |
%{name} | Name of package, set by Name: tag | |
%{_sbindir} | /usr/sbin | |
%{_sharedstatedir} | /var/lib | |
%{_sysconfdir} | /etc | |
%{version} | Version of package, set by Version: tag |
To see more about macros you can look in /etc/rpm/* and the "macros" files under "/usr/lib/rpm/", especially /usr/lib/rpm/macros. You can also use "rpm --showrc" to show the values rpm will use for all of the options currently set in rpmrc and macro configuration files.
You can set your own macro values using %global; be sure to define them before you use them. Macro definitions can refer to other macros. For example:
%global myvalue 50
You can use rpmbuild to find the value of some macro, using its "-E" (--eval) option. For example, to find the current expansion of %{_bindir} in myfile.spec, you can run:
rpmbuild -E '%{_bindir}' myfile.spec
Packaging/RPMMacros has more information on macros, as does RPM Guide chapter 9.
Other tags
We noted the "Requires" and "BuildRequires" tags earlier. There are a few other tags for controlling dependencies: Provides, Obsoletes, Conflicts, and BuildConflicts.
- "Provides:" lets you list virtual package names that this package provides. Sometimes there are several different packages that can provide a function, and using packages won't care which one. In that case, each of the packages that provide the function should "provide" a virtual package, and then using packages can list the virtual package name under "Requires:". For example, several different packages might provide "latex"; if you depend on the virtual package "tex(latex)", then users can choose which package to get "latex" from. If you provide virtual packages, you might also want to use the "alternatives" system, but be careful: "alternatives" settings are system-wide, so if multiple users on the same system might want different defaults, don't use the alternatives system. You can find out what a given package provides (both virtual and non-virtual names) by querying "rpm -q --provides PACKAGENAME". Some virtual packages in Fedora are:
- MTA : Used for mail transport agents, such as sendmail.
- tex(latex) : Used for latex
- "Obsoletes:" lets you state that installing this package should (normally) cause the removal of the other named package(s). This is useful when a package's name changes, or when a package wholly replaces a different package.
- "Conflicts:" lets you state what packages cannot be installed simultaneously this one. Obviously, try to avoid this if you can; see Packaging/Conflicts if you think you need to use it.
- "BuildConflicts:" lets you state what packages cannot be installed when building this package. Obviously, try to avoid this if you can.
You can control which architectures a package builds (or doesn't build). For example, if your package can't compile on ppc, you can do this:
ExcludeArch: ppc
There's also an "ExclusiveArch" tag. The valid architectures one can specify in these tags are listed in the Architectures section.
Subpackages
A spec file can define more than one binary package, e.g., client and server, or runtime and developer packages. If there's a large amount of documentation, it may be split into a NAME-doc subpackage. You will always have one spec file and one source RPM (SRPM), even if there are multiple binary RPMs that they generate. A spec file that produces multiple binary packages still has only one creation process, so there is only one %prep, %build, %check, and %install section that creates all the files for all the packages.
In a spec file, use the %package directive to start defining a subpackage:
%package sub_package_name
By default, the subpackage name is PACKAGE_NAME, "-", SUBPACKAGE_NAME; you can use "-n" to override this and make a new name:
%package -n new_sub_package_name
After the %package directive, list the tags for the subpackage. This should include at least the "Summary:" and "Group:" tags and directives "%description SUBPACKAGE_NAME" and "%files SUBPACKAGE_NAME". Anything not specified by the subpackage will be inherited from its parent. For the directives, if you used "-n" with %package, you'll need it again for these directives. You need to specify the name for the other directives, e.g., %pre and %post, if you use them in the subpackage.
See the RPM Guide section on subpackages for more information.
Conditionals
You can insert conditional statements. E.G., you can test if you are creating a binary for a certain architecture with:
%ifarch ARCHITECTURE_NAME
the negated version with:
%ifnarch ARCHITECTURE_NAME
or the more general conditional:
%if TRUE_OR_FALSE
There is an optional "%else" section; all of these are closed with "%endif".
Application Specific Guidelines
There are many application-specific guidelines that can help you (e.g., for specific programming languages, applications, libraries, and build systems). Many of them are listed as part of the Application Specific Guidelines of Packaging/Guidelines. Examples of application-specific guidelines are those for:
Failing that, some other ways of finding application-specific help are:
- The 'SEARCH' command on Fedoraproject.org.
- PackagingDrafts
- A Special Interest Group (SIG)
- Wiki pages prefixed with 'Packaging'
Miscellaneous hints
Try to write your scripts so that when upstream makes changes, the packaging is likely to work when you change the version number and reload the source file(s). For example, if it contains *.txt files with execute bits, instead of doing:
chmod a-x Filename1.txt Filename2.txt Filename3.txt
consider doing this, which will handle new filenames that use the same file naming convention:
chmod a-x *.txt
If you want to see lots of examples of scriptlets, you can show all the scriptlets on installed programs using:
rpm -qa --queryformat "\n\nPACKAGE: %{name}\n" --scripts | less
Packaging/FrequentlyMadeMistakes has information on frequently-made mistakes.
Don't try to interact with the user; RPM is designed to support batch installs. If an application needs to show a EULA, that needs to be part of its initial execution, not its installation.
You might not want to start services, because in a big install that could slow things down. If you install an init script, consider using chkconfig to arrange for the service to be started and stopped on the next reboot. Before uninstalling you should normally try to stop its services if it's running.
Uninstall should reverse most changes made during installation, but don't remove any user-created files.
Normally, if there are binary executables, a separate "debug" package is created with the symbols, and the symbols are stripped from the normal binary packages. If this shouldn't happen, you can disable the package-creation and stripping with:
%global _enable_debug_package 0 %global debug_package %{nil} %global __os_install_post /usr/lib/rpm/brp-compress %{nil}
To prevent stripping you may also need to do this in the %install section:
export DONT_STRIP=1
A way to check for the version of Fedora in a spec file for conditional builds is:
%if 0%{?fedora} <= <version>
(The ? causes the macro to evaluate to blank if %fedora is not defined, and this causes the end result to be "0", which is a number and thus ok, while not interfering with the result if there is actually a value for %fedora.)
Note that the previous trick DOES NOT work in Koji "scratch" builds - %fedora is set during the creation of a source RPM. (Thus, this trick does work in actual Koji builds as the system extracts sources from the source RPM and rebuilds the source RPM with the appropriate %fedora value.)
There are also some recommendations and controversial tricks on PackageMaintainers/Packaging Tricks.
GUI programs must have a desktop entry (so that people can invoke it from a graphical menu). The Fedora packaging guidelines discuss desktop files. See also the desktop entry spec (for .desktop files) and icon theme spec (for icon-related materials such as those in /usr/share/icon).
Older RPM documents
Some older documents about RPM have the most information, but some older documents make claims that are no longer true:
- rpm files are no longer placed in a shared /usr/src/redhat directory. This is an obsolete way of using rpm and not recommended; modern systems set a %{_topdir} instead like ~/rpmbuild.
- the %install process does not install files in their final location. Instead, it "installs" files to the buildroot.
- The "rpm" command no longer creates packages (e.g., "rpm -ba" was once legal). Use the separate "rpmbuild" program instead.
- Many historical specs use the "%define" command to define macros. However, "%define" creates a locally defined submacro within other macro definitions; this is very rarely needed, and using %define incorrectly can cause subtle bugs. For nearly all uses, use "%global" instead. (See PackagingDrafts/global_preferred_over_define.)
- The "BuildRoot:" value is now ignored.
Test veloce con rpmlint
Prima di provare a costruire qualsiasi cosa da esso, si dovrebbe eseguire rpmlint sullo spec file:
$ rpmlint program.spec
Troverà molti errori velocemente. Se l'errore riportato non ha molto senso, ridare lo stesso comando aggiungendo l'opzione "-i" (questo darà maggiori informazioni).
Generalmente non si dovrebbero avere errori con rpmlint, ma talvolta è eccessivamente "esplicativo". Le linee guida Fedora packaging spiega quali sono da ignorare, ad esempio gli errori "no-packager-tag" e "no-signature".
Creazione degli RPM dallo spec file
Una volta creato uno spec file, chiamato program.spec, è possibile creare l'rpm sorgente e l'rpm binario semplicemente avviando:
$ rpmbuild -ba program.spec
Se funziona, i file binari RPM verranno creati nella sottocartella ~/rpmbuild/RPMS/ e l'RPM sorgente in ~/rpmbuild/SRPMS.
Quando qualcosa va male, è possibile entrare ("cd") nella directory appropriata e vedere cosa contiene. Se si vogliono saltare i passaggi precedenti, usare l'opzione "--short-circuit"; è utile quando si è avuto un build con successo, ma si ha un errore nella sezione %install. Ad esempio, per reiniziare lo stage %install (saltando i passaggi precedenti):
$ rpmbuild -bi --short-circuit program.spec
Se si vuole creare l'rpm sorgente (.src.rpm), entrare nella cartella SPECS e:
$ rpmbuild -bs program.spec
Verrà creato l'rpm sorgente nella cartella ~/rpmbuild/SRPMS. Creare solo l'rpm sorgente è abbastanza veloce, poiché non fa altro che associare lo .spec file e i file SOURCES nel .src.rpm . Creare un rpm binario tipicamente prende più tempo perché richiede l'avvìo degli script %prep, %build e %install.
Testare gli RPM creati (includendo rpmlint)
Avviato rpmlint sullo spec file, generato l'RPM binario e generato l'RPM sorgente. rpmlint lavora sugli spec, sugli rpm binari o sorgente, trovando cose differenti in ognuno. E' necessario eliminare o modificare degli "rpmlint warning" prima di rilasciare un pacchetto. Dalla cartella SPECS:
$ rpmlint NAME.spec ../RPMS/*/NAME*.rpm ../SRPMS/NAME*.rpm
Generalmente rpmbuild costruisce rpm binari con informazioni di debug, anche questi possono essere sottoposti al test.
Spostandosi nella cartella "~/rpmbuild/RPMS" poi nella sottocartella denominata dall'architettura (32 o 64 bit) si troveranno alcuni rpm binari. E' possibile vederne facilmente i file ed i permessi con rpmls (assicurarsi di trovare ciò che ci si aspetta):
$ rpmls *.rpm
Se corretti, provare ad installarli diventando root:
$ su # rpm -ivp XYZ1.rpm XYZ2.rpm XYZ3.rpm ...
Per poi testarli, utilizzandoli in differenti modi. Se si decide di usare uno strumento ad interfaccia grafica (GUI), assicurarsi che venga mostrato nel menu (se non lo è, allora qualcosa è sbagliato alla voce .desktop).
Successivamente è possibile disinstallarli:
# rpm -e XYZ1 XYZ2 XYZ3
Se tutto funziona, si possono fare ulteriori accurati test sul rispetto delle dipendenze usando Mock. Semplicemente, Mock creerà un ambiente quasi vuoto e cercherà di ricostruire il pacchetto; se fallisce, probabilmente ci si è dimenticato di aggiungere qualcosa alla voce "BuildRequires:". Vedere Using Mock to test package builds per ulteriori info sull'utilizzo di Mock; una volta che il proprio account rientra nel gruppo "mock", è possibile avviare comandi come il seguente per eseguire test in locale:
$ mock -r fedora-9-i386 rebuild path_to_source_RPM
Se la costruzione con mock fallisce o il programma risultante non funziona correttamente, quasi certamente mancano pacchetti alla voce BuildRequires.
Una volta che Mock ha funzionato correttamente, si può usare Koji (il quale usa Mock) per costruire in differenti sistemi alcuni dei quali non si può avere. PackageMaintainers/Join e PackageMaintainers/UsingKoji hanno molte informazioni su Koji. Una volta settati, si possono eseguire test sul proprio rpm sorgente con differenti sistemi
$ koji build --scratch dist-f9 path_to_source_RPM
Si può sostituire la voce "dist-f9" con dist-f8, dist-f10, ... per provare altre release. Non usare "dist-rawhide", perché non è la reale rawhide. Ricordarsi che i valori di %fedora, %fc9, ... non saranno giusti per una scratch build, quindi non funzioneranno se il proprio .spec file fa qualcosa di diverso basato su quei valori. I build koji possono solo dipendere dai pacchetti che sono attualmente disponibili nei repository TARGET. Quindi non si può usare Koji per costruire per distribuzioni rilasciate se il proprio pacchetto dipende da altri nuovi pacchetti che Bodhi non ha ancora rilasciato. E' possibile usare Koji per build rawhide (cioé per distro non ancora rilasciate) anche se dipende da altri nuovi pacchetti, finché gli altri pacchetti in questione sono costruiti nella sezione CVS "sviluppo" come descritto in seguito. Se si vuole costruire un pacchetto che non è ancora una versione aggiornata stabile, si può aprire un ticket con rel-eng a https://fedorahosted.org/rel-eng/newticket e chiedere che il pacchetto venga aggiunto come buildroot override.
Strumenti utili
Il pacchetto "rpmdevtools" fornisce diversi strumenti utili; "rpm -qil rpmdevtools" mostra ciò che verrà installato. Uno particolarmente utile è rpmdev-bumpspec, che ha questa forma:
$ rpmdev-bumpspec --comment=COMMENT --userstring=NAME+EMAIL_STRING SPECFILES
rpmdev-bumpspec inserirà il tag "versione" nello .spec file, aggiungendo un commento alla lista dei cambiamenti (changelog) con la data e la versione corretta. COMMENT dovrebbe iniziare tipicamente con "-".
Allo stesso modo, "yum-utils" contiene molti strumenti per Yum. "Yumdownloader" è particolarmente utile; si può scaricare l'rpm sorgente semplicemente con "yumdownloader --source PACKAGENAME", per poi usare "rpm -U SOURCEPACKAGENAME" per installare i file sorgente. Ad esempio, "yumdownloader --source glib; rpm -Uvh glib*.src.rpm".
Il pacchetto auto-buildrequires ha un paio di buoni strumenti d'aiuto per configurare correttamente la voce BuildRequires. Dopo averlo installato, rimpiazzare "rpmbuild" con "auto-br-rpmbuild" e si vedrà automaticamente generata la lista buildrequires.
Potrebbe essere utile RUST (GPL).
E' un "drag&drop GUI e 'sandboxing' toolkit per la creazione di RPM che permette l'installazione di software in un sistema chroot e di generare RPM da codice sorgente arbitrario senza aver mai visto uno spec file".
Se si sta creando uno .spec file, è di aiuto per determinarne il %files.
Da notare, comunque, che non crea lo .spec file e non crea rpm di adeguata qualità per i repository Fedora; è principalmente uno strumento per la creazione "sbrigativa" di pacchetti RPM binari.
(Non è più in "rusthq.com".)
Alien converte pacchetti di diverso formato. Non produce rpm sorgente puliti ma potrebbe essere utile per la conversione di pacchetti esistenti dai quali trarre informazioni preziose.
Linee guida e regole
Una volta creato il proprio pacchetto, bisogna seguire queste regole e linee guida:
- How to join the Fedora Package Collection Maintainers - Descrive il processo per diventare Fedora package maintainer
- Packaging Guidelines
- Package Naming Guidelines
- Dist Tag Guidelines
- Package Review Guidelines
Ci sono molte linee guida ufficiali che possono essere d'aiuto in circostanze particolari (Java programs, OCaml programs, GNOME programs, etc.); le Packaging Guidelines includono riferimenti incrociati a queste linee guida. Si può inoltre imparare molto dalle sezioni SIGs e Package Maintainers. Lista delle pagine wiki sul Packaging per vedere se qualcuno si applica.
Se non servono, si potrebbero trovare utili quelle non ufficiali Packaging Drafts e Packaging Drafts To Do. Queste non sono ufficiali ovviamente.
Si potrebbero trovare idee da SuSE, Debian, ma distributions differ in their rules presume che non possano essere usate direttamente.
Gli .spec file devono essere opensource, come annotato nella CLA.
Mantenimento del pacchetto
Quando il pacchetto viene accettato, dev'essere mantenuto dal maintainer (o dal co-maintainer). Vedere Package update HOWTO e Package update guidelines per maggiori informazioni. Se si aggiorna a più di una release Fedora, farlo a ritroso nel tempo; ad esempio, release per Fedora N, una volta accettato, Fedora N -1 ( il sistema presuppone che versioni successive di Fedora hanno versioni uguali o più aggiornate dei programmi).
Incoraggiare gli sviluppatori upstream ad usare convenzioni stardard nel rilascio del codice sorgente; questo renderà più facile il packaging del software. Per maggiori informazioni, vedere:
- Releasing Free/Libre/Open Source Software (FLOSS) for Source Installation (sommario veloce)
- GNU Coding Standards release process
- Software Release Practice HOWTO
- Filesystem Hierarchy Standard (FHS)
- Packaging Unix software
Per maggiori informazioni
La pagina Package Maintainers è collegata a molte altre pagine utili e Package update HOWTO descrive come aggiornare un pacchetto esistente già mantenuto in Fedora.
Per maggiori informazioni, fuori dal wiki Fedora, vedere:
- How to build RPM packages on Fedora - ripasso veloce
- Packaging software con RPM (developerWorks) Part 1, Part 2 e Part 3
- Fedora Classroom ha avuto una sessione IRC sul packaging e si può far riferimento al log su https://fedoraproject.org/wiki/Building_RPM_packages_%2820090405%29
- Manuale Fedora Packager
- When Sally met Eddie - Un semplice testo con pochi dettagli
- Maximum RPM Book - Molte informazioni complete, ma in alcuni casi obsolete
- RPM Guide, section on creating RPMs - Ha parecchie buone informazioni leggermente più aggiornate, ma è una bozza
- Guida per sviluppatori, sezione building RPM
- Creating RPMS slides da Guru Labs
- La lotta, il mio primo tentativo di fare un'introduzione leggibile sull'rpm building.
- RPM Tutorial (Fullhart)
- Cambridge RPM tutorial è una presentazione sulla creazione basilare degli RPM
- [1] RPM HOWTO: RPM al Minimo di Donnie Barnes
- [2] RPM HowTo di Dawson
- SuSE build tutorial - ma su SuSE, non per Fedora. Cross-distribution package HOWTO contiene suggerimenti se si fanno rpm per diverse distribuzioni.
- Mandriva Rpm HowTo (en) (alt) è un tutorial RPM anche se per Mandriva. Da notare che in Fedora non si ricomprimono i tarball originali, come Mandriva suggerisce, perché questo avrebbe cambiato le loro hash crittografate.
- Creazione del proprio Linux RPM - Software Building Iniziale è un'altra introduzione ma fa il punto su "Il processo per costruire RPM è più facile della creazione dei pacchetti per Solaris... Meno passaggi, e l'abilità di aggiungere tutte le informazioni sul software in uno specifico file, fatti per una maggiore essenzialità (più facile da modificare e riprodurre) del sistema di packaging".
- Tutto ciò da sapere sul RPM (più sull'installazione che sulla creazione)
- The rpm.org Wiki ha alcune informazioni utili, come la lista dei problemi conosciuti
Da notare: il sito rpm5.org ha alcuni documenti ma non dipende da loro; è la casa di un fork di RPM mantenuto da Jeff Johnson. L'RPM usato da Fedora (e da Novell/SuSE) ha invece la sede in rpm.org.
lwn.net contiene un articolo a riguardo.