RPM is a widely used tool for delivering software for Linux. Users can easily install an RPM-packaged product. In this article, the first in a series, IBM software engineer Dan Poirier shows you how to use RPM to package simple software on a Red Hat Linux 7.1 system.
RPM (Red Hat Package Manager) is the most common software package manager used for Linux distributions. Because it allows you to distribute software already compiled, a user can install the software with a single command.
RPM is the designated install tool of the Linux Standard Base version 1.0.0. And eight of the top 10 Linux distributions are RPM based (see the "Comparison of Linux Distributions" at distrowatch.com listed in Resources later in this article). Even some distributions that don't use RPM normally, like Debian, have tools available to convert RPMs to their own format. RPM is also the best choice for packaging software to be used on Linux by anyone other than developers.
Whether you've developed the software yourself, or you want to help an open source project by contributing the code to build an RPM package from it, this article will help you get started. Future articles in this series, by the way, will cover topics like building RPMs without having to be the root user, patching the software before building it, running scripts during install and uninstall, and running scripts when other packages are installed or uninstalled.
I'll start with a simple case, using mostly RPM default values. Then I'll add a few optional features.
An RPM software package begins with a program in source form, ready to compile. Rather than creating a toy example, I've chosen to use the GNU Indent program (see Resources).
Indent builds pretty easily under Linux. With the indent-2.2.6.tar.gz file in the current directory, all you do is:
$ tar xzf indent.2.2.6.tar.gz |
This probably looks familiar if you've built many open source projects. The unpack; ./configure; make; make install
sequence is typical of software that uses GNU's autoconf tools. Because this is so common, most of what I describe here for indent will work with few changes for many other open source projects.
I'll assume for now you're using Red Hat 7.1. Later in this article, I'll give some suggestions for using RPM on other Linux distributions.
On Red Hat 7.1, be sure you have installed the rpm-build package before you continue. To check, run rpm -q rpm-build
. You should see something like rpm-build-4.0.2-8
(the version might be different). If instead, you see package rpm-build is not installed
, you'll need to install it from your Red Hat install CDs.
To build an RPM package, you need to write an input file for RPM, called a spec file, which tells RPM how to build and package your software. To write a spec file:
- Create the file indent-1.spec as shown below. You can name it anything and put it anywhere; RPM doesn't care.
- Log in as root
- Copy the indent-2.2.6.tar.gz file to /usr/src/redhat/SOURCES.
- Run
rpm -ba indent-1.spec
, changing indent-1.spec to the name you used.
First spec file: indent-1.spec
Summary: GNU indent |
You should see RPM unpack the tar file, compile it, and install it. On Red Hat 7.1, the working directory will be /usr/src/redhat/BUILD.
At the end, RPM will create two RPM files. A source RPM file will be created in /usr/src/redhat/SRPMS/indent-2.2.6-1.src.rpm, and a binary RPM file in /usr/src/redhat/RPMS/i386/indent-2.2.6-1.i386.rpm.
The source RPM file is a simple bundling of your spec file and all the source and patch files that were using in building your package. If you choose to distribute this, other people can use it to easily rebuild your software. The binary RPM file contains only the compiled software and information on how to install it.
Here's a summary of what RPM does when you run rpm -ba filename.spec
:
- Read and parse the filename.spec file
- Run the
%prep
section to unpack the source code into a temporary directory and apply any patches - Run the
%build
section to compile the code - Run the
%install
section to install the code into directories on the build machine - Read the list of files from the
%files
section, gather them up, and create binary and source RPM files - Run the
%clean
section to remove the temporary build directory
The spec file has several sections. The first is unlabeled; the other sections start with lines like %prep
and %build
.
Headers
The first (unlabeled) section defines a variety of information in a format something like the headers of an e-mail message.
Summary
is a one-line description of the package.
Name
is the base name of the package, and Version
is the version number of the software. Release
is the version number of the RPM itself -- if you fix a bug in your spec file and release a new RPM of the same version of the software, you should increase the release number.
License
should give some indication of the licensing terms (such as "GPL", "Commercial", "Shareware").
Group
identifies the type of software; programs that try to help people manage their RPMs will usually list the RPMs by group. You can see a list of the groups used by Red Hat in the file /usr/share/doc/rpm-4.0.2/GROUPS (assuming your installed RPM version is 4.0.2). You are not restricted to those group names, though.
Source0
, Source1
, etc. name the source files (usually tar.gz files). %{name}
and %{version}
are RPM macros that expand to the rpm name and version defined in the headers, so in this case, Source0
gets set to indent-2.2.6.tar.gz
.
Don't include any paths in your Source
statements. RPM will look for the source files in /usr/src/redhat/SOURCES by default. Copy or link your source files there. (To make spec files as portable as possible, you should avoid embedding assumptions about your own development machine's paths. Other developers can tell RPM to look in other directories for source files without having to modify your spec file.)
Description
The next section starts with the %description
line. You should provide a longer description of the software here, which anyone using rpm -qi
to query your package will see. You can explain what the package does, describe any warnings or additional configuration instructions, etc.
Shell scripts
The next few sections are shell scripts embedded in the spec file.
%prep
is responsible for unpacking the package. In the most common case, you can just use the %setup
macro and it will do the right thing, unpacking the source tar files under the build directory. Adding the -q
option just reduces the output.
%build
should compile the package. The shell script is run from the software package's subdirectory, in the indent-2.2.6 directory in our case, so often this is a simple as running make
.
%install
should install the package on the build system. This might be as simple as make install
, but usually gets more complicated. I'll explain below.
File list
%files
lists the files that should be bundled into the RPM, and optionally sets permissions and other information.
Within %files
, you can use %defattr
once to define the default permissions, owner, and group; in this example, %defattr(-,root,root)
will install all the files owned by root, using whatever permissions they were found to have when RPM bundled them up from the build system.
You can override the owner and permission on individual files with %attr(permissions,user,group)
.
You can include multiple files per line in %files.
You can tag files by adding %doc
or %config
to the line. %doc
tells RPM that this is a documentation file, so that if a user installs the package using --excludedocs
, this file will not be installed. You can also list file names under %doc
without paths, and RPM will look for the files in the build directory and include them in the RPM file, to be installed in /usr/share/doc/%{name}-%{version}
. It is a good idea to include files like README and ChangeLog as %doc.
%config
tells RPM that this is a configuration file. During upgrades, RPM will attempt to avoid overwriting a user's carefully modified configuration with an RPM-packaged default configuration file.
Warning: If you list a directory name under %files, RPM will include every file under that directory. This is usually not what you want, especially for directories like /bin
.
![]() |
|
Avoiding problems with the simple case
There are several problems with the most basic spec file. One of the biggest is that you end up doing a real install of the product on your build system. This might be a test version of the software that you don't want in production on your build system.
RPM can handle this with a feature called the build root. The idea is to set up your spec file to copy all the installed files to a dummy directory tree, starting at the build root; then RPM gets the files from there.
This requires some support from the software package, though. In the case of many GNU software packages, including indent, defining DESTDIR
when you make install
will add the value of DESTDIR on the front of all the install paths.
Note that you don't want to use ./configure --prefix=$RPM_BUILD_ROOT
. That would build the entire package under the assumption that the final location of its files was the build root. It might not matter for indent, but any program that needs to locate its installed files at runtime would fail, because when your RPM is finally installed on a user's system, the files aren't under the build root anymore -- that's just a temporary directory on your build system.
See the updated file indent-2.spec as shown below.
Second spec file: indent-2.spec
Summary: GNU indent |
First, we increased our Release number. Don't forget to do this anytime you edit your spec file.
We've added BuildRoot to the header, to tell RPM that this is where the files will be temporarily installed during the build. We've used a couple of RPM macros here instead of assuming a particular location for temporary files. On Red Hat 7.1, %{_builddir}
ends up as something like /usr/src/redhat/BUILD
.
We also need to tell indent to install there. RPM helps us by defining a shell variable RPM_BUILD_ROOT
with the value of the build root, so we just pass this in as the value of DESTDIR when we make install
.
We've also added lines to %install and %clean to clean up the build root before we start installing (just in case), and when we're done. %clean is a script that gets run at the end of the RPM building, if everything works, so that your temporary files don't hang around forever.
Finally, in %files, notice that we do not include the BuildRoot on the fronts of the paths here. Use the "real" paths; RPM will look for the files under the build root because you included the BuildRoot
definition.
If you watch closely, everything should work the same until RPM gets to the install part. Then the files will not be installed directly in /usr/local/bin, for example, but instead in /usr/src/redhat/BUILD/indent-root/usr/local/bin.
If you examine the final binary RPM file (with rpm -qlp indent-2.2.6-2.i386.rpm
), you'll see that the build root has been removed by RPM. If you install the RPM, the files will end up in their proper directories, such as /usr/local/bin/indent.
![]() |
|
Using RPM on other Linux distributions
If you are using a different Linux distribution, RPM might have some different built-in paths. For example, it almost certainly will not look in /usr/src/redhat for source files! To determine what paths your installation of RPM expects, run rpm --showrc
and look to see how the following are defined:
-
_sourcedir
- Where RPM looks for source files (tar files, etc.) _srcrpmdir
- Where RPM puts new source RPM files _rpmdir
- Where RPM will put new binary RPM files (in an architecture-specific subdirectory)
Some of these are defined in terms of other variables; if you see, for example, %{_topdir}
, then look for the definition of _topdir
and so forth.
![]() |
|
I hope this introduction to packaging your software with RPM proves helpful to you. For related reading, see the Resources below. In future articles in this series, we'll cover these topics:
- Building RPMs without having to be the root user
- Patching the software before building it
- Running scripts during install and uninstall
- Running scripts when other packages are installed or uninstalled
- Source for files described in this article:
- The RPM Web site has pointers to many useful resources. The RPM e-mail list is a good place to ask questions.
- See which Linux distributions are RPM based in the "Comparison of Linux Distributions" at distrowatch.com. The RPM-based distributions include Red Hat, SuSE, Mandrake, TurboLinux, and Caldera.
- Get the GNU Indent program.
- Maximum RPM is a book about using RPM. It has become quite outdated, but an effort is now underway to update it.
- The RPM HOWTO is also getting somewhat dated. It covers some of the same ground as this article.
- Eric S. Raymond's Software Release Practice HOWTO document is not specific to RPM or Linux. It gives many good tips on releasing software in a way that makes it easy for users to use and programmers to contribute fixes and improvements.
- The Free Software Foundation is the source for GNU Indent and many other useful software packages.
- Get the IBM Developer Kit for Linux, Java 2 edition, version 1.3 or the IBM Software Evaluation Kit for Linux.
- Browse more Linux resources on developerWorks.
- Browse more Open source resources on developerWorks.
![]() | ||
![]() | Dan Poirier is an Advisory Software Engineer at IBM. He currently works in Research Triangle Park, North Carolina on network appliances that run Linux. Contact Dan at poirier@us.ibm.com |