[home] [packages] [docs] [apt] [links] [mirrors] [lists] [misc] [about]

The fight, my first attempt to make a readable rpm package building introduction.
(or how I learned to stop worrying and love the packages)

Note : This document is not intended to be a reference, not even a "howto". It will hopefully just do what I intended it for : Show the basics of the rpm build process for people already familiar with software compiling and rpm packages from a user point of view.

The four steps I will guide you through :

1) Know your enemy : The source!
In most cases, source code is a good thing. Here, we'll find out that quite often it's a real pain to deal with.

2) Prepare your weapon : The spec file!
This is the mandatory defensive weapon to stand a chance. Reusability will save us lots of time here.

3) Fight against the beast : The duel!
Now that we saw what the beast was up to, and that we are all set, it's time to strike back!

4) Happy end : The winner!
If you're as determined as I am, you will now enjoy a millisecond of glory, and many people will benefit from your fight.

The basic rules to never forget :

1) Know your enemy : The source!

So, here we go. Everything usually starts with a tarball of the program we want to package. The very first step is to analyse it to see how it needs to be compiled. Most of the time, the usual "./configure ; make ; make install" is given in the INSTALL or README file, but sometimes you may want to pass extra arguments to the configure script, or the installation needs to be done in a special way.
Here's how I proceed with the common "./configure ; make ; make install" case :

For the last step (make install), there are various ways of getting things to work, and most of the time you will have to take a look at the Makefile if the "prefix=" way doesn't work. Very often you just need to execute "make install DESTDIR=/var/tmp/packagename" (quite common) or "make install ROOT=/var/tmp/packagename" (less common). Getting things to install at this point isn't vital, but keep in mind that we will need to install all the files we want contained in our package to a temporary "build root", which is a location from which they will appear as their final destination : If our package is to contain /bin/ls, it should have been installed to /var/tmp/packagename/bin/ls by our last command.

Now you should know the steps to build and install the package from sources with the desired options, and you should have prepared any needed patches (I won't get into details here since patches are rarely required, but it does happen, unfortunately...).

2) Prepare your weapon : The spec file!

Now, mighty knights, we need to get prepared : Let's start the spec file! This file is the soul of every rpm package, and will be the magic potion based on many ingredients (the rpm macros) that will allow us to change the ugly tarball into a handsome... rpm package :-)
Here's (quickly) how I usually structure my spec files :

You can order most of these sections as you like, but the above is the most widely used way of doing it.
Here's what my simple skeleton spec file looks like :

Summary: .
Name: 
Version: 
Release: 
License: GPL
Group: 
Source0: 
Source1: 
Patch0: 
Patch1: 
URL: 
BuildRoot: %{_tmppath}/%{name}-root
Requires: /sbin/ldconfig

%description

%prep
%setup -q

%build
%configure
make %{_smp_mflags}

%install
rm -rf %{buildroot}
%makeinstall
%find_lang %{name}

%clean
rm -rf %{buildroot}

%post -p /sbin/ldconfig

%postun -p /sbin/ldconfig

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

%files devel
%defattr(-, root, root)
%doc HACKING
%{_libdir}/*.a
%{_libdir}/*.la
%{_libdir}/*.so
%{_mandir}/man3/*

%changelog
* Fri Feb 14 2003 Matthias Saou <matthias.saou@est.une.marmotte.net>
- Initial RPM release.

As you can see, it's fairly simple. I should even say *amazingly* simple if you have any programming notions. I personnaly don't know much about programming, but it didn't take me long to understand the structure of a spec file. I think the only two things you need are to already have installed tarballs yourself and a basic rpm knowledge, then you're all set! How's that for simplicity?

Now as you can see, many macros are used here. To see exactly what they do, take a look at the /usr/lib/rpm/macros file on your system... yes, all the ingredients needed to prepare the magic potion are right there. Basically, you could guess what most of the path macros (the %{_*} ones) are : %{_bindir} defaults to /usr/bin, %{_datadir} to /usr/share, %{_sysconfdir} to /etc and so on. They're all called the same as the options you usually feed the configure scripts (and "make install" too), simple eh? Well there's even better! The %configure macro executes the ./configure script with all those paths set (./configure --prefix=%{_prefix} --bindir=%{_bindir} ...) and even sets the CFLAGS environment variables (the compiler optimization flags) to the ones you gave rpm! Same for the %makeinstall macro that will prepend the build root (make install prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir} ...).

Starting with RedHat 7.0, there's even more magic performed : The binaries and libraries are automagically stripped and all the manpages gzipped!
That's it for the build part. If only life was as simple :-) Luckily it's not, and actually rpm package building isn't either... you often encounter "interesting" problems. <grin>

Now we need to know what files to include in the package. All of them will need to be referenced in the %files section, with a path relative to the build root, which is in fact the absolute path they will have in the final RPM. You need to be sure to not miss any (the package would be incomplete) or not to include too many (the build would fail). Since in Red Hat Linux 8.0, the default is to complain if some files exist in the build root but aren't referenced. I personally think it's a good thing.

By now you're probably wondering what the battle area looks like, right? Well, it's just like the files containing the marcos, it's been right under your nose forever : It's the /usr/src/redhat directory and all it's subdirectories. Now remember the rule saying NEVER EVER to build rpm packages as root? Well, that's why we won't touch those directories, so let's just copy them to our home (cp -a /usr/src/redhat ~/), or keep reading for a per-package structure instead. Now we need to change our rpm preferences to use this "~/redhat" directory instead of the original (and default) one, by editing the ~/.rpmmacros file (create it if necessary, and yes, ~/.rpmrc is depreceated now, so ignore anything you see that still relates to it). Here's mine :

%packager               Matthias Saou
%distribution           Psyche Freshrpms
%vendor                 Freshrpms.net

%_signature             gpg
%_gpg_name              Matthias Saou (Thias)

%_topdir                %(echo $HOME)/redhat
%_tmppath               %{_topdir}/tmp
%_builddir              %{_tmppath}

%_rpmtopdir             %{_topdir}/%{name}
%_sourcedir             %{_rpmtopdir}
%_specdir               %{_rpmtopdir}
%_rpmdir                %{_topdir}/RPMS
%_srcrpmdir             %{_topdir}/RPMS
%_rpmfilename           %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm

You need to remove that last big block out if you intend to use the same structure as the one under /usr/src/redhat. If you use the lines above, you will get all files related to a build (sources, spec) in ~/redhat/%{name} and built packages under ~/redhat/RPMS/ which I prefer. So the %_topdir is the directory we're after to put our stuff in, and %_tmppath is the one where the build roots will go (see the BuildRoot: from the spec file). The first few options are simply default values that I've set so that I don't have to insert them into every spec file I write, as well as my GnuPG signature options.

Now here's how the subdirectories of this "top directory" will be used if you don't define the %_rpmtopdir and following options :

If you do, here is what it would look like :

So now our last move before the duel is to put our spec file, tarballs and patches in the right place. Usually, the spec file is called "packagename.spec" (e.g. rpm.spec) and does not contain any version number, it saves some time when updating the package since you don't need to rename it.

3) Fight against the beast : The duel!

Ready? Fight!

Oops! I forgot to explain how to use the weapon :-) It's pretty straightforward : Just execute "rpmbuild -ba yourfile.spec". This is the first move, you may need to do it over, over and over again fixing your spec file each time anything fails. I won't go into the details here, just a few pointers : The %_builddir (~/redhat/BUILD/ or ~/redhat/tmp/ depending on the setup you chose earlier) and "BuildRoot:" (%{_tmppath}/%{name}-root usually) directories are your allies, so are the rpm* files created under %{_tmppath} and the "rpmbuild --help" command (-ba is build all : binary + source, -bb is build binary, -bi --short-citcuit may be useful too sometimes).

4) Happy end : The winner!

You got your rpm packages to build at last? Great!
Well, now you can run the usual queries (rpm -qpi, rpm -qpl, rpm -qp --scripts) on your packages to see it they're correct, but you probably know them off by heart by now, so it won't teach you much. I bet you've never felt you knew so well a program you haven't made yourself. Who ever said rpms were for lazy people?
Last step, install your new binary rpm package on a system somewhere and see if the program works... if not, you've lost the battle... but if it does, you've made it! You are now a "knight or the rpm package" :-)

The end.

What?? you've only read this page and you haven't compiled anything yet?
Then I suggest you read this mini for-this-page-only faq while you're at it :

I hope you found this page useful, please send me any suggestions or corrections if you have any.