RPM packaging for beginners

So, my first post on my blog. The most difficult part: what to write about? As openSUSE just had it’s first community week with plenty of people participating, I decide to go with the flow.

I for myself am mostly active in the community with packaging all kinds of thins, and of couse mailinglists, testing openSUSE Factory and IRC channels.

Packaging is an important part for the community and for a distribution’s users. Not everybody has the knowledge or will to install something from source. Some packages are highly complex, others are very simple.

Let’s start with something simple, which does not end up in a complex spec file (the spec is the package build instructions). During the Community week, I was asked to package up cairo-clock, which ended up being fairly easy and suits perfect for this example.

Pre-required knowledge: how to install a program from a source tarball.
Typically this is handled with

./configure
make
sudo make install

And this is exactly true for cairo-clock (once all the build dependencies are satisfied).

How does a spec file look? IT consists of a preamble, a %prep, %build, %install and a %clean section. To finalize, there is a %files and %changelog section. I’ll just go to explain them all:

Preamble

The preamble contains all the information about the package, that is visible to the user and is important for package manager and for the build process. Some are required, and some are optional. The list given below are not all considered required for an RPM to build successfully, but I would highly suggest to heve them always in.

Name:           cairo-clock
Summary:        Cairo-rendered on-screen clock
Version:        0.3.3
Release:        1
URL:            http://macslow.thepimp.net/cairo-clock
Source0:        cairo-clock_0.3.3-1.tar.bz2
License:        GPL v2
Group:          Productivity/Other
BuildRoot:      %{_tmppath}/%{name}-%{version}-build

Fairly easy to understand: Name is the name of the packag and Summary is a short summary. This is both shown in yast (and zypper) when you look for the package.  The Version and release tag should not be confused though: Version is what the program author said, the program’s version is, and Release is the number of released versions of the RPM you prepared. If you’re using the openSUSE Build Service, it will actually take care of the Release number and increase it internally whenever you make a change.
The URL is for reference and tells where the project lives. This is very practical information if somebody wants to cross reference or even for yourself, if you want to verify if a newer version is available.
Source is the filename of the source tarball. License should be fairly easy to understand and has to be of course what the author of the application released it under. The Group is where you can find the package in yast, when you use the Group view.
And last, BuildRoot: I would say: just copy this one always around. It’s a safe assumption, creating the temporary buildroot in your tmp folder. Should anything mess up, you can always delete it and your system should not be risked.

Also part of the preamble are the BuildRequires: those can sometimes take some time to find what is required, but you’d have the exact same problem when you build an application from source yourself. A good way to go is to just ‘build’ the package with the missing BuildRequires. Configure is most likely going to tell you what is missing, and you can add the specific dependencies.

For Caire-Clock, this give the following list:

BuildRequires:  fdupes
BuildRequires:  gtk2-devel
BuildRequires:  pango-devel
BuildRequires:  fontconfig-devel
BuildRequires:  libglade2-devel
BuildRequires:  librsvg2-devel
BuildRequires:  perl-XML-Parser
BuildRequires:  update-desktop-files 

fdupes and update-desktop-files are not mandatory for the build to succeed; they are here to get the package a bit nicer (space savings for example) and to fix up some things.

Not as difficult as you thought it would be, right?

The %prep section

In the %prep section, the build process (rpm-build for example) is instructed on what to do, before we can actually build the package.
very common you will have %setup in there. I normally add -q, which just suppresses some output, makes the log more readable.

So what does %setup mean? It will extract (tar -xf) the file specified in the preamble as Source. It’s expected that the tarball creates a folder named %{name}-%{version}, so in the case of this package cairo-clock-0.3.3. For this source package this is true, so nothing more is needed.

The %build section

So, how exactly is this program to be compiled? Simply try to get the compile process done without trying to package the application. For cairo clock this was fairly simple:

  ./configure && make

is all we need. This typically installs programs to /usr/local, which is not what we want when building a program for distribution via packages. They should cleanly ntegrate with the system (/usr/local is defined to be for locally built applications. This would only be true for your own machine).

Instead of writing ./configure with all it’s parameters, we use the provided macro.

%configure
%__make %{?jobs:-j%jobs}

That’s what we put in the final spec file for this package. The %__make is just taking care of differences between different systems. I’s safe to always use this line.

The %install section

So far, the tarball has been extracted, we configured the build and compiled the source. Next step in a regular install would be make install, and the same we do now in the spec file.

%makeinstall
rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
%suse_update_desktop_file -r -G "Generic Name" %{name} X-SuSE-DesktopUtility
%fdupes %{buildroot}%{_datadir}/%{name}
%find_lang %{name}

%makeinstall is the call for make install as you would do manually, but it takes care of redirecting the installation to a temporary folder. We need to be sure to stay in the buildroot after all (as defined in the preamble).

The other commands and their meaning:

rm -f $RPM_BUILD_ROOT%{_libdir}/*.la : Deletes all libtool archives that were just installed. They can cause much more trouble than they are good for.
%suse_update_desktop_files [...]     : takes care of putting the originally provided .desktop file in a category we know on a openSUSE Gnome system
%fdupes %{buildroot}%{_libdir}%{name}: cairo-clock installs several themes and a lot of files are equal in the themes. This is wasting space on the harddisks. To reduce the install size, those files are linked (ln).
%find_lang %{name}: finds all the files called cairo-clock.mo that were installed and creates a list for us, nicely prepended with the language specific information. To be used later in the %files section.

The %clean section

At the end, when our package is built, we don’t want to leave a mess on the system we were working ourselves. So we clean up everything.

The %files section

%files contains a list of all the files we need to copy in our RPM, so everything that should finally be installed with our package.

%files -f %{name}.lang
%defattr(-,root,root)
%doc AUTHORS COPYING INSTALL NEWS README TODO
%{_bindir}/*
%{_datadir}/*/%{name}.*
%{_datadir}/%{name}
%{_mandir}/*/%{name}.*

    As said, we make use of the list of the translation files from the %instal section. %files -f %{name}.lang instructs to use the list from cairo-clock.lang to start with.
    %defattr sets the default permissions and file owner and groups: the permission is set to ‘-‘, which means we use what the installation did. This is typically safe to follow. All files installed will be owned by user root and group root.
    The %doc line copies some files that were not installed during %install, but should nevertheless be part of every package to acknowledge the source and to confrom with the license. If available, you should also package eventual original README files. It might even make sense to put your own README with further instructions regarding coniguration, in your packages.

    and finally we have a complete list of files to be included.

    DONE

    Sounds like a higly complex task at first, but understandin what the different lines mean make the entire process almost child play.

    I hope you can get some valuable information out of this and the openSUSE community is looking forward to your valuable additions.

    9 responses to “RPM packaging for beginners”

    1. Sankar Avatar

      Nice post.

    2. Adam Williamson Avatar

      Nice job 🙂

      Just one note, although it may be too advanced for your intended audience:

      “The %__make is just taking care of differences between different systems. I’s safe to always use this line.”

      This is not strictly true; not all code is actually safe for parallel compilation. Some builds will fail if built with -jX on true multi-processor systems.

    3. Dominique Leuenberger Avatar

      Adam,

      You’re right with both your statements. The ‘target’ audience was people really just ‘jump starting’ into RPM. And for this I think it’s better not to talk to much about exceptions (on the cost of some inaccuracy).

    4. Gabriel Avatar
      Gabriel

      Very nice post! Just recommended and ping back on my blog.

    5. […] its a very useful guide  ‘RPM packaging for beginners‘ from Dominique Leuenberger. Please enjoy, and post your feedback using comments. Share […]

    6. KonstantinMiller Avatar

      Hi. I like the way you write. Will you post some more articles?

    7. LnddMiles Avatar
      LnddMiles

      The best information i have found exactly here. Keep going Thank you

    8. Matthew Avatar
      Matthew

      You should rather call this entry “Preparing .spec file” I want to start preparing packages for my convenience but this entry is only useful for preparing .spec file. It will be great if You could complete this entry for entire process of building rpm, e.g rpmbuild or suse build. Thanks!

    9. Dominique Leuenberger Avatar

      Thanks for the comment. I’ll try to make a follow up. But it will be very simple I’m afaid (copy the files in the right directory and use rpmbuild -bb). But thanks for the suggestion.