Packaging software with RPM, Part 1

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.

A simple case

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:


Building indent manually

$ tar xzf indent.2.2.6.tar.gz
$ cd indent-2.2.6
$ ./configure
$ make
$ make install

 

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.

Making a basic RPM package

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:

  1. Create the file indent-1.spec as shown below. You can name it anything and put it anywhere; RPM doesn't care.
  2. Log in as root
  3. Copy the indent-2.2.6.tar.gz file to /usr/src/redhat/SOURCES.
  4. Run rpm -ba indent-1.spec, changing indent-1.spec to the name you used.

 


First spec file: indent-1.spec

Summary: GNU indent
Name: indent
Version: 2.2.6
Release: 1
Source0: %{name}-%{version}.tar.gz
License: GPL
Group: Development/Tools
%description
The GNU indent program reformats C code to any of a variety of
formatting standards, or you can define your own.
%prep
%setup -q
%build
./configure
make
%install
make install
%files
%defattr(-,root,root)
/usr/local/bin/indent
%doc /usr/local/info/indent.info
%doc %attr(0444,root,root) /usr/local/man/man1/indent.1
%doc COPYING AUTHORS README NEWS

 

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.

What RPM does

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

 

What's in the spec file

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.



Back to top



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
Name: indent
Version: 2.2.6
Release: 2
Source0: %{name}-%{version}.tar.gz
License: GPL
Group: Development/Tools
BuildRoot: %{_builddir}/%{name}-root
%description
The GNU indent program reformats C code to any of a variety of
formatting standards, or you can define your own.
%prep
%setup -q
%build
./configure
make
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
/usr/local/bin/indent
%doc /usr/local/info/indent.info
%doc %attr(0444,root,root) /usr/local/man/man1/indent.1
%doc COPYING AUTHORS README NEWS

 

Explanation of changes

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.

What happens this time

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.



Back to top



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.



Back to top



What's next

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

 


Resources


About the author

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值