Tips & Tricks: The RPM Packager Manager [RPM] -- Revisited


A few months ago, we gave you a quick look at basic RPM commands. But how is an RPM built? It all begins with the SPEC file. A what file? We'll explain all that, and maybe a bit more. The package information tags, such as the name of the package, and the build sections; such as the commands to compile the software.

The following sections summarize the spec file syntax.

Package Information Tags

The package information tags contain most of the header tags that you can query with the rpm command. First and foremost, this includes a name.

The name-epoch-version-release tags, which form the NEVR used to identify packages, should all appear in your spec file, although you can skip the Epoch tag.

Name: name

# Epoch: 1
Version: version_number

Release: package_release_number

The optional Epoch tag provides an ordering for the version numbers (replacing the deprecated Serial tag). Use this tag if RPM cannot figure out the ordering of which release comes after another.

Epoch: 42

A number of tags allow you to define who made the package and under what conditions has the package been released:

Vendor: name_of_vendor

URL: URL_to_package_home
Copyright: package_copyright_message
Distribution: Linux_or_product_distribution
Packager: John Q. Smith <john.smith@somecompany.yow>

Group: group_for_categorizing_package

Use the Group tag to help users categorize your package.

The Icon tag allows you to provide a desktop icon for the package:

Icon: filename.xpm

A one-line summary is essential to tell users what your package is for:

Summary: one_line_description_of_package

You should also include a longer description section, marked by %description:

%description

Tcsh is an enhanced but completely compatible version of csh, the C
shell.  Tcsh is a command language interpreter which can be used both
as an interactive login shell and as a shell script command processor.
Tcsh includes a command line editor, programmable word completion,
spelling correction, a history mechanism, job control and a C language

like syntax.

In the description section, blank lines indicate paragraphs. Lines that start with a space are not formatted.

Comments

To help document your work, you can include comments (to yourself and others reading the spec file). Any line starting with a hash character, #, holds a comment. RPM will ignore comments.

# This is a comment.

In spec files, comments are used mostly to help explain your syntax choices to yourself should you view the spec file later.


Note

Avoid using percent signs (%) in comments. They may get interpreted as RPM macros. See Chapter 10 for details.


Build settings

The BuildArchitectures tag names the architectures that a binary RPM will run on. See Chapter 21 for a description of the architecture settings. A special value of noarch indicates a package that is not dependent on a particular architecture, such as a Perl or Python script.

The BuildPreReq tag lists any prerequisites for building. For example:

BuildPreReq: ncurses-devel

The Buildroot tag names the temporary directory in which to build the package. For example:

Buildroot: %{_tmppath}/%{name}-root

Dependency tags

Dependency tags define all the dependencies for the package, as described in Chapter 6.

For each dependency, you can specify a capability name alone. For example:

Provides: capability_name

You can also provide a particular version number or indicate that your package has a dependency on a version larger or smaller than a given number. For example:

Requires: capability_name >= version_number

Requires: capability_name <= version_number
Requires: capability_name > version_number
Requires: capability_name < version_number
Requires: capability_name == version_number

Requires: capability_name = version_number

The ==and = act the same for dependencies. Both check for a version equal to the given number. You can provide multiple items, separated by commas. For example:

Requires: python >= 1.3, perl

For add-on modules for interpreters, especially Perl, you can use the following syntax to define capabilities:

Provides: perl(MIME-Base64)

This example provides the MIME-Base64 add-on Perl module.

You can also use or to specify more than one possibility. For example:

perl(IO-Wrap) == 4.5 or perl(IO-Wrap)-4.5

The Provides, Requires, Obsoletes, and Conflicts dependency tags all work the same for capability names and version numbers.


Note

You can also specify BuildRequires tags for capabilities necessary to build the package, not to install it. A BuildConflicts tag names capabilities that conflict for building, such as a particular version of the gcc C compiler.


Source files

The source and patch tags identify the source files used to build the binary package. The patch tags identify any patches used to modify the sources.

If you have more than one of a particular kind of tag, append a number. For example:

Source0: ftp://ftp.uk.linux.org/pub/linux/telnet-%{telnet_version}.tar.gz

Source2: telnet-client.tar.gz
Source3: telnet-xinetd
Source4: telnet.wmconfig
Patch1: telnet-client-cvs.patch
Patch5: telnetd-0.17.diff
Patch6: telnet-0.17-env.patch
Patch7: telnet-0.17-issue.patch
Patch8: telnet-0.17-sa-01-49.patch
Patch9: telnet-0.17-env-5x.patch

Patch10: telnet-0.17-pek.patch

Macros

You can define macros in your spec files to help control how the package gets built. The following section describes these macros.

Variable definition macros

The %define macro allows you to define new macros from within your spec file. A common usage is to define top-level directories with %define macros at the top of a spec file and then reference these directories throughout the file. For example:

%define _bindir /bin

This allows you to change the setting in one place, which is very handy for directory paths used throughout your spec files.


Cross Reference

See the section "Defining Macros in Spec Files" in Chapter 21 for more on this subject.


You can use this syntax for other things that may commonly change, such as version numbers. For example:

%define major 2

%define minor 2
%define patchlevel 7

Version: %{major}.%{minor}.%{patchlevel}

Table B-1 lists more special macros used within spec files.

TABLE B-1 SPECIAL SPEC FILE MACROS

Macro

Usage

%dump

Prints out macro values

%{echo:message}

Prints message to stderr

%{error:message}

Prints message to stderr and returns BADSPEC

%{expand:expression}

Like eval, expands expression

%{F:file_exp}

Expands file_exp to a file name

%global name value

Defines a global macro

%{P:patch_exp}

Expands patch_exp to a patch file name

%{S:source_exp}

Expands source_exp to a source file name

%trace

Toggles the printing of debugging information

%{uncompress:filename}

Tests if file filename is compressed. If so, uncompresses and includes in the given context. If not compressed, calls cat to include file in given context.

%undefine macro

Undefines the given macro

%{warn:message}

Prints message to stderr

Conditional macros

You can use a special syntax to test for the existence of macros. For example:

%{?macro_to_test: expression}

This syntax tells RPM to expand the expression if macro_to_test exists, otherwise ignore. A leading exclamation point, !, tests for the non-existence of a macro:

%{!?macro_to_test: expression}

In this example, if the macro_to_test macro does not exist, then expand the expression.

The %if macro performs an if test much like scripting languages. For example:

%if %{old_5x}

%define b5x 1
%undefine b6x

%endif

A %else allows you to specify what to do if the test is not successful. For example:

%if %{old_5x}

%define b5x 1
%undefine b6x
%else
%define b6x 1
%undefine b5x

%endif

Again, use an exclamation point to negate the test. For example:

%if ! %{old_5x}

%define b5x 1
%undefine b6x

%endif

You can use a && for an and test. For example:

%if %{old_5x} && %{old_6x}

%{error: You cannot build for .5x and .6x at the same time}
%quit

%endif

Built-in macros

The following macros are built into RPM and can help allow you to place your files in the right locations:

%_prefix /usr

%_exec_prefix     %{_prefix}
%_bindir          %{_exec_prefix}/bin
%_sbindir         %{_exec_prefix}/sbin
%_libexecdir      %{_exec_prefix}/libexec
%_datadir         %{_prefix}/share
%_sysconfdir      %{_prefix}/etc
%_sharedstatedir  %{_prefix}/com
%_localstatedir   %{_prefix}/var
%_libdir          %{_exec_prefix}/lib
%_includedir      %{_prefix}/include
%_oldincludedir   /usr/include
%_infodir         %{_prefix}/info

%_mandir %{_prefix}/man

Build Sections

After providing information about the package, you need to define the build stages, as described in Chapters 10 and 12.

Build preparation

The build preparation section sets the stage for the build. Usually this section has a %setup command. For example:

%prep

%setup -q

Build

The build section describes how to build the library or application. In most cases, the majority of the instructions are in the Makefile created by the prep section, leaving a build section something like the following:

%build

%configure

make

Installation

After building, the installation section holds the commands to install the library or application. For example:

%install

rm -rf %{buildroot}

%makeinstall

Clean up

The clean up section usually calls the make clean command to clean up the built files. For example:

%clean

rm -rf %{buildroot}

Install and uninstall scripts

RPM packages can run scripts prior to installation with %pre, and after installation with %post. You can also run scripts prior to an uninstall with %preun and after an uninstall with %postun. For example:

%post

/sbin/chkconfig --add ypbind
%preun
if [ "$1" = 0 ] ; then
    /sbin/service ypbind stop > /dev/null 2>&1
    /sbin/chkconfig --del ypbind
fi
exit 0
%postun
if [ "$1" -ge 1 ]; then
    /sbin/service ypbind condrestart > /dev/null 2>&1
fi

exit 0

File Tags

The %files tag lists the files your package should install. For example:

%files

%defattr(-,root,root)
/usr/X11R6/bin/xtoolwait

/usr/X11R6/man/man1/xtoolwait.*

You should mark configuration and documentation files with %config and %doc, respectively. For example:

%files

%defattr(-,root,root)
/sbin/ypbind
%{_mandir}/*/*
%config /etc/rc.d/init.d/*
%config /etc/yp.conf
%dir /var/yp
%dir /var/yp/binding

%doc README NEWS

Making relocatable packages

You can make a relocatable package by setting up one or more Prefix tags. For example:

Prefix: /usr

Prefix: /etc

Each file in the %files section must then start with one of the prefixes you provided. With this, installers can easily relocate the package with a command like the following:

# rpm --relocate /etc=/usr/etc file_name.rpm

The Change Log

The change log usually appears at the end of a spec file. It holds messages for each significant change. For example:

%changelog

* Fri Jun 21 2002 Bob Marley <marley@redhat.com>
- automated rebuild
* Tue May 08 2001 Peter Tosh <tosh@redhat.com> 1.3-1

- updated to 1.3