Building an RPM

In this example, I build a patched cfengine 2.1.21 on a RHEL 4 system.

One of the tenets of RPM building is to never build as root. Building as root with an incorrect .spec file could, in the worst case, render the build system inoperable.

I will be building RPMs in ~/rpmbuild as my non-root user. If needed, create the RPM build directory structure, and modify ~/.rpmmacros to use the new directory structure instead of the default (e.g. /usr/src/redhat).

$ mkdir -p ~/rpmbuild/{BUILD,RPMS,S{OURCE,PEC,RPM}S}
$ echo -e "%_topdir\t$HOME/rpmbuild" >> ~/.rpmmacros

Because I am patching the pristine source, I extract the cfengine source twice in order to create the patch file for the RPM.

$ cp cfengine-2.1.21.tar.gz /tmp
$ cp cfengine-2.1.21.tar.gz ~/rpmbuild/SOURCES

$ cd /tmp
$ tar zxvf cfengine-2.1.21.tar.gz

$ mv cfengine-2.1.21 cfengine-2.1.21.orig
$ tar zxvf cfengine-2.1.21.tar.gz
$ cd cfengine-2.1.21/src

I make a modification to do.c.

$ awk 'NR != 2469 { print }; NR == 2469 { sub("cfinform","cfverbose") ; print }' do.c > do.c.new
$ mv do.c.new do.c

Since I've modified the pristine source, I create a patch. Patches should be placed in %{topdir}_SOURCES.

$ cd /tmp
$ diff -Naur cfengine-2.1.21.orig/ cfengine-2.1.21/ > ~/rpmbuild/SOURCES/cfengine-2.1.21.patch

I then create the .spec file.

cfengine.spec:

Summary: A configuration engine
Name: cfengine
Version: 2.1.21
Release: 1
Copyright: GPL
Group: Applications/System
Source: ftp://ftp.iu.hio.no/pub/cfengine/%{name}-%{version}.tar.gz
Patch0: %{name}-%{version}.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description
Cfengine, or the configuration engine is an autonomous agent and a middle to hi
gh level policy language and agent for building expert systems to administrate
and configure large computer networks. Cfengine is designed to be a part of a c
omputer immune system. It is ideal for cluster management and has been adopted
for use all over the world in small and huge organizations alike.

%prep
%setup -q
%patch -p1

%build
./configure --with-docs
make

%install
rm -rf $RPM_BUILD_ROOT
%makeinstall

%clean
rm -rf $RPM_BUILD_ROOT

I have not yet included a %files stanza in the .spec file. RPM will return a list of files that are installed but unpackaged (i.e. files to include in the %files stanza) when I attempt to build the package.

$ rpmbuild -bi cfengine.spec

A list of installed but unpackaged files will be displayed. To obtain this list of files:
$ rpmbuild -bl cfengine.spec 2>&1 | egrep '^[[:space:]]+/' | cut -c4- | sort | uniq
/usr/sbin/cfagent
/usr/sbin/cfconvert
/usr/sbin/cfdoc
/usr/sbin/cfenvd
/usr/sbin/cfenvgraph
/usr/sbin/cfetool
/usr/sbin/cfetoolgraph
/usr/sbin/cfexecd
/usr/sbin/cfkey
/usr/sbin/cfrun
/usr/sbin/cfservd
/usr/sbin/cfshow
/usr/share/cfengine/cfagent.conf-advanced.example
/usr/share/cfengine/cfagent.conf.example
/usr/share/cfengine/cf.chflags.example
/usr/share/cfengine/cfengine.el
/usr/share/cfengine/cf.freebsd.example
/usr/share/cfengine/cf.ftp.example
/usr/share/cfengine/cf.groups.example
/usr/share/cfengine/cf.linux.example
/usr/share/cfengine/cf.main.example
/usr/share/cfengine/cf.motd.example
/usr/share/cfengine/cf.preconf.example
/usr/share/cfengine/cfrc.example
/usr/share/cfengine/cfrun.hosts.example
/usr/share/cfengine/cfservd.conf.example
/usr/share/cfengine/cf.services.example
/usr/share/cfengine/cf.site.example
/usr/share/cfengine/cf.solaris.example
/usr/share/cfengine/cf.sun4.example
/usr/share/cfengine/cf.users.example
/usr/share/cfengine/ChangeLog
/usr/share/cfengine/doc/cfengine-Anomalies.pdf
/usr/share/cfengine/doc/cfengine-Anomalies.ps
/usr/share/cfengine/doc/cfengine-Reference.pdf
/usr/share/cfengine/doc/cfengine-Reference.ps
/usr/share/cfengine/doc/cfengine-Tutorial.pdf
/usr/share/cfengine/doc/cfengine-Tutorial.ps
/usr/share/cfengine/html/cfengine-Anomalies.html
/usr/share/cfengine/html/cfengine-Reference.html
/usr/share/cfengine/html/cfengine-Tutorial.html
/usr/share/cfengine/INSTALL
/usr/share/cfengine/NEWS
/usr/share/cfengine/README
/usr/share/cfengine/update.conf.example
/usr/share/info/cfengine-Anomalies.info.gz
/usr/share/info/cfengine-Reference.info-1.gz
/usr/share/info/cfengine-Reference.info-2.gz
/usr/share/info/cfengine-Reference.info.gz
/usr/share/info/cfengine-Tutorial.info.gz
/usr/share/info/dir
/usr/share/man/man8/cfagent.8.gz
/usr/share/man/man8/cfengine.8.gz
/usr/share/man/man8/cfenvd.8.gz
/usr/share/man/man8/cfenvgraph.8.gz
/usr/share/man/man8/cfetoolcheck.8.gz
/usr/share/man/man8/cfetoolcreate.8.gz
/usr/share/man/man8/cfetooldump.8.gz
/usr/share/man/man8/cfetoolgraph.8.gz
/usr/share/man/man8/cfetoolimport.8.gz
/usr/share/man/man8/cfetoolinfo.8.gz
/usr/share/man/man8/cfetoolupdate.8.gz
/usr/share/man/man8/cfexecd.8.gz
/usr/share/man/man8/cfkey.8.gz
/usr/share/man/man8/cfrun.8.gz
/usr/share/man/man8/cfservd.8.gz
/usr/share/man/man8/cfshow.8.gz

I populated the %files stanza based on the list above.

%files
/usr/sbin/cfagent
/usr/sbin/cfconvert
/usr/sbin/cfdoc
/usr/sbin/cfenvd
/usr/sbin/cfenvgraph
/usr/sbin/cfetool
/usr/sbin/cfetoolgraph
/usr/sbin/cfexecd
/usr/sbin/cfkey
/usr/sbin/cfrun
/usr/sbin/cfservd
/usr/sbin/cfshow
%doc /usr/share/cfengine/*
%doc /usr/share/info/*
%doc /usr/share/man/man8/*

I then build the source and binary RPMs.

$ rpmbuild -ba cfengine.spec

More information:
RPM Tutorial
[freshrpms.net] - The fight
Packaging software with RPM, Part 1
Packaging software with RPM, Part 2
Packaging software with RPM, Part 3
RPM HOWTO
Better Living Through RPM, Part 2

Back to brandonhutchinson.com.

Last modified: 2007/07/26