RPM homepage link
Home
Up

  
  The following is a copy taken of: http://freshrpms.net/docs/fight.html on 31 Jul 2002 -- Please follow the link to ensure you see the author, Matthias Saou's, latest version.  
FreshRPMs large logo

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 very often it's a real pain to deal with.

2) Prepare your equipment : The spec file!
This is the required equipment to stand a chance. Reusability and tweaking will help us a lot here.

3) Fight against the beast : The duel!
Now that we saw what the beasty was up to and that we are prepared, it's our turn to attack, let's get him!

4) Happy end : The winner!
If you're as determined as I am, you should now live happily ever after, and many people will benefit from you've done.

The rules to never forget :

dot Don't EVER build any packages as root, use a regular user account instead.
dot Don't EVER modify any of the source tarballs, create patches or quick tweaks instead.
dot If the software can be installed by hand, it can ALWAYS be packaged as an rpm (even if your brain does get damaged during the process).
dot If you've done something completely new or useful (a new spec file, a patch, an init script...), ALWAYS take the time to offer it to the program's author(s).

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 has to be done in a special way.
Here's how I proceed with the generic "./configure ; make ; make install" case :

  • Execute the ./configure script manually and try to see if it checks for some particular librairies to be able to later report them as build dependencies and most of the time as package dependencies too.
  • Execute "./configure --help" to see if there are any special options we may want to turn on or off in our build.
  • Execute "make" once the configure is done to be sure that everything compiles cleanly.
  • Execute "make install prefix=/var/tmp/packagename" to see if it is possible to install the package in a temporary location.
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" or "make install ROOT=/var/tmp/packagename". Getting things to install at this point isn't vital (for now), 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 where 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 equipment : The spec file!

Now, mighty knights, we need to get prepared : Let's start the spec file! This file is the core of every rpm package, it's the one that contains the recipe that will allow us to elaborate a magic potion based on all the ingredients in rpm inorder to change the ugly tarball into a handsome... rpm package :-)
Here's (quickly) how I usually structure my spec files :

  • First the required usual informations (headers)
  • The package description (%description)
  • The build preparation (%prep)
  • The sources build (%build)
  • The sources install (%install)
  • The build cleaning (%clean)
  • The package pre/post(un)install scripts (%pre, %post, %preun, %postun)
  • The package file list (%files)
  • The package changelog (%changelog)
And that's it!
Here's what my simple skeleton spec file looks like :
Summary: .
Name: 
Version: 
Release: 
#Epoch: 1
License: GPL
Group: 
Source0: 
Source1: 
Patch0: 
Patch1: 
URL: 
BuildRoot: %{_tmppath}/%{name}-root
Requires: /sbin/ldconfig

%description

%prep
%setup -q

%build
%configure
make

%install
rm -rf %{buildroot}
%makeinstall

%clean
rm -rf %{buildroot}

%post -p /sbin/ldconfig

%postun -p /sbin/ldconfig

%files
%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
* Mon Jan 14 2002 Matthias Saou 
- 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 (sorry, I'm just a sysadmin ;-)), 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 yourself were there from the very beginning! 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 exactly like 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 (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 rpm package building 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. Most of the time, to be sure to not miss any (the package would be incomplete) or not to include too many (the build would fail), since now the duel must begin and get all the way to the %install part!

OK, here 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		Fresh RPMS
%vendor			Freshrpms.net
%_signature		gpg
%_gpg_name		Matthias Saou (Thias) 

%_topdir                /home/dude/redhat
%_tmppath		/var/tmp/rpm

%_rpmtopdir		%{_topdir}/%{name}
%_builddir		%{_tmppath}/BUILD
%_rpmdir		%{_rpmtopdir}
%_sourcedir		%{_rpmtopdir}
%_specdir		%{_rpmtopdir}
%_srcrpmdir		%{_rpmtopdir}

The %_topdir is the one we're after, %_tmppath being the directory where the build roots will go (see the BuildRoot: from the spec file). All the options below allow to build each package in a subdirectory named after the package inside the %_topdir instead of having everything straight in the RPMS, SRPMS etc. directories. 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, and my GnuPG signature options.

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

  • SPECS/ : Where all the spec files go (we put)
  • SOURCES/: Where all the tarballs and patches go (we put)
  • RPMS/<arch>/ : Where all the binary RPMS we build will be written (we take)
  • SRPMS/ : Where all the source RPMS we build will be written (we take)
  • BUILD/ : Where all the preparation and build will be done (we cleanup, we use to debug)

So now our last move before the duel is to put our spec file in the SPECS directory and all our tarballs and patches in the SOURCES one. 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.

If you've used a configuration similar to mine, with all the bottom lines from the ~/.rpmmacros, you will instead need to create a subdirectory for each package, named after it (the same name you put in the "Name: " tag), then copy the spec file, sources and patches in it. This is much more efficient if you build many packages.

3) Fight against the beast : The duel!

Ready? Fight!

Oops! I forgot to explain how to use your weapon :-) Well, it's still pretty straightforward : Just execute "rpmbuild -ba yourfile.spec". Note that you should always prefer "rpmbuild" over "rpm" since the building abilities have been moved there, and the ones provided by "rpm" are only wrappers that execute "rpmbuild" themselves. This is the first move, you'll 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 /var/tmp/rpm/BUILD 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 OK, but usually you've gotten to know them off by heart by now, so it won't teach you much. I bet you've never felt you knew a program you haven't made yourself that well before. 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" :-)

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

  • What's the difference in between binary and source rpm packages?
  • The binary is the program ready to be installed on a specific architecture, whereas the source is a totally different package containing the spec file, the sources and patches, and can be used to rebuild binary rpms in no time! Both were created during the build process.
  • Where can I find detailed documentation on the spec file syntax?
  • Read the very good "Maximum RPM" docs, they were written in 1997 (hey, I didn't even have a PC back then!), haven't been much changed since, but it's my absolute reference.
  • Isn't there an easier way to learn how to build rpms than trying to make one from scratch right away?
  • Sure! If all this scared you (just a bit I hope), simply set up you're "equipment" as described and install source rpms. You will then have all the tarballs, patches and spec files ready to be examined and rebuilt. This is how I learned many interesting tweaking methods, it's probably far from being the worst way to learn rpm package building :-)
  • In the %files section, why not just put "/" since all the files I want to include and *only* them are in the build root?
  • Simple question, simple answer : All directories referenced as being part of the RPM will be "rmdir"ed when it is erased, which means you will get an error if you included /bin in your package and there are still files in that directory when you remove the package from the system (which will probably happen indeed!). You can easily recognize rpms built by non-experts when you get such messages (for /usr/share most of the time). The %files section is not as simple as it looks, so be careful!
  • How come you know rpms so well? And why the hell do you build so many?
  • Well, I know rpms quite well because I've built many :-) (and some tricky ones, pheeeew!). I build them first of all because I have three home computers, two laptops, and two other computers at work... and yes, they all run Red Hat Linux at the moment (some have a multiboot... with FreeBSD). It's so much easier to perform a simple "rpm -ivh" command rather than having to recompile the same program over and over and it's so much "cleaner" too... and the second reason is because I like to feel useful to others, that's why I make them available from my website.
  • You haven't said much about dependencies, why?
  • Look at some existing rpms and you'll know how to deal with them. For instance, if the package you are building requires gtk, you will need to put "Requires: gtk+" in your spec file or you can even include a version, let's say "Requires: gtk+ >= 1.2.0". In these cases, you should also add a "BuildRequires: gtk+-devel >= 1.2.0" to be nice with the people trying to rebuild your source package so it will tell them right away if they don'y have that development package installed instead of failing later in the configure script. I'm sure you got it now :-)
  • You haven't said much about the changelog, why?
  • OK, I suppose looking at existing spec files IS the best way to learn then... just have a look at a few and everything should be crystal clear in no time.

 

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



Graphics by Gimp Powered by Red Hat Linux Created with Vim
Copyleft 2001 Matthias Saou - This site is not endorsed by Red Hat, Inc. nor is official in any way.
$Id: fight.html,v 1.7 2002/05/02 21:14:47 dude Exp $


Last updated: Tue, 30 Jul 2002 22:12:25 -0400

 

Back to Top page
Maintained by Owl River Company -- Comments to: rpm editor, please.