RPM Tutorial

T.R. Fullhart

Revision History
Revision A09 Sep 2002trf
Revised with help of John Stile, also described the purpose of some of the sections in a .spec file.
Revision B06 Oct 2003trf
Revision C27 May 2005trf
Updated bibliography links and switched to DocBook 4.1.2 and using xmlto to process.

Table of Contents

Setting up the RPM build environment
Configuring your ~/.rpmmacros
Creating your build directories
Package Configuration
For Previously Released Tarballs
For Inclusion in Autoconf'd Packages
Building the RPMS
Checking your RPMS
Getting and installing rpmlint
Setting up ~/.rpmlintrc
Using rpmlint
Bibliography

Distributing binary packages of your software is an excellent way to get exposure. The more exposure that your project gets, the more interest there will be in the project, and hopefully that will attract developers.

In this document, I will discuss how to prepare RPM packages. I don't have any special love for RPMs. Packages are packages as far as I'm concerned, but I'm more familiar with making RPMs so I will cover those first. In later documents, I will cover Debian packages, apt-get, and the FreeBSD ports collection.

Setting up the RPM build environment

This is how to create the RPM build directories and how to setup your ~/.rpmmacros.

For more information see [IBMRPM2] and [FRFIGHT].

Configuring your ~/.rpmmacros

Put something similiar to the following in a file called .rpmmacros in your home directory:

%packager      T.R. Fullhart <kayos@genetikayos.com>
%vendor        Name of your project

%_topdir       /home/kayos/rpm

The .rpmmacros file is used by rpmbuild to provide defaults. You may find references to the .rpmrc file, but it has been deprecated in favor of this file.

The first 2 lines will add information to each RPM package you build so others can know who made the package

The last line is so you can build packages as a user. It's not good practice to build packages as root.

Creating your build directories

In order to build packages as a user, you will also need to create build directories. By default, rpm will expect to find and use the following directories:

%{_topdir}/BUILD
%{_topdir}/RPMS
%{_topdir}/RPMS/i386
%{_topdir}/SOURCES
%{_topdir}/SPECS
%{_topdir}/SRPMS

You will need to manually create the directories. For example, on my machine I use the example .rpmmacros file above. I set %_topdir to /home/kayos/rpm, so I had to run the following commands to create the build tree:

mkdir /home/kayos/rpm/BUILD
mkdir /home/kayos/rpm/RPMS
mkdir /home/kayos/rpm/RPMS/i386
mkdir /home/kayos/rpm/SOURCES
mkdir /home/kayos/rpm/SPECS
mkdir /home/kayos/rpm/SRPMS

Package Configuration

For more information on making .spec files and RPMs, check out the bibliography at the end of this document for some great links and examples.

For Previously Released Tarballs

Making an RPM for software that comes as a tarball and uses the ./configure and make conventions is easy.

Put your .spec file in the SPECS subdirectory that you created in the previous section. Put your tarball in the SOURCES subdirectory.

I'll cover the major sections in the .spec file, but the key sections that actually build the software in an RPM are the %build, %install, and %files sections.

The %prep section is where you unpack your sources so you can do the build. In the sample below, I use the %setup macro. The %setup macro uses the Source: line at the top of the file to find a file in the SOURCES directory. Then it unpacks the file into the BUILD directory. The %setup macro is smart, it knows how to unpack .tar, .zip, .bz2, and .gz files.

In the %build section, you usually want to run something like ./configure and then make.

In the sample I have below, it checks to see if the configure script exists, and if it doesn't, it runs ./autogen.sh, a shell script that was included in the package that, in turn, runs Autoconf to regenerate the configure script.

Also notice that I passed --prefix=%{_prefix} to ./configure. That is so you can adjust whether you want the package installed in /usr, /opt, or /usr/local by changing the Prefix: line near the top of the .spec file.

In the %install script, you usually just run something like 'make install', but you have to somehow make it install to the directory pointed to by $RPM_BUILD_ROOT, that's where RPM will look for the files that it puts into the RPM package. In the sample I have below, I pass DESTDIR=$RPM_BUILD_ROOT. For Makefiles that are generated by Automake, DESTDIR overrides where it installs to.

Sample .spec file

%define name skstream
%define version 0.2.2
%define release 1

Summary: Portable C++ classes for IP(sockets) applications.
Name: %{name}
Version: %{version}
Release: %{release}
Source: ftp://ftp.worldforge.org/pub/worldforge/libs/%{name}-%{version}.tar.gz
Vendor: The WorldForge Project
URL: http://www.worldforge.org/
License: LGPL
Group: System Environment/Libraries
Prefix: %{_prefix}

%description
This library contains C++ utility classes for using IP(sockets).

%package devel
Summary: Libraries, includes to develop applications with %{name}.
Group: Development/Libraries
Requires: %{name} = %{version}

%description devel
The %{name}-devel package contains the header files and static libraries for
building applications which use %{name}.

%prep
%setup -q

%build
if [ -x ./configure ]; then
  CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix}
else
  CFLAGS="$RPM_OPT_FLAGS" ./autogen.sh --prefix=%{_prefix}
fi
make

%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install

%clean
rm -rf $RPM_BUILD_ROOT

%post -p /sbin/ldconfig

%postun -p /sbin/ldconfig

%files
%defattr(-,root,root)
%doc AUTHORS ChangeLog COPYING INSTALL NEWS README TODO
%{_prefix}/lib/lib*.so.*

%files devel
%defattr(-,root,root)
%doc AUTHORS ChangeLog COPYING INSTALL NEWS README TODO
%{_prefix}/bin/*-config
%{_prefix}/lib/lib*.a
%{_prefix}/lib/lib*.so
%{_prefix}/include/*
%{_prefix}/share/aclocal/*

%changelog
* Thu Mar 7 2002 T.R. Fullhart <kayos@kayos.org>
- First draft of the spec file

For Inclusion in Autoconf'd Packages

GNU Autotools is being widely adopted by open-source software, including the WorldForge Project, so that makes building RPM packages very easy. Basically, it's just like doing it from a tarball, but you can use autoconf to fill in some of the blanks in your .spec file so you don't have to maintain it very much between releases.

Sample .spec.in file

Change configure.in.

Rerun ./autogen.sh.

Run ./configure

Make a dist, make dist.

Building the RPMS

Put the sources and patches in the SOURCES directory and then run rpm -ba package.spec. Rpm will use the spec to figure out how to unpack and build the package and then it will dump a binary RPM in RPMS/i386 and a source RPM in SRPMS.

Or, if you have a tarball will a .spec file in it, run rpm -ta package.tar.gz. Rpm will extract the .spec file from the inside of the tarball, put the tarball in the SOURCES directory, and then it will start building just as above.

Checking your RPMS

It's important that your RPM packages comply with certain conventions and standards because, hopefully, you want your package to work on a variety of systems. You can use a program called rpmlint to check your binary packages for commonly overlooked errors.

Getting and installing rpmlint

rpmlint homepage

Setting up ~/.rpmlintrc

The configuration file of rpmlint is actually a small Python program to set some variables. You won't need to learn Python to configure rpmlint, it's fairly easy. You can find a bit of documentation with rpmlint, but here is what my ~/.rpmlintrc file looks like:

from Config import *

setOption("Vendor", "The WorldForge Project")
setOption("Packager", "T.R. Fullhart <kayos@kayos.org>")
setOption("Distribution", None)

Using rpmlint

rpmlint package.i386.rpm

Bibliography

[IBMRPM1] Dan Poirier. Packaging Software with RPM, Part 1.

[IBMRPM2] Dan Poirier. Packaging Software with RPM, Part 2.

[IBMRPM3] Dan Poirier. Packaging Software with RPM, Part 3.

[RPMHOWTO] Donnie Barnes. RPM HOWTO: RPM at Idle.

[MAXRPM] Edward Bailey. Maximum RPM.