Better living - through RPMS !!

A great way to live life is to keep packages in RPM's, set up your own SRPMS and use yum. To this end, here are my notes on building rpms. Most, if not all of this methodology was stolen from Tim Pickering, who maintained an RPM collection (that I inherited in 2009 when he fled the country) for the MMT at The MMT RPM repository

In a nutshell, you get the tarball for the package you want to fuss with, keep it pristine, and write a specfile, possibly keeping any changes you make separate as patches, and perhaps augmenting the tarball with some config files as needed.

If you are going to be diving deeply into this (and there seems to be no middle ground in the package building game), take a look at the Fedora packaging guidelines on the Fedora Project wiki.

building an RPM - Getting set up.

First of all, you will need to install a couple of packages:
yum install rpm-build rpm-sign
I have been bitten several times by not installing the "rpm-sign" package. You only need it if you want to sign rpms, but if you neglect to install it and use the --sign switch to rpmbuild, you get a bizarre error about your rpm file being missing. In fact it is not your rpm file that is missing, but whatever file is needed to sign the rpm. You have been warned. This package didn't exist until recently, then fedora for some reason split these things out into their own package.

Once this is done, there are 3 things you will need to set up before you dive in and start building rpms:

The rpmbuild directory

The rpmbuild directory is where source rpms will get unbundled and will provide sort of a sandbox to do rpm building. Take a look at .rpmmacros if you want to change this or put this someplace other than your home directory. Using a scheme like this is a LOT more sane than tromping around in your own system tree while you work through the issues involved in whatever package you want to install. This directory has the subdirectories:

Some people also have a SPECS directory, in which case spec files get placed there, while the tarball and patches go into SOURCES, thus far I am happy to omit this and have the whole works in SOURCES.

The directories RPMS and SRPMS can be links to places in your web site documentroot if you are making these things publicly available.

The .rpmrc file

This file has two lines, as follows:
include:    /usr/lib/rpm/rpmrc
macrofiles: /usr/lib/rpm/macros:/usr/lib/rpm/%{_target}/macros:/etc/rpm/macros.specspo:/etc/rpm/macros:/etc/rpm/%{_target}/macros:~/.rpmmacros

The .rpmmacros file

This is pretty big, so I provide it as a link. I got this from Tim Pickering, who got it long ago from Mike Harris at Red Hat, and I make the file available at this link: .rpmmacros

Signing your RPM's

We are getting a little ahead of ourselves, but you may want to set things up so you can sign the rpms you build.

There is absolutely no reason to do this if you only use rpms internally, but if you are offering them to other people, and especially if RPM's you are building are being hosted on sites you do not control, then you really ought to be signing them.

To do this, you have to set up your own GPG digital signature. This really is not all that hard. GPG was already part of my fedora install. I have the details on all of this at:


Starting from a source RPM

If you are starting with a source RPM, you could put it into the SRPMS directory. This is probably the most reasonable thing to do, but beware. If you rebuild the source RPM and neglect to increment the version number in the spec file, this source RPM will be overwritten. Of course you will never do that.

If you are confident that you don't need to fiddle with anything, you can go straight from the source RPM to a binary RPM via:

cd SRPMS
rpmbuild --rebuild yada.src.rpm
This is just the thing if you are rebuilding a driver for a new kernel and are absolutely sure that no kernel API changes affect your driver (as if THAT ever happens). Most of the time, you will need to fiddle, and the first step is to unpack the source RPM as follows:
cd SRPMS
rpm -i package.ver.src.rpm
This will unbundle the source rpm and put its contents into the right places (as dictated by the settings in .rpmrc and .rpmmacros). In general, everything goes to a newly minted directory under SOURCES with a name like SOURCES/package-ver. This directory will include the spec file, the pristine tarball, and any patches.

I was once innocent about how things work from this point. I used rpmbuild -bp to unpack the tarball (this unbundled it, placing it under the BUILD directory). I then made changes to a few of these files, and then issued the rpmbuild -bb to build a trial package. This threw away all of my changes when it began the process by once again unpacking the pristine tarball. This did not make me happy, but such is the price of education. (We are also getting ahead of ourselves.)

What should I have done? Well I should have either gone through the process of unpacking twice (described below) and using diff to generate a patch file or I should have made my changes and regenerated a new tarball. In any event my working tree should NOT be kept under BUILD, this should be left alone as a place for rpmbuild to do its work.

The rpmbuild program

This program is the workhorse of the RPM building process. You can get all kinds of information via man rpmbuild. Using rpmbuild is the name of the game from here on.

Before building, I cd to SOURCES/package-ver and do one or more of the following.

So, for example, to build walrus-1.2.4 we do this:

You could consider putting the following aliases in your .bashrc:

I used to use the --sign switch on the rpmbuild command, but this broke as of Fedora 15 (and rpmbuild 4.9.X) and I gave up on it.

Keep two source trees

If you make any changes and expect to need to generate patch files, you will want to untar the tarball twice.

Let's say you are working on the xephem package.
One tree (the pristine sources) you could call xephem-3.7.3-ORIG.
The other (the one you hack around in) you just call xephem-3.7.3.

What I do to achieve this is:

cd SOURCES/xephem-3.7.3
rpmbuild -bp xephem.spec
cd ../BUILD
mv xephem-3.7.3 xephem-3.7.3-ORIG
cd SOURCES/xephem-3.7.3
rpmbuild -bp xephem.spec

You may find yourself working on a package that already has a patch file. You could apply that patch and treat the patched sources as your reference pristine sources. By doing this, you would be working up a set of changes from those patched sources to whatever you ultimately need, thus creating a second independent patch file.

In a case like this, I prefer to just have one patch file, so I want to create a truly pristine source tree. In a case like this, I go into the spec file and comment out the patch command in the %prep section, then use rpmbuild -bp to expand the original sources. After doing this, I uncomment the patch command and then use rpmbuild -bp to produce my working sources,with the patch applied.

Once you do this, you run make inside the BUILD/xephem-3.7.3 tree and hack to your hearts delight. But when you are done, be sure to save this work somehow, because if you do any rpmbuild command after making edits, you will delete and overwrite all of your work!.

When everything looks good, you make the patch via:

cd BUILD
diff -Naur xephem-3.7.3-ORIG xephem-3.7.3 >xephem.patch
What ends up in the source RPM that you are building is the pristine tarball and your diff. You can have many diffs if you are that crazy (or if there is hackery from various sources that you want to keep segregated). What makes the most sense though is to apply all your diffs and hacking to your source tree and then generate just one diff that reflects the sum total of what needs to change and distribute that.

The spec file needs to indicate (in the %prep section) that your diff needs to be applied.

If you are the package author, there is no reason to have anything to do with diffs. You control the sources and can make the pristine sources do the right thing.

What about the spec file?

This very much is the heart of the matter. Someday I will have the insight and energy to write my own commentary on how to write and fiddle with a spec file.

Until then, perhaps the best thing to do is to grab the source RPM for some package that you think might be similar to what you want to work with and take a look at the spec file and/or use it as a starting point for what you want to do.

The rpmrebuild utility

This allows a certain amount of fiddling with an RPM without actually rebuilding it or even having access to the source RPM. You type
rpmrebuild -ep package.rpm
This in my case launched the "vim" editor with what looked a lot like a condensed spec file for me to edit. I was able to delete and modify dependencies and change the name of the RPM. Then when I exit the editor session, it rebuilds the rpm. Curiously, it places the result into my usual RPM build area, but it tells you the full path where it places it, so all that is necessary is to pay attention. It seemed to work great to fix a dependency issue for a package that was impossible to rebuild from the source RPM for various reasons.

debuginfo packages

Somewhere along the way, rpmbuild began spitting out "debuginfo" packages. (This seemed to happen in late 2008 with the advent of Fedora 9). Although these now get generated, I have never been sure why or what they are all about. Here is the story.

The Gnu debugger (gdb) was enhanced to allow debugging information to be read from separate files (it used to be the case that an executable had to be specially built with certain compiler switches to include debug information). The rpmbuild program (actually the RPM macros) has been set up to generate this information and place it into a separate "debuginfo" package whenever a package is built. Details about how this is done may be found in the files in /usr/lib/rpm, in particular /usr/lib/rpm/find-debuginfo.sh.

This behavior can be suppressed by adding the following to your ~/.rpmmacros file:

%debug_package %{nil}
(The string %define debug_package %{nil} is mentioned in some documentation, but that is apparently in error).

symbol stripping

So, I have a package (namely ds9) for which the distributor provides a single file (a binary executable). My idea is to set up an RPM that just encapsulates that single binary file. The problem is that rpmbuild by default strips symbols (as part of the new debuginfo scheme I suppose), and this executable does not work once that is done. Don't ask me why it doesn't work, it just complains about not finding tcl files and gives up -- the unstripped version just works. So the question is how to make rpmbuild stop stripping. I have found two recommendations:
%define __strip /bin/true
This fix is the least intrusive and is probably the best. Another fellow redefined a larger macro as follows:
%define __spec_install_port /usr/lib/rpm/brp-compress
This eliminates more than just the stripping, just how much more you can evaluate by inspecting the unmolested value of this macro via:
rpm --eval %__spec_install_post

Yum repositories

These days, the end result of all of this is to dump your collection of RPMS into a Yum repository. It is almost, but not quite sufficient to just create a directory, dump the rpms in there, and put it on the web. The extra part is:
cd /repodir
createrepo .
This creates the all important repodata file, which is a bunch of XML describing the repository.

Note that yum seems to cache information for some amount of time. If you modify a package, put the new version in your repository, do the createrepo thing to rebuild your repodata, then try to update a machine, it may frustrate you by insisting your package is up to date when you know it is not. What will solve this is:

yum clean metadata

You can use the big hammer and do yum clean all, but this may be overkill (or not). Overkill does have it's place, and sometimes caching sucks.


More information

There are a some good tutorials out there.
Here are some:

There are also some books. an ancient classic (but still quite useful) is the book: Maximum RPM. As of 2009, many inexpensive used copies are available, other than that it is out of print.


Have any comments? Questions? Drop me a line!

Adventures in Computing / [email protected]