From Mageia wiki
Jump to: navigation, search


Drakconf multiflag.png
Other languages
English ; Français
Synopsis:
This tutorial is aimed at helping people who wish to build software packages that integrate well in the Mageia distribution. In particular, it will stress in what way the packages differ from the packages anyone would build for other rpm-based distributions. This document is intended to be particularly useful to Mageia developers and other parties interested in packaging for Mageia.

Mageia is produced by a large number of contributors, testers, and translators. For more information on this, please have a look at the page on contributing.

Warning!
Building RPMs as root is dangerous because the binary files are installed on the system before being packaged, therefore you must always build as normal user so you won't accidentally corrupt your system. Install the colorprompt package if you want a red root prompt.

Foreword

It is assumed in this document that the reader is "linux-ready". He/she already knows the basic commands, directory structure and has already used rpm, at least for installing packages.

This document is constructed as a step-by-step recipe to create an rpm package, that can integrate well into Mageia, from either a previous source rpm or from a tar source.

RPM roughly means three things:

  • a program intended to install or create packages
  • a format used in packages (source or binary) created by the program rpm
  • a file called package which contains either a binary or sources along with an information header about how to install/uninstall the program

The program rpm is, from the user's point of view, a powerful package manager. It acts as a "conductor" for any action on RPM packages. Amongst other things, it can:

  • install or upgrade a package and verify dependencies
  • while installing a package, perform actions in order to make the installed program ready to use
  • restore accidentally erased files belonging to a package
  • check if a package is already installed
  • find to which package a particular file belongs
  • verify the current installation as to the fulfilment of dependency requirements of installed packages
  • ....

From the programmer's point of view, the rpm program is a packager which encapsulates, in a single rpm file, all the information needed to install a program on a given platform.

It is important to distinguish, from the beginning, the difference between source (.src.rpm) and binary (.<archtype>.rpm) packages.

The first one contains (yes you guessed) the complete source tree from the original programmer, plus all the stuff the packager added in order to configure, compile and install the program. It generally consists of a spec file (the file used to instruct rpm which operations it has to perform, in order to create the package) along with patches, if any.

The second one contains the compiled binary, and all the files (documentation, config files, icons...) that will be installed on the target system. It also contains the procedure used to place the files in their correct location and the actions to perform in order to make the program operable.

Install the software

The basics

Although RPM was originally designed to work with Red Hat Linux, "Red Hat Package Manager", hence "RPM", it also works on other rpm-based distributions: OpenMandriva, Qubes OS, Suse, etc ; rpm is already installed on these systems.


The binary rpm you will build for Mageia may not work across the distributions, although Mageia does everything possible to stay compatible with Red Hat.

Building for Mageia

Building packages for Cauldron (the development version of Mageia) is always subject to small patches and enhancements to the rpm program in use. You should install the following packages:

  • rpm: our patched version of Red Hat's
  • rpm-build: scripts used to build packages
  • spec-helper: a tool to minimalize the specfiles by doing automatic things such as stripping the binaries and compressing the man pages
  • libtool: used by some configure scripts to build shared libraries
  • rpmlint: used to check the validity of the generated rpm

Preliminary tasks

Install required package

In order to be able to build RPMs, you must have the rpm-build package installed.

Create required folders

To build packages, rpm needs a special tree in your home directory. This tree can be created with the following command:

mkdir -p ~/rpmbuild/{SRPMS,SOURCES,SPECS,tmp}

Later, when installing a source-package (.src.rpm) or building a package, some more directories will be created resulting in this structure:

Warning!
It is dangerous to build RPMs as root, since the binaries are installed on the system before being packaged. Therefore, you should always build your RPMs as a normal user so that you never accidentally pollute your system.

Make sure that the tree structure is of the form:

  • ~/rpmbuild/BUILD: The directory where the sources are built.
  • ~/rpmbuild/BUILDROOT: The directory where the installation will be simulated
  • ~/rpmbuild/RPMS: Contains the directories, one for each architecture, that will receive the binary packages after.
  • ~/rpmbuild/RPMS/i586: The directory where rpm packages for i586 processors will be stored.
  • ~/rpmbuild/RPMS/x86_64: The directory where rpm packages for AMD64 processors/Core 2 duo and later will be stored.
  • ~/rpmbuild/RPMS/noarch: Idem for noarch (processor-independant) packages.
  • ~/rpmbuild/SOURCES: The source files (mypackage.tar.bz2 for example).
  • ~/rpmbuild/SPECS: The spec files we will have to construct.
  • ~/rpmbuild/SRPMS: The source rpm after building.
  • ~/rpmbuild/tmp: For temporary stuff that rpm will create when building your packages, you can find the scripts which are generated to actually build and package your package here, they are generated from the spec file and can be handy for debugging.
Note:
The architecture files under ~/rpmbuild/RPMS are essential. If they are missing, an error message will be displayed.

.rpmmacros file creation

In order to build packages for Mageia, you will need to add the .rpmmacros configuration file into your home directory:

# rpm build settings # directory overrides %_topdir %(echo $HOME)/rpmbuild/ %_tmppath %(echo $HOME)/rpmbuild/tmp # package signature add automatically (name as assigned, for example, by GnuPG) # packages can be signed later with `rpm --resign` %_signature gpg %_gpg_name John Doe %_gpg_path ~/.gnupg # packager, distributor, and vendor override # for vendor consider using personal name %packager John Doe <foo@example.com> #%distribution Mageia #%vendor Mageia.Org # distribution name suffix override, if your package is intented for usage outside official repositories # %distsuffix .mypack # %dist %distsuffix%distro_release # distribution name override #%dis mageia # Allow source download. If source is not yet present, it will be downloaded locally. # %_disable_source_fetch %nil # Allow usage of all cores during compression step of the package # w9 is the compression level # zstdio is the format of compression # %_binary_payload w9T%{_smp_build_nthreads}.zstdio
Note:
Using "mga" as distuffix for packages that aren't built by Mageia's build system, makes life for BugSquad and QA team harder. This is a good practice to change it

Building an RPM package

From a source package

This is generally the case for the packages which are already included in the distribution.

The latest rpm files from Cauldron are available on many mirrors whose list is available at Cauldron Mirrors. There you will find under:

  • SRPMS for source rpms (core, nonfree, tainted) and under the cpu architecture (e.g. i586, x86_64, ...):
  • media/core for core binary rpms.
  • media/nonfree for non-free binary rpms.
  • media/tainted for tainted binary rpms.

When you find the source rpm you want to modify for Mageia, just issue rpm -ivh mypackage.src.rpm; it will install all source files into your RPM directory. You can also setup urpmi to download the source.

For example:

[camille@valstar ~/rpmbuild]$ rpm -i /cauldron/SRPMS/core/ktron-4.5.95-1.mga1.src.rpm [camille@valstar ~/rpmbuild]$ ls -R * SRPMS: SPECS: ktron.spec SOURCES: ktron-4.5.95.tar.bz2 RPMS: noarch/ i686/ i586/ i386/ BUILD:

We see that rpm has installed in our RPM tree the source file ktron-4.5.95.tar.bz2 and the spec file. Even before building a newer version of a package, it might be very interesting for you to rebuild the current package in order to understand how it is compiled and if it compiles. The magic command for doing this is rpmbuild with the option buildall:

[camille@valstar ~/rpmbuild]$ cd ~/rpmbuild/SPECS [camille@valstar ~/rpmbuild]$ rpmbuild -ba ktron.spec [camille@valstar ~/rpmbuild]$ ls -l ~/rpmbuild/RPMS/i586/ktron-4.5.95-1.mga1.i586.rpm [camille@valstar ~/rpmbuild]$ ls -l ~/rpmbuild/SRPMS/ktron-4.5.95-1.mga1.src.rpm

If the build finished (it can last hours for some packages like kernels) without errors, you will obtain the binary rpm and the src rpm in your ~/rpmbuild/RPMS/i586 and ~/rpmbuild/SRPMS/ subdirectories respectively. If you want to install the binary rpm, you must act as 'root' which you can achieve by typing su (and exit by typing exit). But when building an rpm, and expanding a src.rpm, you should never be root.

The log of the build might be very long and can be stored for later browsing. I am using emacs or xemacs and use a second window with a shell (Alt-x shell) and save the buffer as ktron.LOG, for example, when finished.

In the ~/rpmbuild/BUILD sub-directories you will usually have access to the patched sources (if one or more patches were given in ~/rpmbuild/SOURCES), to the binaries, compiled libraries, man pages etc. The spec file describes the source and patch files, how to build the package and how to install the package.

Now all we need to do, in this case of improving ktron, is to modify the spec file and then rebuild the package.

It is important to note that each package maintained at Mageia is stored on an SVN system. This allows every state of a package to be recorded by the system, so that the developer may consult the archive to check previous modifications and if necessary revert to an older release version.

Each spec file is stored in the package tree <svn/packages/cauldron>. You can access it on http://svn.mageia.org/

For details on how to access the SVN system, consult the Mageia SVN howto.

Last but not least, the BUILDROOT directory is where the package gets installed before being encapsulated in binary RPMS. This directory is usually empty if the build succeeds, but is not when the build fails. It can be interesting to see what went wrong: for instance, files installed in a wrong directory due to a typo for a macro that expands to a path in the spec file

From raw (tarball) sources

For example, if you find an interesting program at Sourceforge that warns you when the tea is ready, you may want to make it available to all Mageia English tea drinkers. Probably the best way to do that is to set up an RPM for it that conforms to Mageia's standards.

Download the tarball and place it in the SOURCES directory.


Preliminary checks

  • License: Despite the prevalence of GPL licenses, there are still a number of non-GPL licenses in use today. Check the license of the software carefully to determine whether or not it may be incorporated in the distribution and in which repository: core (free licenses), nonfree (non-free licenses) or tainted (patent issues inside). We cannot accept software that does not allow us to freely distribute it. Watch out for these programs. A list of licenses and acceptable software may be found on Mageia license page
  • Tarball Compression: to save efforts to maintenance in the future, it is recommended to use the original tarball without any modifications. If sources are provided in various compression methods, we often choose .tar.bz2, or a better compression algorithm, like tar.xz. Avoid compressing text format patches (as produced by diff and the likes) and other configuration/scripts/etc. (text) files, as it usually saves very little space, while making harder to see the changes in Subversion diffs (and Subversion also already uses some form of compression).
Note:
For high-risk security-critical packages we recommend that you don't modify the original source distribution, as it will change the checksum/signature. For this kind of packages we recommend that you leave it in the original form, so that when someone runs md5sum/gpg on it, it will match the values as listed at the download location. One such example where this exception may apply would be OpenSSH.

Inside the spec file

Here we are. This is the most important section of this document. The spec file contains all the information needed by rpm to:

  • compile the program and build source and binary rpms,
  • install and uninstall the program on the final user's machine.

The fact that these two types of information are combined into one single file may be quite confusing for the beginner. Actually, this is due to the source tar tree, which contains already this information. As installation procedure is extracted from the installation process generally run by make install into the source tree, both parts are tightly linked.

In a nutshell, the spec file describes a "simulated" compilation and installation, tells rpm which files resulting from this installation are to be packed, and how to finally install these files onto the user's system. Commands there are executed using the /bin/sh shell, so things like [ -f configure.in ] && autoconf are valid.

This part is not intended to explain in detail all the features of a spec file. The book Maximum RPM (see Section 7) explains it in depth. All we are going to do here is quickly check all of the features used in one standard example Mageia spec file.

As you build more and more RPMs, you will find that there are some options that we have not told you about. RPM is extremely extensible, so, finding out all of those is left as an exercise to the reader. It is always a good practice to open up some spec files to take a look at them and see how they work.

You can get some more specs and patches here.

Name: gif2png Version: 2.0.1 Release: %mkrel 1 Summary: Tools for converting websites from using GIFs to using PNGs Source0: http://www.tuxedo.org/~esr/gif2png/%{name}-%{version}.tar.bz2 Source1: %{name}-%{version}-mga-addon.tar.bz2 Patch0: gif2png-2.0.1-bugfix.patch URL: http://www.tuxedo.org/~esr/gif2png/ Group: Applications/Multimedia License: MIT-like Requires: python %description Tools for converting GIFs to PNGs. The program gif2png converts GIF files to PNG files. The Python script web2png converts an entire web tree, also patching HTML pages to keep IMG SRC references correct. %prep %setup -q -a 1 %patch -p1 %build %configure %make_build %install rm -rf %{buildroot} %make_install %files %defattr(0755,root,root) %doc README NEWS COPYING AUTHORS %{_mandir}/man1/gif2png.1* %{_mandir}/man1/web2png.1* %{_bindir}/gif2png %{_bindir}/web2png %changelog * Mon Nov 02 2010 Camille Begnis <camille@mageia.org> 2.0.1-1.mga1 - Upgraded to 2.0.1 * Mon Oct 25 2011 Camille Begnis <camille@mageia.org> 2.0.0-1.mga1 - Specfile adaptations for Mageia - add python requirement - gz to bz2 compression

Let's then analyze in detail each line of this file:

Be careful, a % at the beginning of a line may tell different things :

  • the beginning of a section (prep, build, install, clean)
  • a built-in shell script macro (setup, patch)
  • a directive used by a special section (defattr, doc, ...)

Header section

Name: gif2png

The name of the package as used in the package's name and in the package database on the user's machine. As best practice the name should always be lowercase.

Note that the "%{name} " is a reference to the previous define.

Version: 2.0.1 Release: %mkrel 1

At this point, we must explain how the name of a package is formed. It is important to always respect this standard in order to make your work understandable to others.

There are also some tags that you might want to know about, but which are not in the spec file example. There are some that you might encounter. It is not expected that you remember all of this if you just started building rpms, but after some time, this list makes good reference!

  • A binary package is named as: name-version-release.arch.rpm (i.e. gif2png-2.0.1-1.mga1.i586.rpm and gif2png-2.0.1-1.mga1.x86_64.rpm in our example, for 32bit and 64bit architectures respectively)
  • A source package is named as: name-version-release.src.rpm (i.e. gif2png-2.0.1-1.mga1.src.rpm in our example)

The name is generally chosen to be the name of the main binary of the package, though with adequate reasons you can get away with another name.

The version is the number from the unpatched sources. It is the version number in the name of the original archive file: name-version.tar.gz.

The release is a number followed by mga1 (stands for "Mageia 1"; this is absolutely mandatory) which is incremented at each new build of the package. This may be due to a patch applied to the sources, a modification to the spec file, the addition of an icon, etc.

Summary: Tools for converting websites from using GIFs to using PNGs

This line is a one-liner of the package description. It should be max. 79 characters, no dot at the end, the first character uppercased and no space as the first character.

Source0: http://www.tuxedo.org/~esr/gif2png/%{name}-%{version}.tar.bz2

This line tells rpm what source file to use for building this package. Note that the file name is preceded by a complete URL (which is optional) pointing to the site where the original source tarball is available; rpm will remove the url, and search in the SOURCES directory for the tarball file name. Although we say that the complete URL is optional, it is highly recommended so people will know where to find new sources should they take a liking to upgrading the source and do a recompilation. This will allow tools like rpmbuildupdate to automatically rebuild new versions (see rpmbuildupdate for more info TODO).

When there is more than one source file, use other lines with Source1: ..., then Source2: ..., etc.

Note that the "%{name}" and "%{version}" are references to the previous Tags.

Patch0: gif2png-2.0.1-bugfix.patch

Two reasons for this optional tag:

  • You fixed a bug on the program sources. So you generated a patch file to be applied to the sources before compilation.
  • You've been notified of the existence of a patch for the software version included in this particular package somewhere on the net and downloaded it, or you cherry-picked it from upstream (from SVN, GIT.. etc)
Note:
The patch file must be placed in the SOURCES directory; as for the sources, there can be several patches, they will be named Patch1, Patch2, etc.
URL: http://www.tuxedo.org/~esr/gif2png/

This line (optional but highly recommended) points to the home page of the program.

Group: Multimedia

This is to tell rpm in which part of the general package tree to place this package. This feature is used with package manager front-ends such as rpmdrake.

The complete group structure to use, which is different from the one Red Hat uses, can be found on the page RPM groups policy. It must be followed, otherwise your package will mess with the other ones, in the package tree selection of the Mageia installer, or in package manager front-ends.

License: MIT-like

This tag (superseding Copyright) defines the license chosen by the copyright holder that will apply to the software being packed. In most cases it is GPLv2. See the Mageia Licensing Policy, particularly the section Standard license names for a complete list of valid licenses and rules.

Requires: python

This line was added because one of the programs included in the package is a python script. It then needs python to be executed. You can use optionally a minimum (or equal) version, for example: Requires: python >= 1.5.1

%description Tools for converting GIFs to PNGs. The program gif2png converts GIF files to PNG files. The Python script web2png converts an entire web tree, also patching HTML pages to keep IMG SRC references correct.

This is a quite special tag inside the header of the spec file, because it is a complete text made up of various lines and paragraphs, if needed. It contains the full description of the software being installed in order to help the user decide whether a particular package is useful for him or not. You are encouraged to reuse the description upstream gives in either a README file included in the archive, or on its homepage...etc.

You may be asking yourself at this point: "And what about translations?" Actually, to improve readability of spec files, translations of summary and description tags are stored in a special file called <package>.po.

TODO: Specfiles translations

Prep section

%prep %setup -q -a 1 %patch0 -p1

This is the first script in this section, being executed by rpm. Its role is to:

  • create the top-level build directory (into BUILD),
  • unpack the original sources into the build directory,
  • apply optional patches to the sources.

It may then be followed by any command the packager wants in order to get the sources into a ready-to-build state.

%setup -q -a 1

This is a built-in script macro which

  • cd's into the build tree,
  • extracts the source(s) (quietly, -q)
  • changes ownership and permissions of source files.

By default it extracts the first source (Source0 in our example); you have to use parameters for any other sources (archives), in our example -a 1 tells rpmbuild that we also want to extract the second source archive (Source1 in our example).

There are other interesting/useful switches which can be used with %setup macro:

  • -c name - The switch -c tells rpmbuild to create the upper directory first; then cd into this directory and then unpack Source0. This is useful if an archive is extracted without a parent directory.
  • -D - does not delete the directory before unpacking. This is only useful if you have more than one setup macro. It should only be used in setup macros after the first one (but never in the first one).
  • -T - this option overrides the default action of unpacking (untarring) the Source and requires a -b 0 or -a 0 to get the main source file untarred. You need this when there are secondary sources.
  • -n name - if the name of the rpm is something other than what the Source unpacks to, use this switch. For example: if the rpm name is program-version-revision and the Source unpacks to the program-version-date, the rpm build process will not be able to cd into the directory program-version, so use -n program-version-date, so rpm will know the new directory in which to continue.
%patch0 -p1

The macro responsible for applying the patch to the sources; its parameter "-p<num>" is used to determine how many directories of the patch should be stripped.If you look into a patch file you’ll see that some paths are defined:

--- cairo-1.7.6-orig/src/cairo-ft-font.c 2008-09-29 21:43:13.000000000 +0100 +++ cairo-1.7.6/src/cairo-ft-font.c 2008-09-29 21:52:19.000000000 +0100 @@ -1705,7 +1705,9 @@ options->base.subpixel_order = other->base.subpixel_order; } - if (options->base.hint_style == CAIRO_HINT_STYLE_DEFAULT) + options->base.hint_style = CAIRO_HINT_STYLE_DEFAULT; + + if (other->base.hint_style != CAIRO_HINT_STYLE_DEFAULT) options->base.hint_style = other->base.hint_style; if (other->base.hint_style == CAIRO_HINT_STYLE_NONE)

In that case, -p1 means that patch should ignore cairo-1.7.6/, -p2 would mean it should also ignore src/ and so on…

Imagine if you had another patch declared as Patch1: .. in the header section, you would add another line: %patch1 -p1. Adding a -b .your_suffix would also be nice, as it lets you quickly see what each patch does, e.g. %patch1 -p1 -b .fix-makefile this is useful when debugging a build, as you can enable/disable patches quickly without having to scroll all the way up to the Header section in the spec to see the patch name.

Build section

%build

This section will contain the script responsible for the actual build of the software.

It consists of the commands being issued when building a package from an untarred source tree.

%configure

This is the line used for configuring autoconf'ed sources. %configure issues a ./configure with many add-ons and standard configure options such as export CFLAGS="$RPM_OPT_FLAGS" before running configure, and options such as i586-mageia-linux --prefix=/usr --datadir=/usr/share etc.

Sometimes these arguments are not supported by the configure script. In such cases, you have to discover the reason, and issue the ./configure with the appropriate parameters. Give the target platform to the configure call, if supported, with %{targetplatform} ; of course, specification of an architecture must be avoided in spec files; on ix86, this will expand to i586-mageia, as shown in the example above.

For an overview of what rpm actually does when you issue %configure, you can execute rpm --eval %configure in a terminal.

You will need the libtool package to use %configure with packages building shared libraries.

When building, and when testing your package, you should verify that the target host is actually an i586 ; in particular, when compiling on a higher processor type, the default behaviour of the configure script is to discover your processor, and optimize for it. One of the purposes of the %configure macro is to avoid this behaviour.

%%make_build

This is a simple macro that basically executes make with the appropriate multiprocessor parameter -j<num>.

For sources using xmkmf, you should replace the next make with:

make CDEBUGFLAGS="$RPM_OPT_FLAGS" CXXDEBUGFLAGS="$RPM_OPT_FLAGS"

For other packages, in many (but not all) cases a simple make should work.

Install section

%install

This section will contain the script responsible for actually installing the package in the simulated installation directory: %{buildroot}, or the equivalent $RPM_BUILD_ROOT.

It will contain all the commands necessary to make the software ready to run on the user's system.

rm -rf %{buildroot}

This is the first of the commands being executed in the %install section; it cleans up a possible previous install directory. This line is obsolete and this will be automatically done by RPM itself. It should be removed from SPECs and not used anymore.

%makeinstall

This line finally installs the software into the simulation installation directory for autoconf'ed sources. The macro expands to make DESTDIR=%{buildroot} install, as seen with rpm --eval %make_install, which then follows the configure information passed in by the configure macro used earlier.

In some cases the configure script will be partially broken and you may need to lurk in the Makefiles to guess the additional parameters to have it install correctly. In these cases, you usually use %makeinstall. This macro will expand to make install with many options in order to install the software in the %{buildroot}, e.g. prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir}. Again to see what this macro is expanded to, use rpm --eval %makeinstall. You can find a list of commonly used variables for Makefiles on the Coding Standard page

To save both disk space and download time, Mageia uses xz to compress man- and info-pages. However, this aspect is handled directly by the Mageia custom rpm program.

All this stuff is to prepare the files to be ready to be packed.

Clean section

%clean

This section is meant to clean the build directory tree, $RPM_BUILD_ROOT.

rm -rf %{buildroot}

This is where the job is done.

This section is obsolete and this will be automatically done by RPM itself. It should be removed from SPECs and not used anymore.

Files section

%files

This section consists of a list of files that will be picked from our simulation directory tree to be packed into the package. See the fine manual for the different options not being used in that simple example.

The file list must be written by hand in the spec file. It may be constructed by listing all files created by rpm in the build directory tree. In order to do that, issue a rpmbuild -bi mypackage.spec in order to stop the building process just after the simulated installation. Then, look in the simulated installation directory, ~/rpmbuild/BUILDROOT/gif2png in our case, to see which files you want to put in your package (most of the time, you will put them all in).

Note:
You should never use find to build a list of files to include, but explicitly list all files (this may exhibit bugs in newer versions). The only exceptions are for locales for which you should use %find_lang %{name} in the %install section and replace %files by %files -f %{name}.lang.
Note:
About directory structure : The files being installed by your package "should" follow the FHS recommendations at Filesystem Hierarchy Standard.
%defattr(-,root,root)

This tag defines the attributes to be applied to each file being copied to the user's system. The four arguments given mean:

  • -: all the attributes for regular files remain unchanged,
  • root: the owner of the file is root,
  • root: the group of the file is root,
  • 0755: the attributes applied to all directories owned by this package are 0755 ( rwxr-xr-x ).

 %defattr(-,root,root) is useless and should be removed where seen: only use %defattr if you really want to change the default permissions from upstream of all files following after the %defattr macro. This is rarely needed

%doc README NEWS COPYING AUTHORS

The special tag %doc designates files being part of the documentation of the package. The said files will be placed in /usr/share/doc/gif2png-2.0.1/. This directory will be also automatically created. Files specified by %doc are relative to your untarred source directory in BUILD.

%{_mandir}/man1/gif2png.1* %{_mandir}/man1/web2png.1*

It is recommended to list here also each man or info file separately.

Also, you may wonder why gif2png.1* was used instead of gif2png.1.xz. This is done to preserve compatibility with other systems that could use gzip compression instead of xz. If you find such references to xz compression in spec files, change them to a wildcard (*). Most of the time you can even use %{_mandir}/man1/*, this will take all the files it can find.

%{_bindir}/gif2png %{_bindir}/web2png

As you can see, you have macros for every kind of path you need. Here are the most useful ones (look at the file /usr/lib/rpm/macros for a full list) : %{_prefix} , %{_bindir} , %{_sbindir} , %{_datadir} , %{_libdir} , %{_sysconfdir} , %{_mandir} , %{_infodir} . For games, use %{_gamesbindir} and %{_gamesdatadir} .

Changelog section

%changelog

This section is to keep track of any changes made to the package. Every new release build of the package must correspond to a paragraph in this section as well as an increase in the release number (if not in the version number). The structure of these paragraphs have to be respected as following:

  • Mon Nov 02 2010 Camille Begnis <camille@mageia.org> 2.0.1-1.mga1
  • The first line of the paragraph begins with * and, in order, each one separated by a space:
  • three letters for the day of the week,
  • three letters for the month,
  • two figures for the day of the month,
  • four figures for the year,
  • First name of the packager,
  • Last name of the packager,
  • e-mail of the packager between <>.
  • version and release of current modifications.
- Upgraded to 2.0.1

Then follows one line per modification applied to the package beginning with a -.

These are examples:

  • spec file stolen from korganizer.
  • last snapshot before release
  • Mageia adaptations.
  • Fix bug in /etc/zsh use USERNAME instead of USER.
  • Remove petit bouchon which annoys other players.
  • Improve /etc/z* to source the /etc/profile.d/ files.
  • fix typo in examples directory name
  • fixed QT libs version requirements
  • add patch to handle Earl Grey tea
Note:
By default only entries younger than 1 year will be preserved in the built package. To change this behaviour modify the value of %_changelog_truncate

The build

Our spec file is finally complete. Take a long breath, sit down and type rpmbuild -ba mypackage.spec

You may also add the --clean option which cleans the BUILD directory after package building completes. This is useful if you have little disk space.

There are then two possibilities for the last line of your process:

  • 0.01% probabilities: + exit 0
  • 99.99% probabilities for other cases.

You are in the second case? Congratulations, you passed the test, you are not an alien.

Good luck, so long, have a look to rpm building options (man rpmbuild ) to debug your work, look at other persons' specfiles, etc...

There is a very clean way to build packages: use rpmbuild -bs --rmspec --rmsource (in order to remove anything from the original build) and then do a rpmbuild --rebuild.

Optimize the build

When you launch the command to build your package, you certainly noticed message like foo-devel is necessary for foo2".

This means that it needs information from other packages used for development (usually files named foo.h). If you don't have these, compilation will stop or features will be missing in your package.

The place where all official packages are built (The Mageia Build System) have a lot of these devel packages preinstalled. If one is not declared in your SPEC file and is mandatory, the package will be built anyway on the cluster. It will work, but the lack of this information prevents building on machines missing the devel package, making debugging/upgrading more difficult.

To find the needed development packages to build a certain package, look at the website of the package, or the README/INSTALL files in the source tarball, usually this information is in one place or the other (but unfortunately not always).

An idea to hunt down these "missing BuildRequires" is to start packaging with only basics devel packages installed :

  • glibc-devel
  • libncurses5-devel
  • libstdc++6-devel

After that, only install the package's relative devel package that is asked for by the rpmbuild command.

When launching the build, watch for "checking for.." messages in ./configure output.

If you see something like "checking for foo... foo.h not found", this means that a header needed has not been found on your system. Search for the devel package containing "foo.h", but be careful: you can find more than one package containing what you seek. So choose the more obvious package. Don't choose a network related package when you build a sound application (for example).

Then install it on your system, and don't forget to add its name in the BuildRequires section of your SPEC file.

Missing headers can also be found during compilation itself. If it stops, check for others missing "foo.h" and apply the same recipe.

Testing an RPM

You should also check the Bugzilla pages for information about this subject.

Basic tests

The first steps to perform are:

  • Are the rpms created in the corresponding directories with the correct names? (into ~/rpmbuild/SRPMS/ and ~/rpmbuild/RPMS/i586/)
  • Is the information obtained from issuing the command rpm -qlivp --changelog mypackage.(src.)rpm correct?

Using rpmlint

Next, you have to use rpmlint, which will test various things on the package. rpmlint is a tool to check common errors on RPM packages. It is configured to check Mageia packages (according to the various RPM packaging policies in Mageia) but should work with all RPM packages. SUSE and RedHat are also using it.

Type rpmlint mypackage.<archtype>.rpm and a report on the specified package will be issued. For more precision, use the -i switch. You should check the binary packages (.*rpm) and the source RPM package (.*src.rpm).

You can configure rpmlint with the file ~/.rpmlintrc, or /etc/rpmlintrc. You should set at least the following:

from Config import * setOption("Packager","login@email.org") # default value # setOption('Packager', 'Mageia Team <http://www.mageia.org>|@mageia.org') addFilter("E: .* no-signature") addFilter("W: .* invalid-packager") addFilter("E: .* no-packager-tag") addFilter("E: .*-debug .*") addFilter("W: .*-debug .*") # not very clean, but easier to maintain release_tag = os.popen("rpm --eval '%mkrel 1'").readlines()[0][1:-1] setOption('ReleaseExtension', release_tag)

If you intend to create an rpm suitable for Mageia repository inclusion, you should also ensure that rpmlint-mageia-policy is installed, as this contains the various configurations and policies used by Mageia packagers.

rpmlint will check lots of stuff like: tags, binaries, configuration files, location, permission, ownership, FHS compliance, sources, menus, scripts, spec file content... For more details have a look at /usr/share/rpmlint/config.d/mageia.error.list.

Install test

On any machine - but preferably on a different one than that used for compilation - do an upgrade or an install, and then check:

  • Are all the expected files created in their expected places with the expected rights and owners?
  • Are all the installation modifications (if any) effective?
  • Are all binaries executable, and is the documentation accessible to the intended users?

Perfectionists should try various different installs and uninstalls to check whether all expected features are implemented correctly, for example without required packages.

If all of these tests are passed successfully, you are almost done, and should go to the last step of the process: submitting packages.

Something's going wrong?

Well, it appears that you have been reading this HowTo, which is a good beginning. If you couldn't find your answer right here, you should try in the given order:

For general RPM matters:

  • The official RPM-HOWTO (installed along with the rpm program on your system).
  • The book from Red Hat "Maximum RPM", which is available at http://www.redhat.com/docs/books/max-rpm/max-rpm-html/.
  • Post a question in the mailing list mageia-dev you subscribed to a long time ago at the beginning of reading these howto pages.

For specific Mageia RPM matters:

Drop a line to Mageia's Quality Assurance

If you feel that the information you found may be useful to others, in the scope of that document, feel free to submit your proposal to the maintainer of that document.

Pre- and Post-installation scripts

Basics

The RPM package is in fact a bit more than a simple archive containing files to be expanded in specific directories of the host client system.

The system offers to the programmer a great feature: pre- and post-installation scripts. They allow the packager to write a piece of code which will be executed on the client machine while installing or erasing the package.

These scripts are made of any sh valid commands. There are four of them:

There are certain caveats about these scripts which you should take into account. Number one, each must fit inside a 8192 byte buffer, and number two, they should be non-interactive. Anything which requires manual input from the user is wrong, as this will break non-interactive RPM installation procedures.

  • %pre - This script is executed just before the package is installed on the system.
  • %post - This script is executed just after the package is installed on the system.
  • %preun - This script is executed just before the package is uninstalled from the system.
  • %postun - This script is executed just after the package is uninstalled on the system.

The scope of such scripts may be very large, and they have to be designed with much care not to harm the host system. One has to remember that these scripts will be run as root... They correspond to the tasks a system administrator would have to accomplish when installing a new program on a system. For example:

  • Add a cron job running the program at fixed intervals
  • Run chkconfig to run the daemon at boot time
  • ...

Dealing with upgrades

The fact that a package may be upgraded, and not simply installed or removed, makes the thing a little bit tougher... The problem is that the %postun script of the update is run after the %post of the old version. So all %post stuff is lost...

It is often useful to ensure that an action occurs only during an install and not during an upgrade. Likewise for an action that only occurs during an uninstall and not during an upgrade. RPM's mechanism for dealing with this is the argument that is passed to the %pre, %preun, %post and %postun scripts by default.

This argument indicates the number of instances of this RPM that will be installed on the machine after the current script has completed. For example, if a new package is installed then 1 will be passed to %pre and 1 passed to %post. When the package is upgraded, 2 will be passed to %pre of the new RPM, 2 will be passed to %post of the new RPM, 1 will be passed to %preun of the old RPM and 1 will be passed to %postun of the old package.

Parameter / Script %pre %post %preun %postun
for a first time install 1 1 N/C N/C
for an upgrade 2 2 1 1
for a removal N/C N/C 0 0

This will allow the programmer to distinguish different attitudes of his scripts depending on the operation: install or upgrade.

  • For install scripts ( post, %pre ) check if $1 is equal to "1" then it is a first time install, not an update.
  • For uninstall scripts ( %postun, %preun ) check if $1 is equal to "0", if yes then it is a full removal; if not it is either an upgrade or an install --force of the same package.

To test this argument, the following 'if' statement is used:

%postun if [ $1 = 0 ]; then // Do stuff specific to uninstalls fi if [ $1 = 1 ]; then // Do stuff specific to upgrades fi

A single test is therefore enough, to call the right action at the right time.

Filetriggers

rpm filetriggers (TODO) are used to remove the burden of the repetitive tasks like "%post -p /sbin/ldconfig" or "%update_menus".

More macros

When building RPM's for Mageia, you have more macros to simplify the specfile.

  • Handling the info pages. An example is the best teacher:
%post %__install_info %{name}.info %preun %__install_info %{name}.info
  • Handling internationalization cleanly. The best way is not to enter by hand the .mo files that usually are in /usr/share/locale/... , but to use a special macro in the %install section, which will fill up a special file for that:
%find_lang %{name}

Then you will use the file in the file list:

%files -f %{name}.lang
  • Build macros. The build macros %configure and %makeinstall are quite big at the present time. They specify the prefix, but also every common directory (such as bindir, datadir, and so on); in that respect, they work flawlessly with small and medium sized packages, but always need some attention for the rest. The macro %make performs the make command with appropriate -j<num> option to scale well with multiprocessors. If you need to call manually the ./configure script, remember to NEVER hardcode the architecture; the macro %{targetplatform} is made for that purpose (or even %{target cpu} , if necessary).
  • Building servers. To build safer servers, we use a specific macro, %serverbuild, to be used before the actual build occurs. This allows for safer optimization flags. The %build section will often look like:
%build %serverbuild %configure %make
  • Initscript macros. When you install a package which will provide it's own initscript (the files in the directory /etc/init.d), it needs to be added through a call which looks like chkconfig --add ..., but not in the case of upgrades, and it needs to be restarted if already running; when uninstalling, similar (opposite) things must be done; we have specific macros to do that without a glitch:
%post %_post_service <initscript-name>
%preun %_preun_service <initscript-name>
  • Handling ghostfiles. Mostly with games, sometimes packages use a varying file which may even not be present. That's where ghostfiles are useful. Here's an example:
%install (...) mkdir -p $RPM_BUILD_ROOT/var/lib/games touch $RPM_BUILD_ROOT/var/lib/games/methanescores %post %create_ghostfile /var/lib/games/powermanga.hi root games 664 (...) %files %attr(664, root, games) %ghost /var/lib/games/powermanga.hi

The %create_ghostfile macro will expand to:

if [ ! -f /var/lib/games/powermanga.hi ]; then touch /var/lib/games/powermanga.hi chown root:games /var/lib/games/powermanga.hi chmod 664 /var/lib/games/powermanga.hi fi

You can check at any time the content of a given macro using rpm --eval:

$ rpm --eval %update_icon_cache if [ -x /usr/bin/gtk-update-icon-cache ]; then /usr/bin/gtk-update-icon-cache --force --quiet /usr/share/icons/%{1} || true; fi

You can also list all values and macros used by rpm from macros and rpmrc files: rpm --showrc

Interaction with urpmi and rpmdrake

Sometimes it is necessary to warn the user about some particular care that should be taken when upgrading or installing a specific version of a package.

The following file name formats can be used:

  • README.install.urpmi: displayed when the package is initially installed
  • README.version.upgrade.urpmi and README.version.update.urpmi: displayed when the package is updated to version version or above, from a version that is less than version (version should be either a package version, epoch:version, version-release, or epoch:version-release, the shorter the better)

Also supported are README.urpmi (displayed in all cases) and README.upgrade.urpmi/README.update.urpmi (always displayed when upgrading). These shouldn't be used as they cause the message to be shown in every subsequent update, even if the user has already seen the message many times.

HOW TO DO (example with README.install.urpmi):

  • put a README.install.urpmi in the SOURCES/ directory
  • add it in the spec as SourceX: README.install.urpmi (replace X with an appropriate number)
  • in %install section : install -m644 %{SOURCEX} README.install.urpmi (notice the absence of %buildroot prefix here)
  • in %files section, add README.install.urpmi in a %doc macro, or add a %doc macro if there is none

Alternative : checkinstall

A very easy way to build RPMs for personal use is to install the checkinstall package; compile from source as usual (./configure && make && sudo make install), but just replace the make install' step by checkinstall. This automates building an RPM, and is very simple to use. The advantage is that you don't ever have to bypass the package manager when compiling from source. (However, it's probably A Good Idea to build RPMs "properly" as described above, if you intend to distribute them to others.)

Alternative : alien

Specification files (.spec) are often borrowed from other Linux distributions based on Red Hat rpms, such as Fedora and vice versa. In a similar, but more lazy way, as it might be a huge job to rebuild dependent libraries for a specific application, the maintainers of the original application can provide a foreign binary using a different packing system, such as Linux Standard Base (LSB-compliant .rpm), Debian (.deb), Stampede (.slp), Solaris (.pkg). Then you can try using "alien" to convert from one packing system to another. For example, 'pandoc' is hard to build and maintain because it is a 'Cabal package' which will be compiled with 'ghc' and many Haskell libraries, but by using alien, the command line:

$ /bin/sudo alien --to-rpm --scripts pandoc-1.19.1-1-amd64.deb
[sudo] user password :

will provide a binary rpm which can be installed by

$ /bin/sudo rpm -ivh pandoc-1.19.1-2.x86_64.rpm
[sudo] user password :

and tested by converting a LaTeX document (.tex) to a mediawiki (.wiki) document:

$ /bin/sudo pandoc -o foo.wiki -f latex -t mediawiki foo.tex
[sudo] user password :

The output MediaWiki document will be compatible with this Mageia wiki.