This is a short hands-on tutorial on writing RPM files, suitable for an impatient person who wants to quickly step up to create very simple source and binary software packages. I assume familiarity with using pre-made RPM packages, and with the FOSS software building process.
For more information on how to create RPM files, including more detailed tips, see How to create an RPM package.
This tutorial demonstrates packaging of the GNU "Hello World" project. While 'Hello World" is a trivial program, the GNU project contains most of the usual peripheral components associated with a typical FOSS software distribution, including the configuration/build/install environment, documentation, internationalization, etc. As you will see, it's a reasonable vehicle to practice building RPMs on.
I wrote this tutorial when I worked through Christoph Wickert's IRC class on building RPMs using Rahul Sundaram suggestion of GNU "Hello World" as a test case. After I wrote up my experience, I found out about the excellent and extensive How to create an RPM package page on this wiki, as well as the Christian Lyder Jacobsen's website. However, Christian told me he isn't planning to update his site, and I think a 5-minute 'fast food' alternative to the more extensive article might suit some people. More in-depth information on using and building RPM packages is available from other sources.
Development environment
To build RPMs we need a set of development tools. This is a one-time-only setup,
installed by running those commands from a system administration (root
) account:
yum groupinstall development-tools yum install rpm-build rpmdevtools
If you want to test the build procedure in the context of Fedora anonymous package build system, you need to configure your non-privileged account to be a member of the 'mock' group:
usermod -a -G mock <yourAccountName>
Those are the only commands requiring root
privileges. All the remaining
work should be done from your regular, non-privileged account, or even from a separate
account created just for development work. Modern RPM-based
systems, including Fedora, are set up to build and test RPM packages purely from
within a non-privileged account. The command
rpmdev-setuptree
sets up a RPM build
area in your ~/rpmbuild
. This directory will contain several subdirectories,
for the project source code, RPM configuration files and for the resulting source and binary
packages.
Building a "Hello World" RPM
We need the source code of the project we are packaging, often referred
to as the 'upstream' source. We will download it from the project's website into the ~/rpmbuild/SOURCE
directory. We are getting the compressed tarball archive, which happens to be a preferred distribution form for
most FOSS projects.
cd ~/rpmbuild/SOURCE wget http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz
The RPM package is configured by .spec
files. We will create a template
file hello.spec
in the appropriate directory:
cd ~/rpm/SPECS rpmdev-newspec hello
Recent versions of Emacs
and vi
have .spec file editing modes which will
also bring up a similar template upon creating a new file.
Inside a .spec
file
The fields in our .spec
file need slight editing. Please follow the
Fedora rules
for these fields. In our case, the file might start as follows:
Name: hello Version: 2.5 Release: 1 Summary: The "Hello World" program License: GPLv3 URL: http://ftp.gnu.org/gnu/hello Source0: http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz %description: The "Hello World" program, done with all bells and whistles of a proper FOSS project, including configuration, build, internationalization, helpfiles, etc. %changelog * Tue Mar 30 2010 The Coon of Ty <Ty@coon.org> 2.5-1 - Initial version of the package
The Version
should mirror upstream while Release
numbers our work
within Fedora.
The first letter of the Summary
should be uppercase to avoid
rpmlint complaints.
It is your responsibility to check the License
status of the software, by
inspecting the source files and/or their LICENSE files, and/or by talking to the authors.
The Group
tag is being phased out, but it doesn't hurt to classify it
in accordance to the list in /usr/share/doc/rpm-4.6.0/GROUPS
.
The %changelog
should document the work on preparing the RPM , and should include the version string to avoid
rpmlint complains.
Multi-line sections like %changelog
or %description
start on a line under
the directive, and end with an empty line.
Lines which aren't needed (e.g. BuildRequires
and Requires
) can be commented out with a hash ('#') for now.
Many lines in the template don't need to be changed at all in many cases, at least for the initial attempt.
Building the package
We are ready for the first run to build source, binary and debugging packages:
rpmbuild -ba hello.spec
It will complain and list the unpackaged files, i.e. the files that would be
installed in the system that weren't declared as belonging to the package. We need to declare them in the
%files
section. Do not hardcode names like
/usr/bin/
, but use macros, like %{_bindir}/hello
instead.
The manual pages should be declared in the %doc
subsection:
%doc %{_mandir}/man1/hello.1.gz
.
This is an iterative process: after editing the .spec
file, rerun rpmbuild.
Since our program uses translations and internationalization, we are getting a lot of undeclared i18 files. The recommended method: to declare them is:
- find the filenames in the
%install
step:%find_lang ${name}
- add the required build dependencies:
BuildRequires: gettext
- use the found filenames
%files -f ${name}.lang
If the program uses GNU info files, you need to make sure the installation and unistallation of the package does not interfere with other software on the system:
- delete the 'dir' file in %install:
rm -f $RPM_BUILD_ROOT/usr/share/info/dir
Requires(post): info
andRequires(preun): info
- add those steps:
%post /sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || : %preun if [ $1 = 0 ] ; then /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || : fi
A complete hello.spec
file
Here's the initial version of hello.spec
:
Name: hello Version: 2.5 Release: 1%{?dist} Summary: The "hello world" program from GNU Group: Applications/Text License: GPLv3 URL: http://ftp.gnu.org/gnu/hello Source0: http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: gettext # Requires: Requires(post): info Requires(preun): info %description The "hello world" program from GNU, with bells and whistles %prep %setup -q %build %configure make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %find_lang %{name} rm -f $RPM_BUILD_ROOT/usr/share/info/dir %post /sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || : %preun if [ $1 = 0 ] ; then /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || : fi %clean rm -rf $RPM_BUILD_ROOT %files -f %{name}.lang %defattr(-,root,root,-) %{_bindir}/hello %doc %{_mandir}/man1/hello.1.gz %doc %{_infodir}/%{name}.info.gz %changelog * Tue Mar 30 2010 The Coon of Ty <Ty@coon.org> 2.5-1 - Initial version of the package
With this spec file, you should be able to successfully complete the build process, and create the source and binary RPM packages.
Next you should check them for conformance with RPM design
rules, by running rpmlint
on the spec file and all RPMs:
rpmlint hello.spec ../SRPMS/hello* ../RPMS/*/hello*
If there are no warnings or errors, we've succeeded. Otherwise,
append the error messages to the rpmlint -I
command to see a more verbose description of the rpmlint
diagnostics.
The mock
builds
To check that the package build will succeed in the Fedora restricted build environment, check it with mock.
mock -r fedora-12-i386 --rebuild ../SRPMS/hello-2.5-1.fc12.src.rpm