rpm-guide rpm-guide-customizing-rpm-en.xml,NONE,1.1
by fedora-docs-commits@redhat.com
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv434
Added Files:
rpm-guide-customizing-rpm-en.xml
Log Message:
--- NEW FILE rpm-guide-customizing-rpm-en.xml ---
<!-- $Id: -->
<chapter id="ch-customizing-rpm">
<title>Customizing RPM Behavior</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/).
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Defining RPM macros
</para>
<para>
*Configuring RPM settings
</para>
<para>
*Adding popt aliases
</para>
<para>
RPM provides a high degree of customization in the form of basic
settings, such as where your RPM database is located and the path to
common commands like setup or make, to the ability to define new
macros and command-line aliases. This chapter covers the three main
ways to customize RPM behavior: RPM macros, RPM rc settings, and
popt aliases.
</para>
<sect1>
<title>Customizing with RPM Macros</title>
<para>
Starting with RPM 3.0, RPM macros have replaced most RPM settings
from the rpmrc files.
</para>
<para>
An RPM macro defines a setting to the RPM system. A macro can be
defined as a static value, such as the directory where the RPM
database is installed. A macro can also be defined in terms of
other macros. Furthermore, a macro can be defined with parameters.
</para>
<para>
For example, the following defines two macros in a macro file:
</para>
<para>
%_usr /usr
</para>
<para>
%_usrsrc %{_usr}/src
</para>
<para>
In this case, the macro %_usr names the /usr directory. The macro
%_usrsrc names the /usr/src directory, showing how to set a macro
in terms of another macro.
</para>
<para>
Cross Reference
</para>
<para>
The macro syntax is used in the query formats introduced in
Chapter 5.
</para>
<sect2>
<title>Defining macros</title>
<para>
RPM provides a number of places you can define macros, including
inside spec files (probably the most common usage), in special
macro initialization files, and on the command line.
</para>
<para>
In each case, the syntax is slightly different.
</para>
<sect3>
<title>Defining Macros in Spec Files</title>
<para>
You can define macros in most places in a spec file. With spec
files, use the %define syntax to define a macro, which uses
the following syntax:
</para>
<para>
%define name(options) body
</para>
<para>
The options are optional and can include the special values
defined in Table 21-1.
</para>
<para>
Table 21-1 Special options for macros
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Option
</para>
</entry>
<entry>
<para>
Holds
</para>
</entry>
</row>
<row>
<entry>
<para>
%0
</para>
</entry>
<entry>
<para>
The name of the macro
</para>
</entry>
</row>
<row>
<entry>
<para>
%1
</para>
</entry>
<entry>
<para>
The first argument, after processing with getopt
</para>
</entry>
</row>
<row>
<entry>
<para>
%2-%9
</para>
</entry>
<entry>
<para>
Additional arguments
</para>
</entry>
</row>
<row>
<entry>
<para>
%*
</para>
</entry>
<entry>
<para>
All arguments, except for flags that have been
processed
</para>
</entry>
</row>
<row>
<entry>
<para>
%#
</para>
</entry>
<entry>
<para>
Number of arguments
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
These options are similar to those for shell scripting.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 10 covers spec files.
</para>
<para>
In addition to these options, you can use a syntax of %{-a} to
hold ���a if an option of ���a was passed. The syntax of
%{-a*} indicates the value passed after the ���a option.
</para>
<para>
You can assign a macro to the value returned by a shell
command by using syntax like the following:
</para>
<para>
%(shell_command)
</para>
<para>
Note
</para>
<para>
This is similar to the $(shell_command) syntax supported by
bash.
</para>
</sect3>
<sect3>
<title>Defining Macros in Macro Initialization Files</title>
<para>
Inside a macro file, define macros with the following syntax:
</para>
<para>
%macro_name value
</para>
<para>
Macros defined for the RPM system start with an underscore.
Some older macros are left without the leading underscore.
</para>
<para>
Note
</para>
<para>
The macros defined with an underscore are not exported into
rpm headers.
</para>
<para>
The %expand built-in macro will expand the value of something
else, including executing a shell command. For example, the
following sets the user���s home directory to the %home macro:
</para>
<para>
%home %{expand:%%(cd; pwd)}
</para>
<para>
Note that it is probably easier to simply set the %home macro
in your per-user $HOME/.rpmmacros file to the name of your
home directory rather than try to figure this out
programmatically.
</para>
</sect3>
<sect3>
<title>Defining Macros on the Command Line</title>
<para>
The rpm command also lets you define macros with the --define
option. The basic syntax is:
</para>
<para>
$ rpm --define 'macro_name value'
</para>
<para>
Note
</para>
<para>
Do not place the leading percent sign, %, on the macro you
define with --define.
</para>
<para>
You can evaluate a macro or a macro expression with --eval.
For example:
</para>
<para>
$ rpm --eval %_usrsrc
</para>
<para>
/usr/src
</para>
</sect3>
</sect2>
<sect2>
<title>Customizing Macros</title>
<para>
You can add your own macro definitions, using the syntax shown
in the ���Defining Macros in Macro Initialization Files���
section. These macros are read on each invocation of the rpm or
rpmbuild commands.
</para>
<para>
To add your custom macros, you must edit one of the macro
definition files. Table 21-2 lists the macro definition files
and their usage.
</para>
<para>
Table 21-2 RPM macro files
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
File
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
/usr/lib/rpm/macros
</para>
</entry>
<entry>
<para>
Official RPM macros
</para>
</entry>
</row>
<row>
<entry>
<para>
/etc/rpm/macros
</para>
</entry>
<entry>
<para>
Per-system customizations
</para>
</entry>
</row>
<row>
<entry>
<para>
$HOME/.rpmmacros
</para>
</entry>
<entry>
<para>
Per-user customizations
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Note
</para>
<para>
Do not edit the /usr/lib/rpm/macros file, as this file gets
overwritten when you upgrade to a new version of rpm.
</para>
</sect2>
</sect1>
<sect1>
<title>Configuring RPM Settings</title>
<para>
RPM includes hundreds of settings based on your current system
architecture, environment, and which version of the RPM system you
have installed. The old settings, called rc or rpmrc settings, are
gradually being phased out by the newer, more consistent and more
powerful macros.
</para>
<para>
You can still edit the rc settings, but in most cases you should
edit macros instead.
</para>
<sect2>
<title>Viewing the current settings</title>
<para>
To view the current settings, use the --showrc command-line
option:
</para>
<para>
$ rpm ���showrc
</para>
<para>
ARCHITECTURE AND OS:
</para>
<para>
build arch : i386
</para>
<para>
compatible build archs: i686 i586 i486 i386 noarch
</para>
<para>
build os : Linux
</para>
<para>
compatible build os's : Linux
</para>
<para>
install arch : i686
</para>
<para>
install os : Linux
</para>
<para>
compatible archs : i686 i586 i486 i386 noarch
</para>
<para>
compatible os's : Linux
</para>
<para/>
<para>
RPMRC VALUES:
</para>
<para>
macrofiles :
/usr/lib/rpm/macros:/usr/lib/rpm/i686-linux/macros:/etc/
</para>
<para>
rpm/macros.specspo:/etc/rpm/macros.db1:/etc/rpm/macros.cdb:/etc/rpm/macros:/etc/
</para>
<para>
rpm/i686-linux/macros:~/.rpmmacros
</para>
<para>
optflags : -O2 -march=i686
</para>
<para>
This command displays the architecture and operating system
information first, and then lists all the rpmrc values, shown
here truncated for space.
</para>
</sect2>
<sect2>
<title>Locating the rpmrc files</title>
<para>
The --showrc option reads in all the rpmrc files from the
various locations. By default, this is /usr/lib/rpm/rpmrc,
/etc/rpm/rpmrc, and a file named .rpmrc (with a leading period)
in your home directory.
</para>
<para>
These files are read in the order given, so that the later files
can override settings in the earlier files.
</para>
<para>
The uses for these files are listed in Table 21-3.
</para>
<para>
Table 21-3 Uses for the rpmrc files
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
File
</para>
</entry>
<entry>
<para>
Holds
</para>
</entry>
</row>
<row>
<entry>
<para>
/usr/lib/rpm/rpmrc
</para>
</entry>
<entry>
<para>
RPM standard settings
</para>
</entry>
</row>
<row>
<entry>
<para>
/etc/rpm/rpmrc
</para>
</entry>
<entry>
<para>
Per-system configuration
</para>
</entry>
</row>
<row>
<entry>
<para>
$HOME/.rpmrc
</para>
</entry>
<entry>
<para>
Per-user configuration
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Note
</para>
<para>
The file /usr/lib/rpm/rpmrc gets overwritten each time you
upgrade RPM. Do not customize this file.
</para>
<para>
You can override this list of files by calling the rpm or
rpmbuild commands with the --rcfile option. This option expects
a semicolon@nddelimited list of files to read in, in order. For
example, if you are working on a 686-architecture Intel
platform, you can create a file with the following setting:
</para>
<para>
optflags: i686 -g
</para>
<para>
Note that this disables optimization, so it is not a good
setting. (The use of this value will make the result more
visible.)
</para>
<para>
If you name this file .rpmnew and place it in your home
directory, you can configure an alternate set of files with the
--rcfile option and then evaluate the new optflags setting. For
example:
</para>
<para>
$ rpm --eval "%{optflags}"
</para>
<para>
-O2 -march=i386 -mcpu=i686
</para>
<para>
$ rpm --rcfile $HOME/.rpmnew --eval "%{optflags}"
</para>
<para>
-g
</para>
<para>
This example shows the value before and after changing the
configuration files.
</para>
<para>
When you use the --rcfile option, only the first file listed
must exist. The rest of the files are optional. When you use the
--rcfile option, however, the file /usr/lib/rpm/rpmrc is read
first, and then the list of files you provide with the --rcfile
option. The file /usr/lib/rpm/rpmrc is always used.
</para>
</sect2>
<sect2>
<title>Changing settings</title>
<para>
You can edit the per-user or per-system rc files to change the
settings. The format of the rpmrc files is fairly simple but
contains a few exceptions. The most basic format is:
</para>
<para>
setting: value
</para>
<para>
The settings get more complicated as the rpmrc syntax supports
defining settings for multiple architectures at once. In that
case, the typical format is:
</para>
<para>
setting: uname: value
</para>
<para>
The uname portion is replaced by a value that comes from the
uname(2) system call, for example, i686 on a 686-class Intel
architecture machine.
</para>
<para>
Note
</para>
<para>
In most cases, your best bet is to copy an existing setting and
modify it, rather than remembering all the exceptions.
</para>
<sect3>
<title>Setting the optflags</title>
<para>
One exception to the rule is the optflags setting, which
controls C compiler options for optimization. The format for
the optflags setting is:
</para>
<para>
setting: arch value
</para>
<para>
There is no colon after the architecture. For example:
</para>
<para>
optflags: i686 -O2 -march=i686
</para>
<para>
optflags: alphaev5 -O2 -mieee -mcpu=ev5
</para>
<para>
This example sets the optimization flags for an i686 system to
-O2 -march=i686 and an alphaev5 system to -O2 -mieee
-mcpu=ev5. If your system is running on a 686-class processor,
you will get one set of optimization flags. If your system is
running on a V5 Alpha processor, you will get a different set.
</para>
</sect3>
<sect3>
<title>Setting the Architecture Values</title>
<para>
The arch_canon setting builds up a table of mappings between
architecture names and the numbers used internally. The
following example shows the Intel and SPARC architecture
settings to 1 and 3 internally.
</para>
<para>
arch_canon: athlon: athlon 1
</para>
<para>
arch_canon: i686: i686 1
</para>
<para>
arch_canon: i586: i586 1
</para>
<para>
arch_canon: i486: i486 1
</para>
<para>
arch_canon: i386: i386 1
</para>
<para/>
<para>
arch_canon: sparc: sparc 3
</para>
<para>
arch_canon: sun4: sparc 3
</para>
<para>
arch_canon: sun4m: sparc 3
</para>
<para>
arch_canon: sun4c: sparc 3
</para>
<para>
arch_canon: sun4d: sparc 3
</para>
<para>
arch_canon: sparcv9: sparcv9 3
</para>
<para>
The arch_compat setting builds a table of compatible
architectures. The format is:
</para>
<para>
arch_compat: arch: compatible_with
</para>
<para>
This sets the given architecture arch as being compatible with
another architecture.
</para>
<para>
For example:
</para>
<para>
arch_compat: athlon: i686
</para>
<para>
This setting indicates that an athlon architecture is
compatible with an i686. The table gets built up further with
the following Intel-architecture compatibilities:
</para>
<para>
arch_compat: i686: i586
</para>
<para>
arch_compat: i586: i486
</para>
<para>
arch_compat: i486: i386
</para>
<para>
arch_compat: i386: noarch
</para>
<para>
The os_canon setting defines a table of operating system
labels and internal numeric values. The basic syntax is:
</para>
<para>
os_canon: arch: name value
</para>
<para>
The arch comes from the uname(2) call. The name provides an
RPM name for that operating system, and the value defines an
internal numeric ID for that OS, for example:
</para>
<para>
os_canon: Linux: Linux 1
</para>
<para>
os_canon: HP-UX: hpux10 6
</para>
<para>
The buildarchtranslate setting defines the operating system
settings to use as the build architecture. This value
translates information from the uname(2) call to a value used
by the arch_canon setting. For example:
</para>
<para>
buildarchtranslate: athlon: i386
</para>
<para>
buildarchtranslate: i686: i386
</para>
<para>
buildarchtranslate: i586: i386
</para>
<para>
buildarchtranslate: i486: i386
</para>
<para>
buildarchtranslate: i386: i386
</para>
<para/>
<para>
buildarchtranslate: sun4c: sparc
</para>
<para>
buildarchtranslate: sun4d: sparc
</para>
<para>
buildarchtranslate: sun4m: sparc
</para>
<para>
buildarchtranslate: sparcv9: sparc
</para>
<para>
buildarchtranslate: sun4u: sparc64
</para>
</sect3>
</sect2>
</sect1>
<sect1>
<title>Adding Popt Aliases</title>
<para>
Popt provides a powerful library and RPM subsystem for handling
the very complex RPM command-line options. You can customize your
RPM usage by defining popt aliases for complex command-line
arguments to the rpm or rpmbuild commands. A popt alias is a
command-line option that expands to other command-line options.
</para>
<para>
This technique is used internally to define quite a few
command-line options to the rpm and rpmbuild commands in terms of
other, more complex options. Many of these aliases define simple
command-line options in place of more complex query format
options.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 5 covers the query format.
</para>
<para>
For example, the following entry defines the --requires and ���R
command-line options to the rpm command:
</para>
<para>
rpm alias --requires --qf \
</para>
<para>
"[%{REQUIRENAME} %{REQUIREFLAGS:depflags} %{REQUIREVERSION}\n]" \
</para>
<para>
--POPTdesc=$"list capabilities required by package(s)"
</para>
<para>
rpm alias -R --requires
</para>
<para>
These options are set in the file /usr/lib/rpm/rpmpopt-4.1.
</para>
<para>
Note
</para>
<para>
This is specific to RPM 4.1. Other releases of RPM use the same
naming format but with the current RPM version number, such as 4.2
and so on.
</para>
<sect2>
<title>Defining aliases</title>
<para>
Defining aliases is pretty easy. The basic syntax is:
</para>
<para>
command_name alias option expansion
</para>
<para>
To create an alias for the rpm command, you use rpm for the
command_name.
</para>
<para>
Note
</para>
<para>
The command_name must be the name passed to the C poptGetContext
function, covered in Chapter 16.
</para>
<para>
Follow this with alias and then the option. You will need
separate aliases for the long and short options. The expansion
defines the alias in terms of other already-defined command-line
parameters.
</para>
<para>
You can define some complex aliases, such as the following one
to display information about a package:
</para>
<para>
rpm alias --info --qf 'Name : %-27{NAME} Relocations:
%|PREFIXES?{[%{PREFIXES} ]}:{(not relocateable)}|\n\
</para>
<para>
Version : %-27{VERSION} Vendor: %{VENDOR}\n\
</para>
<para>
Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}\n\
</para>
<para>
Install date: %|INSTALLTIME?{%-27{INSTALLTIME:date}}:{(not
installed) }| Build Host: %{BUILDHOST}\n\
</para>
<para>
Group : %-27{GROUP} Source RPM: %{SOURCERPM}\n\
</para>
<para>
Size : %-27{SIZE}%|LICENSE?{ License: %{LICENSE}}|\n\
</para>
<para>
Signature :
%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\n\
</para>
<para>
%|PACKAGER?{Packager : %{PACKAGER}\n}|\
</para>
<para>
%|URL?{URL : %{URL}\n}|\
</para>
<para>
Summary : %{SUMMARY}\n\
</para>
<para>
Description :\n%{DESCRIPTION}\n' \
</para>
<para>
--POPTdesc=$"list descriptive information from package(s)"
</para>
<para>
Popt aliases get evaluated into Linux commands, so you can use
pipes and other aspects of Linux shells in your aliases.
</para>
<para>
Cross Reference
</para>
<para>
Look closely at the examples in the /usr/lib/rpm/rpmpopt-4.1
file. This is the most complete set of popt alias examples for
RPM commands.
</para>
<para>
You can also define aliases that can set RPM macros, such as the
following alias for setting the path to the RPM database:
</para>
<para>
rpm alias --dbpath --define '_dbpath !#:+'
</para>
<para>
In this example, !#:+ was defined to behave like a shell
history-editing command. With popt, this means to grab the next
command-line parameter and place it into the command defined for
the alias.
</para>
<para>
To support the --help and --usage options, you can define the
--POPTdesc and --POPTargs options to the alias as shown in the
previous examples. These options also support
internationalization.
</para>
<para>
All together, the popt alias setting is very close to the popt
option table entries used with the C programming API.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 16 shows how to program with the popt library.
</para>
</sect2>
<sect2>
<title>Customizing popt aliases</title>
<para>
Like RPM macros and settings, popt aliases are defined in a
cascading set of files. The official RPM aliases are defined in
/usr/lib/rpm/rpmpopt-4.1 for rpm 4.1.
</para>
<para>
Note
</para>
<para>
Do not modify this file! The RPM system depends on this file for
proper functioning. Incorrect changes might disable many options
to the rpm command.
</para>
<para>
Store per-system popt aliases in /etc/popt. Store per-user
aliases in $HOME/.popt (with a leading period).
</para>
<para>
Note
</para>
<para>
These files are shared by all applications that use popt.
</para>
<para>
For example, you can define an alias for rpm -qa that executes
faster than the normal query all packages command, by turning
off the tests for digest signature verification. To do so, add
the following line to a file named .popt in your home directory:
</para>
<para>
rpm alias --qall -qa --nodigest --nosignature
</para>
<para>
Once you set up this alias, you can run the following command in
place of rpm -qa:
</para>
<para>
$ rpm --qall
</para>
<para>
This should execute about one-third to one-half faster than the
normal rpm -qa command.
</para>
<para>
Warning
</para>
<para>
Turning off the signature and digest tests means you are
ignoring important information that pertains to the integrity of
your system. That is why the alias shown here does not override
the normal -qa option, and instead defines a new --qall option
</para>
</sect2>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter shows the many ways you can customize RPM usage for
your system or your own personal environment. You can define RPM
macros, which is the preferred way to make RPM settings. Or you
can set RPM values in the older rpmrc files, which are now mostly
replaced by RPM macros.
</para>
<para>
Using popt, the powerful command-line option parser, you can
define aliases to add simple options that popt expands into
whatever you define. Many of the rpm command-line options are
defined this way.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
18 years, 6 months
rpm-guide rpm-guide-creating-rpms-en.xml,NONE,1.1
by fedora-docs-commits@redhat.com
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv405
Added Files:
rpm-guide-creating-rpms-en.xml
Log Message:
--- NEW FILE rpm-guide-creating-rpms-en.xml ---
<!-- $Id: -->
<chapter id="ch-creating-rpms">
<title>Creating RPMs: An Overview</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/).
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Preparing to build RPMs
</para>
<para>
*Planning for RPMs
</para>
<para>
*Explaining the build process
</para>
<para>
*Using build files
</para>
<para>
*Seeing the results
</para>
<para>
*Verifying your RPMs
</para>
<para>
Thus far in this book, all the commands presented have been used to
manage or query packages. With this chapter, though, you start
creating RPMs of your own. Even if you do not produce applications
on your own, you may want to create RPM packages out of software you
use, if only for the ease of management that the RPM system
provides.
</para>
<para>
Creating RPMs allows you to create a consistent set of applications
for use on all systems in your organization and easily manage those
applications. You may create RPMs of applications developed in house
or RPMs of applications developed elsewhere that you need to
customize for your environment. Making RPMs of the customized
applications reduces work and makes the customizations consistent.
</para>
<para>
This chapter introduces the RPM system from the point of view of
creating RPMs and demonstrates the steps and planning necessary to
make your own packages. As such, this chapter introduces the
RPM-building topics covered in depth in the remaining chapters in
this part.
</para>
<sect1>
<title>Preparing to Build RPMs</title>
<para>
The RPM-building task starts with gathering all the material you
want to bundle into an RPM package and then defining the RPM
directives to make your package. The final steps are to build and
test an RPM. This sounds easy, and for the most part it is fairly
straightforward.
</para>
<para>
The main problems arise when you try to define the many RPM
directives for your package. In addition, some of the elements in
an RPM can be complex, such as upgrade scripts.
</para>
<para>
The main tasks in building RPMs are:
</para>
<para>
1.Planning what you want to build
</para>
<para>
2.Gathering the software to package
</para>
<para>
3.Patching the software as needed
</para>
<para>
4.Creating a reproducible build of the software
</para>
<para>
5.Planning for upgrades
</para>
<para>
6.Outlining any dependencies
</para>
<para>
7.Building the RPMs
</para>
<para>
8.Testing the RPMs
</para>
<para>
The sections in this chapter cover the initial planning stages and
provide an overview of the process of building RPMs. The remaining
chapters in Part II go in depth into the process of building RPMs.
</para>
<sect2>
<title>Planning what you want to build</title>
<para>
The first step in the entire RPM-building process is simply to
decide exactly what you want to make into an RPM. Is this an
application, a programming library, a set of system
configuration files, or a documentation package? If this is an
application, is it customized or patched? Think these issues
over and decide what you want to package as an RPM.
</para>
<para>
In most cases, you want to create both a source package and a
binary package containing the built sources. You need a binary
package because that holds the RPM you want to install on other
systems. You need the source package so you can recreate the
binary package at any time. And, if the sources get updated, you
can quickly make a new binary RPM from the updated sources if
you have already defined a source RPM.
</para>
<para>
Most packages start with a source RPM, although you have the
option to skip making a source RPM. It is a good idea to make
the source RPM, however, because it makes it easier to reproduce
the final binary RPM. Once of the key goals of the RPM system is
to allow for reproducible builds, and making source RPMs is just
one step to help towards this goal.
</para>
<para>
Creating a source RPM also allows you to transfer the entire set
of sources for a package to another system, since the source RPM
is just one file and it contains all the program sources along
with the instructions, called a spec file, for building the
binary RPM. Furthermore, creating a source RPM makes it easier
to create binary RPMs on different processor architectures or
different versions of Linux.
</para>
<para>
Note
</para>
<para>
Not all programs are portable to multiple-processor
architectures. But many Linux programs can simply be recompiled
on another architecture to make a binary program for that
architecture. That's because there are a lot of common APIs for
Linux applications and because most programs are not processor
dependent. This is not true of all programs, so your mileage may
vary.
</para>
<para>
Source packages are not that hard to make, and they provide a
single package, and single file, that holds all the sources
necessary to build your binary package. In addition, once you
have a source RPM, it is very easy to build a binary RPM.
</para>
<para>
Binary packages are likely the real reason you want to make an
RPM. You can package an application, a programming library, or
almost anything you want. Armed with a binary RPM, you can
transfer one file to another machine and install the application
there, taking full advantage of the RPM system.
</para>
</sect2>
<sect2>
<title>Gathering the software to package</title>
<para>
Whether you are writing your own software or merely packaging
software found elsewhere, the next step is to gather the
software you want to bundle into an RPM. This includes the
applications or libraries you want to package, as well as the
program source code.
</para>
<para>
In general, you���ll be doing one of three things:
</para>
<para>
*Packaging your own software
</para>
<para>
*Packaging someone else���s software
</para>
<para>
*Packaging someone else���s stuff after first customizing or
patching the software
</para>
<para>
In all cases, you need to gather the software together and
decide whether you want everything to go into one bundle or a
number of bundles.
</para>
<para>
As covered in Chapter 2, a major tenet of the philosophy behind
RPM is to start with pristine���unmodified--sources. You may
need to patch or customize the sources for your environment, but
you can always go back to the original sources.
</para>
<para>
Starting with pristine sources provides a number of advantages,
including the following:
</para>
<para>
*You clearly separate any changes you have made to the software
from the original software.
</para>
<para>
*You make it easier to get an upgrade of the original sources,
since your changes are cleanly separated from the original
sources. With each new release of the software, you can
determine which of your changes, if any, are still needed. This
is especially important if you are packaging an application
created by another organization into an RPM.
</para>
<para>
*You have a reproducible way to recreate everything in the
package. Since you start with unmodified sources, you can always
go back to the beginning of the process and start again. Thus,
your RPMs don���t depend on any actions taken beforehand, such
as patching, that you may later forget to do because the steps
are not automated as part of the RPM-building process.
</para>
<para>
Start with pristine sources; then patch as needed. A patch is an
automated set of modifications to the source code. Use the diff
command to build a patch and the patch command to apply the
patch (that is, to modify the source code). Keep the original
sources separate from any patches you need to make the software
work in your environment.
</para>
<para>
Cross Reference
</para>
<para>
See the online manual pages for the patch and diff commands for
more information on how to create and apply a patch.
</para>
</sect2>
<sect2>
<title>Creating a reproducible build of the software</title>
<para>
The RPM system will automate the steps to create an application,
as long as you configure the RPM with the proper steps, such as
which make targets to run. Unfortunately, configuring the proper
steps is not always easy. So before trying to make an RPM, you
need to figure out how to build the application or library you
plan to package into an RPM. Once you have figured out how to
build the application or library, you can set up a reproducible
build. The RPM system can then automate this build.
</para>
<para>
To build the software, you���ll need to use a variety of Linux
tools. The specific tools you need depend largely on where the
original software came from. The following sections outline some
of the more common techniques for preparing and building Linux
software.
</para>
<sect3>
<title>Unpacking Software</title>
<para>
Many applications are downloaded in compressed tar format,
often called a tarball. A tarball is merely an archive file
built by the tar command that has been compressed, usually
using the gzip command.
</para>
<para>
In most cases, these files have a name such as the following:
</para>
<para>
filename.tar.gz
</para>
<para>
filename.tgz
</para>
<para>
filename.tar.Z
</para>
<para>
For the first two cases, use the gunzip command to unzip the
file; then use the tar command to extract the file, for
example:
</para>
<para>
$ gunzip filename.tgz
</para>
<para>
$ tar xf filename.tar
</para>
<para>
Note
</para>
<para>
In the case of a file name ending in .Z, use the uncompress
program instead of gunzip.
</para>
<para>
Once you have unpacked the sources, start looking around at
the files.
</para>
</sect3>
<sect3>
<title>Reading the README</title>
<para>
Many applications come with a very handy file named README, or
something similar, such as README.txt. As the name implies,
you should read this file. The README file answers some of the
most common questions about a particular application.
</para>
<para>
Note
</para>
<para>
You really should read any file named README or any variant of
README.
</para>
<para>
Other useful files include those named INSTALL or some close
variant. Read these files, too. Usually, the README or the
INSTALL file will tell you what you need to do to build the
software.
</para>
<para>
Once you have extracted the source code files and read all the
available documentation, the next step is to build, usually
compile, the application or library.
</para>
</sect3>
<sect3>
<title>Building Programs with Linux Build Tools</title>
<para>
Most applications or libraries need to be built into
executable programs or compiled archived libraries. This
process of building can be as simple as just compiling, but is
usually more involved. Most Linux applications and libraries
use a build tool called make to manage the building of the
source code and creation of the executable programs. The make
command uses a file, normally named Makefile, that contains
the rules for building the software. You will usually find a
Makefile in each directory in the source code
</para>
<para>
Each Makefile contains a set of targets that define things
that make can build. Each target defines the commands to run
to build a particular thing (make targets are purely
arbitrary, although some conventions are usually followed).
Some combination of the targets results in a built
application. The make program runs the targets that you
specify on the command line, or the Makefile rules indicate it
needs to run based on the targets you specify on the command
line.
</para>
<para>
You need to tell make the target to build the application or
library you want to package into an RPM. Each target is
defined within the Makefile. The conventional make targets to
build and install a program are:
</para>
<para>
make
</para>
<para>
make install
</para>
<para>
When you call the make command without the name of a target,
make builds the default target, named all. This target usually
compiles the program or library. The install target should
install the program.
</para>
<para>
Note
</para>
<para>
The names of these make targets are conventions shared by many
but not all programs. Other common targets include clean,
which should clean up any files built.
</para>
<para/>
<para>
The commands in the Makefile may be specific to a given
system. For example, the traditional command for compiling C
programs is cc, short for C Compiler. You may have the gcc
command (GNU C Compiler) instead. The options passed to the C
compiler may differ depending on the architecture of the
system. Other commands may exist but be located in different
locations. SuSE Linux, for example, puts a lot of programs in
/opt.
</para>
<para>
Note
</para>
<para>
These system-dependent issues mostly apply to various versions
of Unix. Most modern Linux systems are fairly similar. Because
many packages, such as sendmail, have a long UNIX history,
you���ll find all sorts of complications in the Makefiles or
many Makefiles provided with many applications. If we could
just convince everyone to give up all non-Linux operating
systems, this task would be much simpler.
</para>
<para>
Because the Makefiles are platform specific, a number of tools
have been developed to create the proper Makefile, usually by
running a program that knows about your system's architecture.
The simplest of these tools is the manual approach. You may
download a program and find files such as Makefile.amiga,
Makefile.solaris, and Makefile.linux. You need to copy the
file for your system architecture to the name Makefile.
</para>
<para>
The following sections discuss other tools for creating
Makefiles.
</para>
<para/>
<sect4>
<title>imake</title>
<para>
A program called imake is used mostly for X Window graphical
applications, and typically older X Window applications. The
imake command uses a file named Imakefile that contains
rules used to build a platform-specific Makefile. This
allows X Window applications, which run on many
architectures and operating systems, to come with fairly
generic build scripts.
</para>
<para>
When you see an Imakefile, use the following general set of
commands to compileand install an application:
</para>
<para>
$ xmkmf
</para>
<para>
$ make
</para>
<para>
$ make install
</para>
<para>
These commands work for most X Window applications. The
xmkmf command is a script that runs the imake command to
create a Makefile. If the xmkmf command is not available or
if this command does not work, you may need to run a command
such as the following:
</para>
<para>
make Makefile
</para>
<para>
Or, if there are multiple directories of source code, try
the following command:
</para>
<para>
make Makefiles
</para>
<para>
Cross Reference
</para>
<para>
For more on imake, see www.dubois.ws/software/imake-stuff/.
</para>
</sect4>
<sect4>
<title>The configure script</title>
<para>
Most Linux programs, especially server-side or command-line
programs, use a script called configure. The configure
script outputs a platform-specific Makefile.
</para>
<para>
If you see a script named configure in the source files, try
the following commands to build and install the program:
</para>
<para>
$ ./configure
</para>
<para>
$ make
</para>
<para>
$ make install
</para>
<para>
The ./configure command runs the script in the local
directory, which outputs a Makefile configured for your
system. The make command builds the program and the make
install command installs the program.
</para>
<para>
The configure script is created by a set of tools including
automake and autoconf, which use generic files usually named
configure.in and makefile.am, among other files, to create
the generic configure script.
</para>
<para>
In many cases, you���ll need to pass parameters to the
configure script. One of the most common parameters is
--prefix, which tells the configure script the name of the
starting directory from which to base all other paths. This
is the root directory for building the application.
</para>
<para>
Cross Reference
</para>
<para>
For more on the configure system, autoconf, and automake,
see www.airs.com/ian/configure/.
</para>
</sect4>
<sect4>
<title>Building Perl modules</title>
<para>
Perl is a scripting language used heavily on Linux systems,
especially by administrators. Most Perl modules and packages
use the following set of commands to create a
system-specific Makefile and to build the module:
</para>
<para>
$ perl Makefile.PL
</para>
<para>
$ make
</para>
<para>
$ make test
</para>
<para>
$ make install
</para>
<para>
If you see a file named Makefile.PL, chances are these are
the commands to run to build the application or module.
</para>
<para>
The goal of all these steps is to figure out how to make a
reproducible build of the application or library you want to
package in RPM format. Once you have a build, the next step
is to plan for upgrades.
</para>
</sect4>
</sect3>
</sect2>
<sect2>
<title>Planning for Upgrades</title>
<para>
Any application or library you package in RPM format is likely
to get upgraded sometime. When this happens, you���ll need to
make a new RPM. This new RPM must handle not only installing the
package, but also handling any upgrade issues. You need to think
about the following issues:
</para>
<para>
*How to install the RPM for the new version of the software. Are
there any necessary install scripts?
</para>
<para>
*How to remove the previous RPM package. If your package has an
install script, then you may need an uninstall script to cleanly
remove any changes made to the system by the install script. The
RPM system handles the removal of the files in the package. You
need to handle the task of undoing any changes made to the
system during installation.
</para>
<para>
At this point in time, the main effort is to keep these issues
in mind and plan ahead, since these issues will come up with any
upgrade.
</para>
</sect2>
<sect2>
<title>Outlining Any Dependencies</title>
<para>
Often, the hardest task is getting make to build a program
properly. One potential problem is assuring that all the
dependencies are included. As you work with make, keep track of
any other libraries that the program you are trying to build
requires. These libraries will become dependencies when you get
to the stage of making the RPM.
</para>
<para>
In most cases you do not want to include the dependencies in
your RPM. Instead, each dependency should have its own RPM for
each necessary library. In many cases, you should be able to
find RPMs for these dependencies. Keep track of the packages
that provide the dependencies.
</para>
<para>
After you have built the application, planned for upgrades and
outlined dependencies, you can make an RPM.
</para>
</sect2>
</sect1>
<sect1>
<title>Building RPMs</title>
<para>
In previous chapters, just about everything you want to do with
RPMs is accomplished with the rpm command. Building RPMs is one
exception. Just about everything you want to do to build an RPM is
done by the rpmbuild command, often with a single command.
</para>
<para>
Warning
</para>
<para>
Older RPM manuals refer to using the ���b option to the rpm
command to create RPMs. Don���t use that option. Instead, always
use the rpmbuild command. The reason for this change is that
starting with version 4.1, RPM no longer maps the rpm -b command
to the real command, rpmbuild.
</para>
<para>
When building RPMs, go through the following steps:
</para>
<para>
1.Set up the directory structure.
</para>
<para>
2.Place the sources in the right directory.
</para>
<para>
3.Create a spec file that tells the rpmbuild command what to do.
</para>
<para>
4.Build the source and binary RPMs.
</para>
<para>
The following sections provide details for these steps.
</para>
<sect2>
<title>Setting up the directory structure</title>
<para>
The RPM system expects five directories, as listed in Table 9-1.
</para>
<para>
Table 9-1 RPM directories
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Directory
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
BUILD
</para>
</entry>
<entry>
<para>
The rpmbuild command builds software in this
directory.
</para>
</entry>
</row>
<row>
<entry>
<para>
RPMS
</para>
</entry>
<entry>
<para>
The rpmbuild command stores binary RPMs it creates in
this directory.
</para>
</entry>
</row>
<row>
<entry>
<para>
SOURCES
</para>
</entry>
<entry>
<para>
You should put the sources for the application in this
directory.
</para>
</entry>
</row>
<row>
<entry>
<para>
SPECS
</para>
</entry>
<entry>
<para>
You should place the spec file for each RPM you plan
to make in this directory.
</para>
</entry>
</row>
<row>
<entry>
<para>
SRPMS
</para>
</entry>
<entry>
<para>
The rpmbuild command places source RPMs in this
directory.
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
The RPMS directory usually has a number of architecture-specific
subdirectories, such as the following (on an Intel architecture
system):
</para>
<para>
$ ls RPMS
</para>
<para>
athlon
</para>
<para>
i386
</para>
<para>
i486
</para>
<para>
i586
</para>
<para>
i686
</para>
<para>
noarch
</para>
<para>
By default, Red Hat Linux systems expect RPMs to be built in the
/usr/src/redhat directory.
</para>
<para>
Note
</para>
<para>
This directory is obviously specific to Red Hat Linux. On other
Linux distributions, you'll likely see other directories.
</para>
<para>
Within the /usr/src/redhat directory, you���ll see the
subdirectories listed in Table 9-1, as follows:
</para>
<para>
$ ls /usr/src/redhat
</para>
<para>
BUILD
</para>
<para>
RPMS
</para>
<para>
SOURCES
</para>
<para>
SPECS
</para>
<para>
SRPMS
</para>
<para>
At first, it seems rather odd to be using a system directory to
build RPMs. But remember that the RPM system was originally
built to create Linux distributions. You can also change the
default directories by modifying your rpmrc settings.
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 21 for more on the use of the rpmrc settings.
</para>
<para>
For now, it is easiest to just change to the /usr/src/redhat
directory and work from this location. To start, you will need
to change ownership or permissions on these files so you can
build RPMs while logged in as a normal user.
</para>
<para>
Warning
</para>
<para>
Do not build RPMs while logged in as root. Mistakes in building
packages can have serious consequences if you are logged in as
root.
</para>
<para>
To build RPMs, you really need only two things:
</para>
<para>
*Your sources in the SOURCES directory
</para>
<para>
*Your spec file in the SPECS directory
</para>
</sect2>
<sect2>
<title>Placing your sources into the directory structure</title>
<para>
You can place all the source files directly in the
/usr/src/redhat/SOURCES directory. In most cases, however, it is
easier to create a tarball of the sources you want to build and
place the tarball file in the /usr/src/redhat/SOURCES directory.
The RPM specifications for commands necessary to extract the
sources from such a file are trivial. Furthermore, the tarball,
when extracted, should create a subdirectory specific to your
package. This keeps your source code separate from other
packages that also have source code in the SOURCES directory.
</para>
<para>
The best strategy is to start in a directory of your own making,
create the tarball file from the sources, and then copy the
tarball file to the /usr/src/redhat/SOURCES directory.
</para>
<para>
The convention for these tarball files is
package-version.tar.gz. For example:
</para>
<para>
jikes-1.17.tar.gz
</para>
<para>
Place a file like this into the /usr/src/redhat/SOURCES
directory. This file should include all the sources, all the
build scripts, and any documentation you want to install as part
of the package.
</para>
</sect2>
<sect2>
<title>Creating the spec file</title>
<para>
The spec file, short for specification file, defines all the
actions the rpmbuild command should take to build your
application, as well as all the actions necessary for the rpm
command to install and remove the application. Each source RPM
should have the necessary spec file for building a binary RPM.
</para>
<para>
The spec file is a text file. The normal naming convention is to
name the file with the package name and a .spec filename
extension. For example, the jikes package spec file would be
named jikes.spec.
</para>
<para>
Inside the spec file, format the information on the package
using a special syntax. This syntax defines how to build the
package, version numbers, dependency information, and everything
else you can query about a package. This syntax differs slightly
depending on the sections in the spec file. The following
sections describe these spec file sections and the necessary
syntax in each section.
</para>
<sect3>
<title>The introduction section</title>
<para>
The introduction section contains information about the
package, the type of information shown with the rpm -qi
command. For example:
</para>
<para>
Summary: java source to bytecode compiler
</para>
<para>
%define version 1.17
</para>
<para>
Copyright: IBM Public License,
http://ibm.com/developerworks/oss/license10.html
</para>
<para>
Group: Development/Languages
</para>
<para>
Name: jikes
</para>
<para>
Prefix: /usr
</para>
<para>
Provides: jikes
</para>
<para>
Release: 1
</para>
<para>
Source: jikes-%{version}.tar.gz
</para>
<para>
URL: http://ibm.com/developerworks/opensource/jikes
</para>
<para>
Version: %{version}
</para>
<para>
Buildroot: /tmp/jikesrpm
</para>
<para/>
<para>
%description
</para>
<para>
The IBM Jikes compiler translates Java source files to
bytecode. It
</para>
<para>
also supports incremental compilation and automatic makefile
generation,
</para>
<para>
and is maintained by the Jikes Project:
</para>
<para>
http://ibm.com/developerworks/opensource/jikes/
</para>
<para>
In this example, you can see the Source: definition of a
compressed tar archive associated with a particular version
number. This also names a Buildroot: setting that defines
where the files will get built into a working program. You can
see the description of the package that will get printed with
the rpm ���qi command.
</para>
<para>
Note
</para>
<para>
You can further divide this first section into the preamble
and other areas. For simplicity, I grouped all introductary
parts of a spec file into one introduction section.
</para>
<para>
This example comes from a real-world RPM spec file. It does
not follow all the rules for creating RPMs. This example:
</para>
<para>
*Should not explicitly provide jikes, the name of the package.
</para>
<para>
*Should not include a Copyright tag, as this tag is
deprecated.
</para>
<para>
*Uses a %define for the version when the rpmbuild command can
create a version macro for you.
</para>
</sect3>
<sect3>
<title>The prep section</title>
<para>
The prep section, short for prepare, defines the commands
necessary to prepare for the build. If you are starting with a
compressed tar archive (a tarball) of the sources, the prep
section needs to extract the sources.
</para>
<para>
For example:
</para>
<para>
%prep
</para>
<para>
%setup -q
</para>
<para>
The prep section starts with a %prep statement.
</para>
<para>
This example uses the %setup RPM macro, which knows about tar
archives, to extract the files. In most cases, this will be
all you need in your spec file prep section.
</para>
</sect3>
<sect3>
<title>The build section</title>
<para>
The spec file build section contains the commands to build the
software. Usually, this will include just a few commands,
since most of the real instructions appear in the Makefile.
For example:
</para>
<para>
%build
</para>
<para>
./configure CXXFLAGS=-O3 --prefix=$RPM_BUILD_ROOT/usr
</para>
<para>
make
</para>
<para>
The build section starts with a %build statement.
</para>
<para>
The commands shown for this build section run the configure
script, covered in the previous section on Linux build tools,
and then run the make command with the default maketarget. If
things unfold as they should, this procedure builds the
software.
</para>
</sect3>
<sect3>
<title>The install section</title>
<para>
The spec file install section holds the commands necessary to
install the newly built application or library. In most cases,
your install section should clean out the Buildroot directory
and run the make install command. For example:
</para>
<para>
%install
</para>
<para>
rm -fr $RPM_BUILD_ROOT
</para>
<para>
make install
</para>
<para>
The install section starts with an %install statement.
</para>
</sect3>
<sect3>
<title>The clean section</title>
<para>
The clean section cleans up the files that the commands in the
other sections create:
</para>
<para>
%clean
</para>
<para>
rm -rf $RPM_BUILD_ROOT
</para>
<para>
The clean section starts with a %clean statement
</para>
</sect3>
<sect3>
<title>The files section</title>
<para>
Finally, the files section lists the files to go into the
binary RPM, along with the defined file attributes. For
example:
</para>
<para>
%files
</para>
<para>
%defattr(-,root,root)
</para>
<para>
/usr/bin/jikes
</para>
<para>
%doc /usr/doc/jikes-%{version}/license.htm
</para>
<para>
%doc /usr/man/man1/jikes.1*
</para>
<para>
The files section starts with a %files statement
</para>
<para>
The %doc macro marks certain files as documentation. This
allows the RPM to distinguish the files holding documentation
from the other files in the RPM.
</para>
<para>
Cross Reference
</para>
<para>
This example skips the install and uninstall script sections,
as well as a verification section. There are also no triggers
defined in this RPM spec file. All of these topics are covered
in Chapters 10 and 11.
</para>
<para>
Once you have written your spec file, and placed the files in
the SOURCES and SPECS directories under /usr/src/redhat,
you���ll see files like the following:
</para>
<para>
$ ls ���CF /usr/src/redhat/*
</para>
<para>
/usr/src/redhat/BUILD:
</para>
<para/>
<para>
/usr/src/redhat/RPMS:
</para>
<para>
athlon/ i386/ i486/ i586/ i686/ noarch/
</para>
<para/>
<para>
/usr/src/redhat/SOURCES:
</para>
<para>
jikes-1.17.tar.gz
</para>
<para/>
<para>
/usr/src/redhat/SPECS:
</para>
<para>
jikes.spec
</para>
<para/>
<para>
/usr/src/redhat/SRPMS:
</para>
<para>
That is, with a clean system and no other RPMs being built,
you'll see a spec file in /usr/src/redhat/SPECS and the
sources in /usr/src/redhat/SOURCES. In this example, the
sources are in a compressed tar archive. (For this, the RPM
spec file, jikes.spec needs to have a command in the prep
section to extract the files.)
</para>
<para>
You should now be ready to build an RPM.
</para>
</sect3>
</sect2>
<sect2>
<title>Building RPMs with the rpmbuild command</title>
<para>
To build RPMs with the rpmbuild command, use the following basic
syntax:
</para>
<para>
rpmbuild -bBuildStage spec_file
</para>
<para>
The -b option tells rpmbuild to build an RPM. The extra
BuildStage option is a special code that tells the rpmbuild
command how far to go when building. Table 9-2 lists these
options:
</para>
<para>
Table 9-2 Options for building with rpmbuild
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Option
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
-ba
</para>
</entry>
<entry>
<para>
Build all, both a binary and source RPM
</para>
</entry>
</row>
<row>
<entry>
<para>
-bb
</para>
</entry>
<entry>
<para>
Build a binary RPM
</para>
</entry>
</row>
<row>
<entry>
<para>
-bc
</para>
</entry>
<entry>
<para>
Build (compile) the program but do not make the full
RPM, stopping just after the %build section
</para>
</entry>
</row>
<row>
<entry>
<para>
-bp
</para>
</entry>
<entry>
<para>
Prepare for building a binary RPM, and stop just after
the %prep section
</para>
</entry>
</row>
<row>
<entry>
<para>
-bi
</para>
</entry>
<entry>
<para>
Create a binary RPM and stop just after the %install
section
</para>
</entry>
</row>
<row>
<entry>
<para>
-bl
</para>
</entry>
<entry>
<para>
Check the listing of files for the RPM and generate
errors if the buildroot is missing any of the files to
be installed
</para>
</entry>
</row>
<row>
<entry>
<para>
-bs
</para>
</entry>
<entry>
<para>
Build a source RPM only
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Note
</para>
<para>
See chapter 12 for advanced options you can use with rpmbuild.
</para>
<para>
For example, to set up all the necessary files and prepare for
building, run the following command:
</para>
<para>
rpmbuild ���bp specfile
</para>
<para>
This example runs through the %prep section, and stops
immediately after this section. With the jikes package, for
example, you���ll see a result like the following:
</para>
<para>
$ rpmbuild -bp /usr/src/redhat/SPECS/jikes.spec
</para>
<para>
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.72435
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ LANG=C
</para>
<para>
+ export LANG
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ rm -rf jikes-1.17
</para>
<para>
+ /usr/bin/gzip -dc /usr/src/redhat/SOURCES/jikes-1.17.tar.gz
</para>
<para>
+ tar -xf -
</para>
<para>
+ STATUS=0
</para>
<para>
+ '[' 0 -ne 0 ']'
</para>
<para>
+ cd jikes-1.17
</para>
<para>
++ /usr/bin/id -u
</para>
<para>
+ '[' 500 = 0 ']'
</para>
<para>
++ /usr/bin/id -u
</para>
<para>
+ '[' 500 = 0 ']'
</para>
<para>
+ /bin/chmod -Rf a+rX,g-w,o-w .
</para>
<para>
+ exit 0
</para>
<para>
After running this command, the source files are extracted into
the /usr/src/redhat/BUILD directory, under the jikes-1.17
subdirectory. Using a subdirectory keeps the sources for this
package from intermixing with the sources for other packages.
</para>
<para>
Running a directory listing on the
/usr/src/redhat/BUILD/jikes-1.17 subdirectory shows what the
spec file %prep section commands have done. For example:
</para>
<para>
$ ls -1 /usr/src/redhat/BUILD/jikes-1.17
</para>
<para>
acinclude.m4
</para>
<para>
aclocal.m4
</para>
<para>
AUTHORS
</para>
<para>
ChangeLog
</para>
<para>
config.guess
</para>
<para>
config.sub
</para>
<para>
configure
</para>
<para>
configure.in
</para>
<para>
COPYING
</para>
<para>
depcomp
</para>
<para>
doc
</para>
<para>
INSTALL
</para>
<para>
install-sh
</para>
<para>
jikes.spec
</para>
<para>
Makefile.am
</para>
<para>
Makefile.in
</para>
<para>
missing
</para>
<para>
mkinstalldirs
</para>
<para>
NEWS
</para>
<para>
README
</para>
<para>
src
</para>
<para>
TODO
</para>
<para>
Note
</para>
<para>
From these sources, you see a configure script. The configure
script gives a good indication of how the software needs to be
built. This example also shows a README file. You know what to
do with these files.
</para>
<para>
The actual source code is in the
/usr/src/redhat/BUILD/jikes-1.17/src directory. The user
documentation is stored in the
/usr/src/redhat/BUILD/jikes-1.17/doc directory.
</para>
<para>
To build a binary RPM, use the ���bb option to the rpmbuild
command. For example:
</para>
<para>
$ rpmbuild -bb /usr/src/redhat/SPECS/jikes.spec
</para>
<para>
Warning
</para>
<para>
Don���t build packages when you are logged in as the root user.
Log in as a normal user instead. This is to limit the damage
caused to your system if the spec file or the Makefile contains
errors that delete system files, for example. If you are logged
in as the root user, you will have permission to perform these
destructive acts. If you are logged in as a normal user, though,
these RPM spec file and Makefile errors will fail to run,
because you don���t have permission to modify system files.
</para>
<para>
This command results in a lot of output, most coming from the
configure script. (This script examines the C programming
environment on your system.) When the rpmbuild command
completes, you���ll see the binary RPM in the proper
subdirectory of the RPMS directory. You can see the RPM with a
directory listing, for example:
</para>
<para>
$ls /usr/src/redhat/RPMS/i386:
</para>
<para>
jikes-1.17-1.i386.rpm
</para>
<para>
To stop execution just after the %install section, use a command
like the following:
</para>
<para>
rpmbuild ���bi specfile
</para>
<para>
For example:
</para>
<para>
# rpmbuild -bi /usr/src/redhat/SPECS/jikes.spec
</para>
<para>
To build a source RPM out of the files you have (in this case a
tar archive of the sources and the spec file), use a command
like the following:
</para>
<para>
rpmbuild ���bs specfile
</para>
<para>
For example:
</para>
<para>
$ rpmbuild -bs /usr/src/redhat/SPECS/jikes.spec
</para>
<para>
When done, you���ll see the source RPM in the
/usr/src/redhat/SRPMS directory:
</para>
<para>
$ ls /usr/src/redhat/SRPMS
</para>
<para>
jikes-1.17-1.src.rpm
</para>
<para>
To clean out the files created by building these RPMs, use the
--clean option to the rpmbuild command:
</para>
<para>
rpmbuild --clean specfile
</para>
<para>
For example:
</para>
<para>
$ rpmbuild --clean /usr/src/redhat/SPECS/jikes.spec
</para>
<para>
Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.21908
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ rm -rf jikes-1.17
</para>
<para>
+ exit 0
</para>
<para>
Cross Reference
</para>
<para>
Chapter 12 covers a number of addition options for the rpmbuild
command that you can use to customize the build.
</para>
</sect2>
</sect1>
<sect1>
<title>Verifying Your RPMS</title>
<para>
After you've built an RPM, you can use the techniques from Chapter
5 to verify the RPM. You can also use the ���bl option to the
rpmbuild command to verify the list of files in the RPM. Use a
command like the following:
</para>
<para>
rpmbuild ���bl spec_file
</para>
<para>
For example:
</para>
<para>
$ rpmbuild -bl /usr/src/redhat/SPECS/jikes.spec
</para>
<para>
Processing files: jikes-1.17-1
</para>
<para>
error: File not found: /tmp/jikesrpm/usr/bin/jikes
</para>
<para>
error: File not found:
/tmp/jikesrpm/usr/doc/jikes-1.17/license.htm
</para>
<para>
error: File not found by glob: /tmp/jikesrpm/usr/man/man1/jikes.1*
</para>
<para>
Provides: jikes
</para>
<para/>
<para/>
<para>
RPM build errors:
</para>
<para>
File not found: /tmp/jikesrpm/usr/bin/jikes
</para>
<para>
File not found: /tmp/jikesrpm/usr/doc/jikes-1.17/license.htm
</para>
<para>
File not found by glob: /tmp/jikesrpm/usr/man/man1/jikes.1*
</para>
<para>
This example shows a number of errors. The -bl option checks that
all the necessary files are located within the buildroot
directory. The buildroot directory is a location that acts like
the final installed root directory. From the previous example,
this package was not properly built yet.
</para>
<para>
In a situation like this, you can start over, or use the
--short-circuit option to restart the build from a given section
in the spec file. As you create an RPM, you will need to go back
and forth restarting the build as you detect and fix errors.
</para>
<para/>
<para>
You can also use the rpm command with options such as ���V for
verification on a fully-built package. For example:
</para>
<para>
$ rpm -Vp /usr/src/redhat/RPMS/i386/jikes-1.17-1.i386.rpm
</para>
<para>
S.5....T /usr/bin/jikes
</para>
<para>
.......T d /usr/doc/jikes-1.17/license.htm
</para>
<para>
..5....T d /usr/man/man1/jikes.1.gz
</para>
<para>
In this case, you see some file sizes and times differ. These
differences can be explained by the fact that the original package
was compiled on a different system and older version of Red Hat
Linux than the version compiled locally.
</para>
<para>
Cross Reference
</para>
<para>
See the on "Verifying Installed RPM Packages" section in Chapter 5
for more on the -V option.
</para>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter introduced the task of building RPMs, whether
building RPMs from your own applications or from software you have
gathered elsewhere. In both cases, the steps for building the RPMs
are the same.
</para>
<para>
In most cases, you should build an RPM of the sources for your
application, an RPM that can be used to reproduce the build of the
application. Create a second RPM that holds the binary
application. Once you set up the commands and define the spec file
for the binary RPM, making a source RPM is trivial.
</para>
<para>
Use the rpmbuild command to create RPMs. This command uses an RPM
spec file to define the commands and settings for creating the
RPM.
</para>
<para>
The next chapter delves into the spec files that define the RPM
directives for your packages.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
18 years, 6 months
rpm-guide rpm-guide-command-reference-en.xml,NONE,1.1
by fedora-docs-commits@redhat.com
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv376
Added Files:
rpm-guide-command-reference-en.xml
Log Message:
--- NEW FILE rpm-guide-command-reference-en.xml ---
<!-- $Id: -->
<chapter id="ch-command-reference">
<title>RPM Command Reference</title>
<para>
In This Appendix
</para>
<para>
*rpm command
</para>
<para>
*rpmbuild command
</para>
<para>
This appendix covers the syntax of the command-line options for the
rpm and rpmbuild commands.
</para>
<sect1>
<title>The rpm Command</title>
<para>
The rpm command is the workhorse of the RPM system. The following
sections cover options for the major operations with the rpm
command.
</para>
<para>
Table A-1 lists the query options for the rpm command.
</para>
<para>
Table A-1 rpm query options with ���q or --query
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Option
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
-a, --all
</para>
</entry>
<entry>
<para>
Query all packages
</para>
</entry>
</row>
<row>
<entry>
<para>
-c, --configfiles
</para>
</entry>
<entry>
<para>
List configuration files
</para>
</entry>
</row>
<row>
<entry>
<para>
--changelog
</para>
</entry>
<entry>
<para>
List changelog entries
</para>
</entry>
</row>
<row>
<entry>
<para>
--conflicts
</para>
</entry>
<entry>
<para>
List capabilities this package conflicts with
</para>
</entry>
</row>
<row>
<entry>
<para>
-d, --docfiles
</para>
</entry>
<entry>
<para>
List documentation files
</para>
</entry>
</row>
<row>
<entry>
<para>
--dump
</para>
</entry>
<entry>
<para>
Dump out extra information on files.
</para>
</entry>
</row>
<row>
<entry>
<para>
-f, --file filename
</para>
</entry>
<entry>
<para>
Query for packages owning given file
</para>
</entry>
</row>
<row>
<entry>
<para>
--filesbypapkg
</para>
</entry>
<entry>
<para>
List all files in each selected package
</para>
</entry>
</row>
<row>
<entry>
<para>
--fileid md5_id
</para>
</entry>
<entry>
<para>
Query for the package with the given MD5 digest
</para>
</entry>
</row>
<row>
<entry>
<para>
-g, --group group_name
</para>
</entry>
<entry>
<para>
Query packages in the given group
</para>
</entry>
</row>
<row>
<entry>
<para>
--hdrid sha1_header_id
</para>
</entry>
<entry>
<para>
Query for the package with the given header identifier
number, in SHA1 format
</para>
</entry>
</row>
<row>
<entry>
<para>
-i, --info
</para>
</entry>
<entry>
<para>
Display a lot of package information including
description
</para>
</entry>
</row>
<row>
<entry>
<para>
--last
[...1918 lines suppressed...]
</entry>
<entry>
<para>
Read the given colon-separated files as the macro
files to define RPM macros; only the first file must
exist
</para>
</entry>
</row>
<row>
<entry>
<para>
--nobuild
</para>
</entry>
<entry>
<para>
Don't really build anything, which really tests the
spec file
</para>
</entry>
</row>
<row>
<entry>
<para>
--pipe command
</para>
</entry>
<entry>
<para>
Pipe the output of the rpm command to the given
command
</para>
</entry>
</row>
<row>
<entry>
<para>
--quiet
</para>
</entry>
<entry>
<para>
Provide less output, normally show only errors
</para>
</entry>
</row>
<row>
<entry>
<para>
--rcfile file:file:file
</para>
</entry>
<entry>
<para>
Read the given colon-separated files as the rc files
to define RPM settings; only the first file must exist
</para>
</entry>
</row>
<row>
<entry>
<para>
--rmsource
</para>
</entry>
<entry>
<para>
Remove the sources after the build
</para>
</entry>
</row>
<row>
<entry>
<para>
--rmspec
</para>
</entry>
<entry>
<para>
Remove the spec file after the build
</para>
</entry>
</row>
<row>
<entry>
<para>
--root directory
</para>
</entry>
<entry>
<para>
Use directory as the top-level directory instead of /
</para>
</entry>
</row>
<row>
<entry>
<para>
--short-circuit
</para>
</entry>
<entry>
<para>
With the -bc or -bi options, jumps directly to the
given stage and just executes that stage
</para>
</entry>
</row>
<row>
<entry>
<para>
--showrc
</para>
</entry>
<entry>
<para>
Print the rpmrc and macro configuration and exit
</para>
</entry>
</row>
<row>
<entry>
<para>
--sign
</para>
</entry>
<entry>
<para>
Sign the package with a GPG signature
</para>
</entry>
</row>
<row>
<entry>
<para>
--target platform
</para>
</entry>
<entry>
<para>
Build for the given platform. May not work if you
don't have the other platform build commands, such as
cross compilers, set up. Can work for Intel platforms
with i386, i686, and so on.
</para>
</entry>
</row>
<row>
<entry>
<para>
-v, --verbose
</para>
</entry>
<entry>
<para>
Provide more verbose output
</para>
</entry>
</row>
<row>
<entry>
<para>
-vv
</para>
</entry>
<entry>
<para>
Provide even more verbose output, including debugging
information
</para>
</entry>
</row>
<row>
<entry>
<para>
--version
</para>
</entry>
<entry>
<para>
Print the RPM version and exit
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para/>
</sect2>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
18 years, 6 months
rpm-guide rpm-guide-advanced-packaging-en.xml,NONE,1.1
by fedora-docs-commits@redhat.com
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv341
Added Files:
rpm-guide-advanced-packaging-en.xml
Log Message:
--- NEW FILE rpm-guide-advanced-packaging-en.xml ---
<!-- $Id: -->
<chapter id="ch-advanced-packaging">
<title>Advanced RPM Packaging</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/).
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Defining package dependency information
</para>
<para>
*Setting triggers
</para>
<para>
*Writing verification scripts
</para>
<para>
*Creating subpackages
</para>
<para>
*Creating relocatable packages
</para>
<para>
*Defining conditional builds
</para>
<para>
The previous chapter introduced the RPM spec file, which controls
how RPM packages are built and installed. This chapter delves into
advanced spec file topics such as using conditional commands and
making relocatable packages, starting with how to specify package
dependencies.
</para>
<sect1>
<title>Defining Package Dependencies</title>
<para>
Dependencies are one of the most important parts of the RPM
system. The RPM database tracks dependencies between packages to
better allow you to manage your system. A dependency occurs when
one package depends on another. The RPM system ensures that
dependencies are honored when upgrading, installing, or removing
packages. From that simple concept, RPM supports four types of
dependencies:
</para>
<para>
*Requirements, where one package requires a capability provided by
another
</para>
<para>
*Provides, a listing of the capabilities your package provides
</para>
<para>
*Conflicts, where one package conflicts with a capability provided
by another
</para>
<para>
*Obsoletes, where one package obsoletes capabilities provided by
another, usually used when a package changes name and the new
package obsoletes the old name
</para>
<para>
Cross Reference
</para>
<para>
Chapter 6 covers more on dependencies. The Obsoletes dependencies
are usually only used when a package is renamed, such as the
apache package becoming the httpd package, starting in Red Hat
Linux 8.0. The httpd package obsoletes the apache package.
</para>
<para>
You can list all of these dependencies in your spec file. The most
commonly used dependency information, though, is what a package
requires.
</para>
<sect2>
<title>Naming dependencies</title>
<para>
In your spec files, you can name the dependencies for your
package. The basic syntax is:
</para>
<para>
Requires: capability
</para>
<para>
In most cases, the capability should be the name of another
package. This example sets up a requires dependency. This means
that the package requires the given capability. Use a similar
syntax for the other kinds of dependencies:
</para>
<para>
Provides: capability
</para>
<para>
Obsoletes: capability
</para>
<para>
Conflicts: capability
</para>
<para>
You can put more than one capability on the dependency line. For
example:
</para>
<para>
Requires: bash perl
</para>
<para>
You can use spaces or commas to separate the capabilities. For
example:
</para>
<para>
Requires: bash, perl
</para>
<sect3>
<title>Specifying the Version of the Dependencies</title>
<para>
You can also add version information, for example:
</para>
<para>
Requires: bash >= 2.0
</para>
<para>
This states that the package requires the capability bash (a
package) at version 2.0 or higher. The same logic applies to
the other types of dependencies. For example:
</para>
<para>
Conflicts: bash >= 2.0
</para>
<para>
This example states that the package conflicts with all
versions of bash 2.0 or higher.
</para>
<para>
Table 11-1 lists the version comparisons you can use.
</para>
<para>
Table 11-1 Dependency version comparisons
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Comparison
</para>
</entry>
<entry>
<para>
Meaning
</para>
</entry>
</row>
<row>
<entry>
<para>
package < version
</para>
</entry>
<entry>
<para>
A package with a version number less than version
</para>
</entry>
</row>
<row>
<entry>
<para>
package > version
</para>
</entry>
<entry>
<para>
A package with a version number greater than version
</para>
</entry>
</row>
<row>
<entry>
<para>
package >= version
</para>
</entry>
<entry>
<para>
A package with a version number greater than or
equal to version
</para>
</entry>
</row>
<row>
<entry>
<para>
package <= version
</para>
<para/>
</entry>
<entry>
<para>
A package with a version number less than or equal
to version
</para>
</entry>
</row>
<row>
<entry>
<para>
package = version
</para>
</entry>
<entry>
<para>
A package with a version number equal to version
</para>
</entry>
</row>
<row>
<entry>
<para>
package
</para>
</entry>
<entry>
<para>
A package at any version number
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
RPM supports an extended version number syntax for
comparisons. The full format follows:
</para>
<para>
Epoch:Version-Release
</para>
<para>
For example:
</para>
<para>
1:5.6.0-17
</para>
<para>
In this case, the epoch is 1, the version 5.6.0, and the
release is 17. In most cases, you will need just the version
number. The epoch allows for handling hard-to-compare version
numbers. The release number is almost never used. This makes
sense, in that it ties a dependency to a particular build of
the RPM package, rather than a version of the software itself.
This type of dependency would only be useful if you
drastically changed the way you build a package.
</para>
</sect3>
<sect3>
<title>Creating Virtual CAPABILITIES</title>
<para>
Dependencies are based on capabilities, most of which are
packages. You can create virtual capabilities, which are just
names you define. For example, the sendmail package provides a
virtual capability named smtpdaemon. For example:
</para>
<para>
Provides: smtpdaemon
</para>
<para>
This capability refers to the general SMTP Internet service
for sending e-mail messages. There is no file of this name.
Instead, it is just a capability, arbitrary text. Other
packages require this capability, such as the fetchmail
mail-retrieval and forwarding application, and mutt, an e-mail
client program.
</para>
<para>
By using a virtual capability, other packages can provide the
capability, and most importantly, client applications can
require the capability without worrying which package provides
the ability to send e-mail messages. For example, the exim and
postfix packages, mail transport agents like sendmail, can
provide the same capability.
</para>
<para>
Note
</para>
<para>
Of course, you want to ensure that these packages specify that
they conflict with each other.
</para>
</sect3>
<sect3>
<title>Naming Dependencies on Script Engines and Modules</title>
<para>
Scripting languages such as Perl and Tcl allow for add-on
modules. Your package may require some of these add-on
modules. RPM uses a special syntax with parenthesis to
indicate script module dependencies. For example:
</para>
<para>
Requires: perl(Carp) >= 3.2
</para>
<para>
This indicates a requirement for the Carp add-on module for
Perl, greater than or equal to version 3.2.
</para>
</sect3>
</sect2>
<sect2>
<title>Setting prerequisites</title>
<para>
A prerequisite is similar to a require dependency, except that a
prerequisite must be installed prior to a given package. Specify
a prerequisite as follows:
</para>
<para>
PreReq: capability
</para>
<para>
You can include version-number dependencies, such as:
</para>
<para>
PreReq: capability >= version
</para>
<para>
In most usage, a PreReq: acts just like Requires:, in fact, the
PreReq: directive exists just to allow for a manual order to
dependencies. RPM guarantees that the PreReq: package will be
installed prior to the package that names the PreReq:
dependency.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 14 covers a common problem of handling circular
dependencies using prerequisites.
</para>
</sect2>
<sect2>
<title>Naming build dependencies</title>
<para>
Your package, once built, has a set of dependencies. These
dependencies are important for anyone installing the package.
But there are also dependency issues when trying to build
packages. Build dependencies allow you to specify what is
necessary to build the package. While you may think this would
be the same as what is needed to install a package, this is
normally not true. Linux distributions tend to divide up
software into runtime and development packages. For example, the
python package contains the runtime for executing scripts
written in Python. The python-devel package provides the ability
to write extensions to the Python language.
</para>
<para>
RPM allows you to define build-time dependencies in your spec
files using the following directives:
</para>
<para>
BuildRequires:
</para>
<para>
BuildConflicts:
</para>
<para>
BuildPreReq:
</para>
<para>
These directives act like Requires:, Conflicts:, and PreReq:,
respectively, except that the dependencies are needed to build
the package, not install it. For example, your package may
require a C compiler to build, or may need a special build tool
or developer library.
</para>
</sect2>
<sect2>
<title>Generating dependencies automatically</title>
<para>
Because so many dependencies are related to shared libraries,
the RPM system will automatically generate provide dependencies
for any file in your packages that is a shared object, or .so,
file. RPM will also automatically generate require dependencies
for all files in the %files list that require shared libraries.
To do this, RPM uses the ldd command, which determines the
shared libraries used by an application.
</para>
<para>
In addition, the find-requires and find-provides scripts in
/usr/lib/rpm can determine Perl, Python and Tcl script
dependencies and other dependencies, such as Java package
dependencies, automatically. The find-requires script determines
requires dependencies automatically, and the find-provides
script determines provides dependencies.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 14 covers how to turn off the automatic generation of
dependencies.
</para>
</sect2>
</sect1>
<sect1>
<title>Setting Triggers</title>
<para>
Triggers provide a way for one package to take action when the
installed status of another package changes. A trigger is a script
you define in your package���s spec file that gets run by the RPM
system when the status of another named package changes. If your
package depends in some way on another package, a trigger can
allow your package to deal with changes to the other package.
</para>
<para>
Triggers are not a replacement for package dependencies. Instead,
triggers are useful when you need to change a package���s
installation based on other packages installed on the system. For
example, if your package is a mail client program, your package
will need to have a mail transfer agent, or MTA. Linux supports a
number of different mail transfer agents, such as sendmail, vmail,
exim, qmail, and postfix.
</para>
<para>
Typically a system will have one mail transfer agent installed. In
most cases, a mail client won���t care which MTA is installed, as
long as one is installed. (In fact, most of these packages should
be marked that they conflict with one another, ensuring that a
given system can only have one.)
</para>
<para>
The %triggerin script is run when a given target package is
installed or upgraded. The %triggerin script is also run when your
package is installed or upgraded, should the target package be
already installed. Similarly, the %triggerun script is run if the
target package is removed. It is also run if your package is
removed and the target package is installed. The %triggerpostun
script is run after the target package has been removed. It is not
run if your package is removed.
</para>
<para>
To define one of these scripts, you need to list the name of the
target package; for example:
</para>
<para>
%triggerin -- tcsh
</para>
<para>
script commands...
</para>
<para>
This example sets up a trigger for the tcsh package. If the tcsh
package is installed or upgraded, RPM will run the script. If your
package is installed or upgraded and the tcsh package is presently
installed, RPM will also run the script.
</para>
<para>
Define the %triggerun script similarly:
</para>
<para>
%triggerun -- tcsh
</para>
<para>
script commands...
</para>
<para>
You can also use version numbers in the trigger script definition
to only run the script in the case of a particular version. For
example:
</para>
<para>
%triggerpostun -- vixie-cron < 3.0.1-56
</para>
<para>
/sbin/chkconfig --del crond
</para>
<para>
/sbin/chkconfig --add crond
</para>
<para>
This example, from the vixie-cron scheduling package, runs a
post-uninstall trigger for the same package, but for older
versions. To define trigger scripts for particular versions, use
the same syntax as for requires dependencies for naming the
version number and comparisons.
</para>
<para>
Triggers are run through /bin/sh, the most commonly used shell
script engine. With the -p option, though, you can specify a
different script interpreter. For example, to write a Perl script,
define your trigger like the following:
</para>
<para>
%triggerpostun -p /usr/bin/perl -- vixie-cron < 3.0.1-56
</para>
<para>
system("/sbin/chkconfig --del crond");
</para>
<para>
system("/sbin/chkconfig --add crond");
</para>
<para>
With subpackages, defined following, you can use a -n option to
tie the trigger script to a subpackage. For example:
</para>
<para>
%triggerpostun -n subpackage_name -- vixie-cron < 3.0.1-56
</para>
<para>
/sbin/chkconfig --del crond
</para>
<para>
/sbin/chkconfig --add crond
</para>
<para>
Inside your trigger scripts, $1, the first command-line argument,
holds the number of instances of your package that will remain
after the operation has completed. The second argument, $2, holds
the number of instances of the target package that will remain
after the operation. Thus, if $2 is 0, the target package will be
removed.
</para>
<para>
The anonftp package, mentioned in Chapter 6, has a lot of
triggers. Many of these set up a number of commands to be locally
available to the anonftp package. This networking package is also
closely tied to the version of the C library, glibc, as shown in
Listing 11-1
</para>
<para>
Listing 11-1: Anonftp package trigger scripts.
</para>
<para>
%triggerin -- glibc
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
# Kill off old versions
</para>
<para>
rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl*
/var/ftp/lib/lib
</para>
<para>
nss_files* &>/dev/null || :
</para>
<para>
# Copy parts of glibc, needed by various programs in bin.
</para>
<para>
LIBCVER=`basename $(ls --sort=time /lib/libc-*.so |head -n 1) .so
|cut -f2- -d-`
</para>
<para>
copy /lib/ld-${LIBCVER}.so /var/ftp/lib
</para>
<para>
copy /lib/libc-${LIBCVER}.so /var/ftp/lib
</para>
<para>
copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib
</para>
<para>
copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib
</para>
<para>
md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
2>/dev/null >/var
</para>
<para>
/ftp/lib/libs.md5
</para>
<para>
chmod 0400 /var/ftp/lib/libs.md5
</para>
<para>
# Use ldconfig to build symlinks and whatnot.
</para>
<para>
[ ! -e /var/ftp/etc/ld.so.conf ] && touch
/var/ftp/etc/ld.so.conf
</para>
<para>
/sbin/ldconfig -r /var/ftp
</para>
<para/>
<para>
%triggerin -- fileutils
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
copy /bin/ls /var/ftp/bin
</para>
<para>
md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
>/var/ftp/bin/bin.md5
</para>
<para>
chmod 0400 /var/ftp/bin/bin.md5
</para>
<para/>
<para>
%triggerin -- cpio
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
copy /bin/cpio /var/ftp/bin
</para>
<para>
md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
>/var/ftp/bin/bin.md5
</para>
<para>
chmod 0400 /var/ftp/bin/bin.md5
</para>
<para/>
<para>
%triggerin -- tar
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
copy /bin/tar /var/ftp/bin
</para>
<para>
md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
>/var/ftp/bin/bin.md5
</para>
<para>
chmod 0400 /var/ftp/bin/bin.md5
</para>
<para/>
<para>
%triggerin -- gzip
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
copy /bin/gzip /var/ftp/bin
</para>
<para>
ln -sf gzip /var/ftp/bin/zcat
</para>
<para>
md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
>/var/ftp/bin/bin.md5
</para>
<para>
chmod 0400 /var/ftp/bin/bin.md5
</para>
<para/>
<para>
%triggerin -- libtermcap
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :
</para>
<para>
copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib
</para>
<para>
md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
2>/dev/null >/var
</para>
<para>
/ftp/lib/libs.md5
</para>
<para>
chmod 0400 /var/ftp/lib/libs.md5
</para>
<para>
# Use ldconfig to build symlinks and whatnot.
</para>
<para>
[ ! -e /var/ftp/etc/ld.so.conf ] && touch
/var/ftp/etc/ld.so.conf
</para>
<para>
/sbin/ldconfig -r /var/ftp
</para>
<para/>
<para>
%triggerin -- ncompress
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
copy /usr/bin/compress /var/ftp/bin
</para>
<para>
md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
>/var/ftp/bin/bin.md5
</para>
<para>
chmod 0400 /var/ftp/bin/bin.md5
</para>
<para/>
<para>
%triggerpostun -- anonftp 4.0
</para>
<para>
if [ "$2" != 1 ] ; then
</para>
<para>
# The user has multiple glibc packages installed. We can't read
the
</para>
<para>
# user's mind, so don't do anything.
</para>
<para>
exit 0
</para>
<para>
fi
</para>
<para>
copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
2>/dev/null |
</para>
<para>
| cp -df "$file" "$2"; }
</para>
<para>
# Kill off old versions
</para>
<para>
rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl*
/var/ftp/lib/lib
</para>
<para>
nss_files* &>/dev/null || :
</para>
<para>
# Copy parts of glibc, needed by various programs in bin.
</para>
<para>
LIBCVER=`basename /lib/libc-*.so .so | cut -f2- -d-`
</para>
<para>
copy /lib/ld-${LIBCVER}.so /var/ftp/lib
</para>
<para>
copy /lib/libc-${LIBCVER}.so /var/ftp/lib
</para>
<para>
copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib
</para>
<para>
copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib
</para>
<para>
copy /bin/ls /var/ftp/bin
</para>
<para>
copy /bin/cpio /var/ftp/bin
</para>
<para>
copy /bin/tar /var/ftp/bin
</para>
<para>
copy /bin/gzip /var/ftp/bin
</para>
<para>
ln -sf gzip /var/ftp/bin/zcat
</para>
<para>
copy /usr/bin/compress /var/ftp/bin
</para>
<para>
rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :
</para>
<para>
copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib
</para>
<para>
# Use ldconfig to build symlinks and whatnot.
</para>
<para>
[ ! -e /var/ftp/etc/ld.so.conf ] && touch
/var/ftp/etc/ld.so.conf
</para>
<para>
/sbin/ldconfig -r /var/ftp
</para>
<para>
# Generate md5sums for verifyscript
</para>
<para>
md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
2>/dev/null >/var
</para>
<para>
/ftp/lib/libs.md5
</para>
<para>
chmod 0400 /var/ftp/lib/libs.md5
</para>
<para>
md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
>/var/ftp/bin/bin.md5
</para>
<para>
chmod 0400 /var/ftp/bin/bin.md5
</para>
</sect1>
<sect1>
<title>Writing Verification Scripts</title>
<para>
RPM automatically handles package verification, checking to see
that the proper files are installed, and testing the files
themselves for the proper size and other attributes. You may need
to do more in your package, though, to ensure everything is
properly set up. With RPM, you can:
</para>
<para>
*Control the tests used to verify each file, as described in
Chapter 10
</para>
<para>
*Create a verify script that performs other tests
</para>
<para>
If you need to perform some other test to verify your package,
such as check that a configuration file has a particular setting
(and that the setting is valid), you can fill in the %verifyscript
in the spec file. The %verifyscript acts much like the %pre or
%post scripts, except that the %verifyscript gets executed during
package verification. Fill in a %verifyscript as follows:
</para>
<para>
%verifyscript
</para>
<para>
your script commands ....
</para>
<para>
Common %verifyscript actions are to check for an entry in a system
configuration file, such as an init-time startup script or
/etc/shells (which lists the available shells). These are files
owned by other packages that may need to be properly modified for
a package to be properly installed. If your package has a similar
circumstance, write a %verifyscript. In your script, send all
error output to stderr.
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 5 for more on package verification.
</para>
</sect1>
<sect1>
<title>Creating Subpackages</title>
<para>
A spec file may define more than one package. This type of
additional package is called a subpackage. Subpackages exist to
handle cases where you don���t want to associate one spec file
with one package. Instead, you can define multiple packages within
the spec file, as needed. For example, you may want to build the
runtime and developer packages together, or the client and server
portions of an application using subpackages. Splitting large
documentation sets into separate subpackages is also common.
</para>
<para>
With subpackages, you get:
</para>
<para>
*One spec file
</para>
<para>
*One source RPM
</para>
<para>
*One set of build commands
</para>
<para>
*Multiple binary RPMs, one per package or subpackage
</para>
<para>
In most cases, subpackages are created just as a means to
partition the files produced by a package into separate packages.
For example, you will often see development libraries and header
files split into a separate package from the main application
package. Sometimes documentation is split out into a separate
package, or client and server applications are divided into
separate packages. In the end, though, this usually results in
shifting files into subpackages and nothing more.
</para>
<para>
To define a subpackage within a spec file, you start with the
%package directive. For example:
</para>
<para>
%package sub_package_name
</para>
<para>
By default, the name of the subpackage will be the name of the
package, a dash, and the subpackage name provided with the
%package directive. For example:
</para>
<para>
%package server
</para>
<para>
This example names a subpackage server, which is a real subpackage
inside the telnet package. In this case, the name for the server
subpackage will be telnet-server, that is, the naming format is
package-subpackage.
</para>
<para>
If you don���t want this naming format, you can use the ���n
option to the %package directive to define an entirely new name,
using the following syntax:
</para>
<para>
%package -n new_sub_package_name
</para>
<para>
For example:
</para>
<para>
%package ���n my-telnet-server
</para>
<para>
With the ���n option, you specify the full name for the
subpackage. The RPM system will not prefix the name with the
enclosing package name.
</para>
<sect2>
<title>Providing information for subpackages</title>
<para>
When you define a subpackage, you need to provide as many of the
package information directives as you need, including at the
least Summary:, Group:, and %description directives. Anything
not specified will use the parent package���s value, such as the
version. Place these directives after the %package directive.
For example:
</para>
<para>
%package server
</para>
<para>
Requires: xinetd
</para>
<para>
Group: System Environment/Daemons
</para>
<para>
Summary: The server program for the telnet remote login
protocol.
</para>
<para>
The %description directive for subpackages requires the name of
the subpackage using the following syntax:
</para>
<para>
%description subpackage
</para>
<para>
For example:
</para>
<para>
%description server
</para>
<para>
Telnet is a popular protocol for logging into remote systems
</para>
<para>
over the Internet. The telnet-server package includes a telnet
daemon that supports remote logins into the host machine. The
</para>
<para>
telnet daemon is enabled by default. You may disable the telnet
</para>
<para>
daemon by editing /etc/xinetd.d/telnet.
</para>
<para>
If you used the ���n option with the %package directive, you
need to repeat the ���n option with the %description directive.
For example:
</para>
<para>
%description ���n my-telnet-server
</para>
<para>
Telnet is a popular protocol for logging into remote systems
</para>
<para>
over the Internet. The telnet-server package includes a telnet
daemon that supports remote logins into the host machine. The
</para>
<para>
telnet daemon is enabled by default. You may disable the telnet
</para>
<para>
daemon by editing /etc/xinetd.d/telnet.
</para>
<para>
The same concept works for the %files section. You need a
separate %files section for each subpackage. For example:
</para>
<para>
%files server
</para>
<para>
%defattr(-,root,root)
</para>
<para>
%{_sbindir}/in.telnetd
</para>
<para>
%{_mandir}/man5/issue.net.5*
</para>
<para>
%{_mandir}/man8/in.telnetd.8*
</para>
<para>
%{_mandir}/man8/telnetd.8*
</para>
<para>
Again, if you used the ���n option with the %package directive,
you need to repeat the ���n option with the %files section. For
example:
</para>
<para>
%files ���n my-telnet-server
</para>
<para>
%defattr(-,root,root)
</para>
<para>
%{_sbindir}/in.telnetd
</para>
<para>
%{_mandir}/man5/issue.net.5*
</para>
<para>
%{_mandir}/man8/in.telnetd.8*
</para>
<para>
%{_mandir}/man8/telnetd.8*
</para>
</sect2>
<sect2>
<title>Defining scripts for subpackages</title>
<para>
Much as you define separate %files and %description sections for
subpackages, you can also define install and uninstall scripts
for subpackages. The syntax is similar to that for the %files
and %description sections:
</para>
<para>
%pre subpackage
</para>
<para>
For example, Listing 11-2 shows the scripts from the VNC
package.
</para>
<para>
Listing 11-2: VNC package install and uninstall scripts.
</para>
<para>
%post server
</para>
<para>
if [ "$1" = 1 ]; then
</para>
<para>
/sbin/chkconfig --add vncserver
</para>
<para>
fi
</para>
<para/>
<para>
%preun server
</para>
<para>
if [ "$1" = 0 ]; then
</para>
<para>
/sbin/service vncserver stop >/dev/null 2>&1
</para>
<para>
/sbin/chkconfig --del vncserver
</para>
<para>
fi
</para>
<para/>
<para>
%postun server
</para>
<para>
if [ "$1" -ge "1" ]; then
</para>
<para>
/sbin/service vncserver condrestart >/dev/null 2>&1
</para>
<para>
fi
</para>
</sect2>
<sect2>
<title>Building subpackages</title>
<para>
The build sections in the spec file serve double duty. These
sections are used for building the main package as well as
subpackages. This is one reason why there are so many options on
the %setup macro.
</para>
<para>
The %setup macro allows for selectively unpacking the sources,
rather than the default option of unpacking all the sources. For
example, the following %setup macro definition gives rpmbuild
specific instructions for unpacking one source file:
</para>
<para>
%setup ���D- T ���a 1
</para>
<para>
In this example, the ���D option disables the automatic deletion
of the directory where the sources will be unpacked. This means
any previous contents of this directory, perhaps for other
subpackages, will be left alone. The ���T option disables the
automatic unpacking of the source files, and the ���a 1 option
specifies to only unpack the first source file. You may need to
use options like these when working with subpackages. Though, in
most cases, subpackages are just means to partition the package
files into separate packages. In cases like this, you will
likely not need any of these special %setup options.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 10 covers the %setup macro and lists the available
options.
</para>
</sect2>
</sect1>
<sect1>
<title>Creating Relocatable Packages</title>
<para>
A relocatable package allows a user to specify where to install
the package. For example, if you build a package for Red Hat
Linux, the normal directory for binary executable programs is
/usr/bin. Other versions of Linux, though, may place executable
programs into /opt/bin, for example. If your package forces the
use of /usr/bin, then your package won���t work on these other
systems.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 19 covers using RPM on other versions of Linux.
</para>
<para>
With a relocatable package, though, you allow the user to redefine
the top-level directories for your package, such as changing from
/usr/bin to /opt/bin in the previous example. Making relocatable
packages is generally considered a good thing, as you make the
user���s life easier.
</para>
<para>
To set up a relocatable package, you need to:
</para>
<para>
*Set up the prefix directives for the top-level directories
</para>
<para>
*Define the files under the prefix directories
</para>
<sect2>
<title>Setting up the prefixes</title>
<para>
The Prefix: directive names a top-level directory as a prefix
you can relocate to another directory. For example:
</para>
<para>
Prefix: /usr
</para>
<para>
This states that all files under /usr can be relocated to other
directories by simply mapping /usr to some other directory, such
as /opt, on the rpm command line when installing or upgrading
the package.
</para>
<para>
Note
</para>
<para>
You can define more than one Prefix: directive to list more than
one top-level directory.
</para>
</sect2>
<sect2>
<title>Define the files section</title>
<para>
When you use a Prefix: directive in your spec file, all files in
the %files section must be under the directory named with the
Prefix: directive. For example, from the jikes compiler package:
</para>
<para>
Prefix: /usr
</para>
<para/>
<para>
...
</para>
<para/>
<para>
%files
</para>
<para>
%defattr(-,root,root)
</para>
<para>
/usr/bin/jikes
</para>
<para>
%doc /usr/doc/jikes-%{version}/license.htm
</para>
<para>
%doc /usr/man/man1/jikes.1*
</para>
<para>
In this example, all the files are under the /usr directory. All
files in the %files section must be located under one of the
Prefix: directories. If you have more than one top-level
directory, such as /usr and /etc, define more than one Prefix:
directive. For example:
</para>
<para>
Prefix: /usr
</para>
<para>
Prefix: /etc
</para>
<para>
Cross Reference
</para>
<para>
Chapter 4 covers how to install or upgrade packages into
different directories using the --relocate and --prefix options.
</para>
</sect2>
<sect2>
<title>Problems creating relocatable packages</title>
<para>
Not all packages work well as relocatable packages. Some
packages have files that simply must go into a certain location
and are therefore not relocatable. Some packages have programs
that are hard-coded to look for files in a particular location
and therefore cannot be relocated elsewhere. Other packages have
symbolic links that also may not be relocatable. Furthermore,
your package may provide software that is referenced by other
packages, in the known directories. Relocating such a package
will disable other software packages, packages you may not even
know about.
</para>
<para>
If your packages face any of these problems, chances are that
making the package relocatable is not a good idea.
</para>
<para>
In addition, if you use the %doc directive with local file
names, remember that RPM will make a package-specific
documentation directory, normally under /usr/doc. For example:
</para>
<para>
%doc README NEWS
</para>
<para>
This may defeat your attempts to create a relocatable package,
unless you have a Prefix: directive with /usr, because the
normal location is under /usr/doc, and all files in the %files
section must start with one of the directories named with
Prefix: directives.
</para>
</sect2>
</sect1>
<sect1>
<title>Defining Conditional Builds</title>
<para>
With the ability to define macros inside spec files, and also to
use macros defined elsewhere, you gain a lot of control over how
your package gets built. You can go further, though, and use
special directives to perform only certain commands based on
certain conditions. This adds a powerful capability to your spec
files, and also makes it much easier to do things like build for
multiple versions of Linux or other operating systems, as well as
handle various backwards-compatibility issues.
</para>
<para>
To define conditional build commands, you need to create
conditional constructs in your package���s spec file. In addition,
you need to define macros that the conditional constructs use to
determine whether or not to execute a set of spec file directives.
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 21 for more on macro file locations, and Chapters 19
and 20 for more on using RPM on other versions of Linux and other
operating systems, respectively.
</para>
<para>
RPM supports a number of ways to make parts of your spec file
enabled or disabled based on certain conditions. These include
conditional macros, conditional blocks, and special directives
based on the system architecture.
</para>
<sect2>
<title>Defining conditional macros</title>
<para>
You can use a special syntax to test for the existence of
macros. For example:
</para>
<para>
%{?macro_to_test: expression}
</para>
<para>
This syntax tells RPM to expand the expression if the macro
macro_to_test exists. If the macro macro_to_test does not exist,
nothing will be output. You can also reverse this test. A
leading exclamation point, !, tests for the non-existence of a
macro:
</para>
<para>
%{!?macro_to_test: expression}
</para>
<para>
In this example, if the macro_to_test macro does not exist, RPM
will expand the expression.
</para>
<para>
If you want, you can omit the expression and just test for the
existence of the macro. If it exists, RPM will use the value of
the macro. If the macro does not exist, RPM will use nothing.
For example:
</para>
<para>
%build
</para>
<para>
./configure %{?_with_ldap}
</para>
<para>
make
</para>
<para>
In this case, if the _with_ldap macro exists, the value of that
macro will get passed on the command line to the configure
script. If the _with_ldap macro does not exist, nothing extra
will be passed on the command line to the configure script. This
is very important when creating commands to build or install
packages.
</para>
<para>
Cross Reference
</para>
<para>
Many of the macros you will test this way are set up with the
--with command-line parameter. See Chapter 19 for details.
</para>
</sect2>
<sect2>
<title>Using conditional blocks</title>
<para>
The %if macro enables all the directives up to the %endif
directive, if the condition is true. This is much like scripting
languages. For example:
</para>
<para>
%if %{old_5x}
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%endif
</para>
<para>
In this case, if the %old_5x macro has a value, the test will be
true and all the directives inside the block will get executed.
</para>
<para>
A %else allows you to specify what to do if the test is not
successful. For example:
</para>
<para>
%if %{old_5x}
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%else
</para>
<para>
%define b6x 1
</para>
<para>
%undefine b5x
</para>
<para>
%endif
</para>
<para>
In this case, if the %old_5x macro has a value, then all the
directives up to the %else will get executed. Otherwise, if the
%old_5x macro has no value, the directives from the %else to the
%endif will get executed.
</para>
<para>
Again, use an exclamation point to negate the test. For example:
</para>
<para>
%if ! %{old_5x}
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%endif
</para>
<para>
You can use a && for an AND test. For example:
</para>
<para>
%if %{old_5x} && %{old_6x}
</para>
<para>
%{error: You cannot build for .5x and .6x at the same time}
</para>
<para>
%quit
</para>
<para>
%endif
</para>
</sect2>
<sect2>
<title>Using architecture-based conditionals</title>
<para>
In addition to the general-purpose %if conditional directive,
you can use special directives that test for processor
architecture and operating system.
</para>
<para>
The %ifarch directive enables all the directives up to the
%endif directive, if the processor architecture matches the
values you pass to the %ifarch directive. For example:
</para>
<para>
%ifarch sparc
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%endif
</para>
<para>
This block will only get executed if the processor architecture
is SPARC.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 21 covers RPM architecture and operating system names.
</para>
<para>
You can pass more than one architecture name, separated by
commas or spaces. For example:
</para>
<para>
%ifarch sparc alpha
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%endif
</para>
<para>
This example tests if the processor architecture is SPARC or
Alpha.
</para>
<para>
As with the %if directive, you can also use an %else, to cover
all cases where the test is not true. For example:
</para>
<para>
%ifarch sparc alpha
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%else
</para>
<para>
%define b6x 1
</para>
<para>
%undefine b5x
</para>
<para>
%endif
</para>
<para>
This example tests if the processor architecture is SPARC or
Alpha. If so, the directives from the %ifarch to the %else are
executed. If not, the directives from the %else to the %endif
are executed.
</para>
<para>
The %ifnarch directive reverses the %ifarch test. That is,
%ifnarch tests if the architecture is not one of the values
listed. The following example tests if the processor
architecture is not an i386 or an Alpha.
</para>
<para>
%ifnarch i386 alpha
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%endif
</para>
<para/>
<para>
The %ifos directive tests for the operating system. For example:
</para>
<para>
%ifos linux
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%endif
</para>
<para>
This example tests if the operating system is Linux. You can
reverse the test with the %ifnos directive. For example:
</para>
<para>
%ifnos irix
</para>
<para>
%define b5x 1
</para>
<para>
%undefine b6x
</para>
<para>
%endif
</para>
<para>
This example tests if the operating system is not Irix.
</para>
</sect2>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter covers advanced topics in creating packages.
Dependencies are very important. You need to specify which
packages or capabilities your package requires, so the RPM system
can ensure that all requirements are met before allowing users to
install the package. If you do not specify the dependencies
properly, then you are defeating the integrity of the RPM system.
</para>
<para>
In addition to specifying what your package requires, it is also
important to specify other dependency information. For example, if
your package conflicts with another package, you need to very
clearly state this. E-mail and Web server packages often conflict
with other servers of the same type.
</para>
<para>
You can specify both package dependencies as well as build
dependencies. For example, you may need certain developer
libraries to build your package, but not to install it. These are
build dependencies.
</para>
<para>
To help manage dependencies between packages and system
configuration issues, you can set up trigger scripts. A trigger is
a script in your package that gets executed when another package
is installed or removed. If your package, for example, is an
e-mail client program, it may need to execute a script should the
e-mail server package change. This is a great usage for triggers.
</para>
<para>
If your package has a complicated installation, the normal RPM
verification won���t be sufficient. To help the RPM system ensure
the integrity of all the packages, you can write a verify script
in your spec file to perform any extra commands necessary to
verify your package has been properly installed.
</para>
<para>
Relocatable packages allow users to install your packages in
different locations than originally planned. This is very useful
when working with more than one version of Linux, or with other
operating systems. For example, most Linux commands are stored in
/usr/bin, at least for Red Hat Linux. Other Linux distributions,
or other operating systems may specify that programs added to the
original set should be stored in /opt/bin and not /usr/bin, for
example. Making your package relocatable helps users in these
situations.
</para>
<para>
Conditional directives in your spec file allow you to control the
build on different processor architectures and operating systems.
The %if directive tests if a value is set. If so, then all the
directives up to the %endif directive are executed. If you need to
execute a different set of directives, use %else. In this case, if
the %if test is true, RPM executes the directives up to the %else.
If the test is not true, RPM executes the directives up to the
%endif.
</para>
<para>
Once you have your spec file defined, the next step is to start
building packages. The next chapter covers options for the
rpmbuild command and how you can use rpmbuild to make your
packages.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
18 years, 6 months
rpm-guide Makefile,NONE,1.1
by fedora-docs-commits@redhat.com
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv312
Added Files:
Makefile
Log Message:
--- NEW FILE Makefile ---
###############################################################################
# Makefile for RHLP docs project
# Created by: Tammy Fox <tfox(a)redhat.com>
# Last edited by: Tammy Fox <tfox(a)redhat.com>
# WARNING: need passivetex 1.24 for pdf generation to work
# License: GPL
# Copyright 2003 Tammy Fox, Red Hat, Inc.
###############################################################################
LANGUAGES = en
DOCBASE = rpm-guide
XMLEXTRAFILES-en =
######################################################
include ../docs-common/Makefile.common
######################################################
$(DOCNAME)/index.html::
mkdir -p $(DOCNAME)/figs
cp figs/*.png figs/*.eps $(DOCNAME)/figs
18 years, 6 months
example-tutorial Makefile,1.13,1.14
by fedora-docs-commits@redhat.com
Author: pfrields
Update of /cvs/docs/example-tutorial
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv23387
Modified Files:
Makefile
Log Message:
Properly clean up rpm packages
Index: Makefile
===================================================================
RCS file: /cvs/docs/example-tutorial/Makefile,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- Makefile 3 Oct 2005 02:42:37 -0000 1.13
+++ Makefile 3 Oct 2005 02:46:04 -0000 1.14
@@ -49,7 +49,7 @@
clean::
- rm -rf $(DOCBASE)*.rpm
+ rm -rf fedora-doc-$(DOCBASE)*.rpm
rpm: clean
18 years, 7 months
example-tutorial Makefile,1.12,1.13
by fedora-docs-commits@redhat.com
Author: pfrields
Update of /cvs/docs/example-tutorial
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv23330
Modified Files:
Makefile
Log Message:
Test twice before you commit, stupid
Index: Makefile
===================================================================
RCS file: /cvs/docs/example-tutorial/Makefile,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- Makefile 3 Oct 2005 02:35:37 -0000 1.12
+++ Makefile 3 Oct 2005 02:42:37 -0000 1.13
@@ -77,12 +77,14 @@
# FIXME: Needs to be multiplexed for LANGUAGES (see above)
cp $(OMFIN) $(DOCOMF)
cp $(DESKTOPIN) $(DOCDESKTOP)
- for file in $(DOCOMF) $(DOCDESKTOP); do \
- sed -i 's/@VERSION@/$(VERSION)/g' $(DOCOMF) ; \
- sed -i 's/@DATE@/$(DATE)/g' $(DOCOMF) ; \
- sed -i 's/@TITLE@/$(TITLE)/g' $(DOCOMF) ; \
- sed -i 's/@DOCBASE@/$(DOCBASE)/g' $(DOCOMF) ; \
- done
+ sed -i 's/@VERSION@/$(VERSION)/g' $(DOCOMF)
+ sed -i 's/@DATE@/$(DATE)/g' $(DOCOMF)
+ sed -i 's/@TITLE@/$(TITLE)/g' $(DOCOMF)
+ sed -i 's/@DOCBASE@/$(DOCBASE)/g' $(DOCOMF)
+ sed -i 's/@VERSION@/$(VERSION)/g' $(DOCDESKTOP)
+ sed -i 's/@DATE@/$(DATE)/g' $(DOCDESKTOP)
+ sed -i 's/@TITLE@/$(TITLE)/g' $(DOCDESKTOP)
+ sed -i 's/@DOCBASE@/$(DOCBASE)/g' $(DOCDESKTOP)
#
# Do the build...
#
18 years, 7 months
docs-common/packaging fedora-doc.desktop.in.common,1.1,1.2
by fedora-docs-commits@redhat.com
Author: pfrields
Update of /cvs/docs/docs-common/packaging
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv23291
Modified Files:
fedora-doc.desktop.in.common
Log Message:
Fix oopsie in desktop file
Index: fedora-doc.desktop.in.common
===================================================================
RCS file: /cvs/docs/docs-common/packaging/fedora-doc.desktop.in.common,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- fedora-doc.desktop.in.common 3 Oct 2005 02:32:06 -0000 1.1
+++ fedora-doc.desktop.in.common 3 Oct 2005 02:38:12 -0000 1.2
@@ -1,8 +1,8 @@
[Desktop Entry]
Encoding=UTF-8
Categories=Application;Documentation;X-Red-Hat-Base;
-Name=@NAME@
-GenericName=@NAME@
+Name=@TITLE@
+GenericName=@TITLE@
Exec=gnome-help file:///usr/share/fedora/doc/fedora-doc-@DOCBASE@/C/@DOCBASE@-en.xml
Icon=icon-documentation.png
Terminal=false
18 years, 7 months
example-tutorial Makefile,1.11,1.12
by fedora-docs-commits@redhat.com
Author: pfrields
Update of /cvs/docs/example-tutorial
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv23259
Modified Files:
Makefile
Log Message:
Some ugly Makefile changes to test rpm buliding
Index: Makefile
===================================================================
RCS file: /cvs/docs/example-tutorial/Makefile,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- Makefile 17 Sep 2005 14:41:42 -0000 1.11
+++ Makefile 3 Oct 2005 02:35:37 -0000 1.12
@@ -26,3 +26,68 @@
# line:
#${DOCBASE}-en/index.html::
# echo FINISHED AT LAST
+
+
+######################################################
+# Some packaging specific vars
+VERSION=$(shell grep BOOKID $(DOCBASE)-en.xml | sed 's/<!ENTITY BOOKID "[^0-9\.]\+//' | sed 's/ .\+//')
+DATE=${shell grep BOOKID $(DOCBASE)-en.xml | sed 's/.\+(//' | sed 's/).\+//' }
+NOW=$(shell date +"%a %b %e %Y")
+SPECIN=../docs-common/packaging/fedora-doc.spec.in.common
+OMFIN=../docs-common/packaging/fedora-doc.omf.in.common
+DESKTOPIN=../docs-common/packaging/fedora-doc.desktop.in.common
+DOCSPEC=$(PWD)/SPECS/$(DOCBASE).spec
+DOCOMF=$(PWD)/SOURCES/fedora-doc-$(DOCBASE)-C.omf
+DOCDESKTOP=$(PWD)/SOURCES/fedora-doc-$(DOCBASE).desktop
+DOCSRCTAR=$(PWD)/SOURCES/$(DOCBASE)-$(VERSION).src.tar.gz
+TITLE=$(shell ../docs-common/packaging/titlegrab.py $(DOCBASE)-en.xml)
+######################################################
+# Some RPM flags...
+######################################################
+RPMFLAGS=--define "docbase $(DOCBASE)" --define "version $(VERSION)" --define "_topdir $(PWD)"
+######################################################
+
+
+clean::
+ rm -rf $(DOCBASE)*.rpm
+
+
+rpm: clean
+#
+# Make RPM-compliant tarball of source XML and other stuff
+ mkdir $(DOCBASE)-$(VERSION)
+ find . -maxdepth 1 -type f ! \( -name '*~' -o -name 'Makefile*' \) \
+ | cpio -pamdv $(DOCBASE)-$(VERSION)
+ find . -maxdepth 1 -type d ! \( -name '$(DOCBASE)-$(VERSION)' \
+ -o -name 'CVS' -o -name '*~' -o -name '$(DOCBASE)*' \) \
+ | cpio -pamdv $(DOCBASE)-$(VERSION)
+#
+# Make RPM build tree; don't rely on local user's setup
+ mkdir -p {BUILD,RPMS/noarch,SOURCES,SPECS,SRPMS}
+ tar -zcvf $(DOCSRCTAR) $(DOCBASE)-$(VERSION)
+ rm -rf $(DOCBASE)-$(VERSION)/
+#
+# Make rpmlint happy with a changelog entry
+# FIXME: Maybe more magic would make this stickier; pity
+# I'm no magician...
+ sed 's/\(%changelog\)/\1\n* $(NOW) Fedora Docs Project <fedora-docs-list(a)redhat.com> - $(VERSION)-1\n- Update to version $(VERSION)\n/' \
+ $(SPECIN) > $(DOCSPEC)
+#
+# Fill in files
+# FIXME: Needs to be multiplexed for LANGUAGES (see above)
+ cp $(OMFIN) $(DOCOMF)
+ cp $(DESKTOPIN) $(DOCDESKTOP)
+ for file in $(DOCOMF) $(DOCDESKTOP); do \
+ sed -i 's/@VERSION@/$(VERSION)/g' $(DOCOMF) ; \
+ sed -i 's/@DATE@/$(DATE)/g' $(DOCOMF) ; \
+ sed -i 's/@TITLE@/$(TITLE)/g' $(DOCOMF) ; \
+ sed -i 's/@DOCBASE@/$(DOCBASE)/g' $(DOCOMF) ; \
+ done
+#
+# Do the build...
+#
+ rpmbuild -bb -vv $(RPMFLAGS) $(DOCSPEC)
+ mv RPMS/noarch/*.rpm .
+ rpmbuild --clean --rmsource $(RPMFLAGS) $(DOCSPEC)
+ rm -rf {BUILD,RPMS,SOURCES,SPECS,SRPMS}
+ rm -rf $(DOCBASE)-$(VERSION)
18 years, 7 months
docs-common/packaging fedora-doc.desktop.in.common, NONE, 1.1 fedora-doc.omf.in.common, NONE, 1.1 fedora-doc.spec.in.common, NONE, 1.1 titlegrab.py, NONE, 1.1
by fedora-docs-commits@redhat.com
Author: pfrields
Update of /cvs/docs/docs-common/packaging
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv23196/packaging
Added Files:
fedora-doc.desktop.in.common fedora-doc.omf.in.common
fedora-doc.spec.in.common titlegrab.py
Log Message:
Some materials for automatic package building, nothing gold yet
--- NEW FILE fedora-doc.desktop.in.common ---
[Desktop Entry]
Encoding=UTF-8
Categories=Application;Documentation;X-Red-Hat-Base;
Name=@NAME@
GenericName=@NAME@
Exec=gnome-help file:///usr/share/fedora/doc/fedora-doc-@DOCBASE@/C/@DOCBASE@-en.xml
Icon=icon-documentation.png
Terminal=false
Type=Application
Comment=Official Fedora documentation
--- NEW FILE fedora-doc.omf.in.common ---
<?xml version="1.0" encoding="UTF-8"?>
<omf>
<resource>
<creator>
fedora-docs-list(a)redhat.com (Fedora Documentation Project)
</creator>
<maintainer>
fedora-docs-list(a)redhat.com (Fedora Documentation Project)
</maintainer>
<title>
@TITLE@
</title>
<date>
@DATE@
</date>
<version identifier="@VERSION@" date="@DATE@" description="@DOCBASE@-@VERSION@ (@DATE@)"/>
<subject category="System|Other"/>
<description>
Official Fedora Documentation: @TITLE@
</description>
<type>@TITLE@</type>
<format mime="text/xml" dtd="-//OASIS//DTD DocBook XML V4.2//EN"/>
<identifier url="file:/usr/share/fedora/doc/fedora-doc-@DOCBASE@/C/@DOCBASE@-en.xml"/>
<language code="C"/>
<relation seriesid="7a5d3ea2-2a1e-11da-86a3-8ea47a4bb227"/>
<rights type="GNU FDL" license.version="1.1"/>
</resource>
</omf>
--- NEW FILE fedora-doc.spec.in.common ---
# Fedora documentation specfile skeleton
Summary: Fedora documentation: %{docbase}
Name: fedora-doc-%{docbase}
Version: %{version}
Release: 1
License: FDL
Url: http://fedora.redhat.com/projects/docs/
Source0: %{docbase}-%{version}.src.tar.gz
Source1: %{name}-C.omf
Source2: %{name}.desktop
Group: Documentation
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-root
Requires: scrollkeeper >= 0.3.11
Requires: fedora-doc-common
BuildRequires: scrollkeeper
BuildRequires: xmlto
%description
This package contains official the Fedora documentation %{docbase}.
For more information, refer to the Fedora Documentation Project.
%prep
%setup -q -n %{docbase}-%{version}
%{__sed} -i 's!../docs-common/!../../docs-common/!' \
$RPM_BUILD_DIR/%{docbase}-%{version}/%{docbase}-en.xml
%build
# Perhaps we will require an HTML chunked build here for use with KDE;
# not sure yet.
%install
rm -rf $RPM_BUILD_ROOT
install -d -m 755 $RPM_BUILD_ROOT/%{_datadir}/omf/%{name}
install -m 644 %{SOURCE1} $RPM_BUILD_ROOT/%{_datadir}/omf/%{name}
install -d -m 755 $RPM_BUILD_ROOT/%{_datadir}/fedora/doc/%{name}/C
install -m 644 $RPM_BUILD_DIR/%{docbase}-%{version}/*.xml \
$RPM_BUILD_ROOT/%{_datadir}/fedora/doc/%{name}/C
for d in `find -type d $RPM_BUILD_DIR/%{docbase}-%{version}`
do
dname=`basename ${d}`
install -d -m 755 \
$RPM_BUILD_ROOT/%{_datadir}/fedora/doc/%{name}/C/${dname}
install -m 644 $RPM_BUILD_DIR/%{docbase}-%{version}/${dname}/* \
$RPM_BUILD_ROOT/%{_datadir}/fedora/doc/%{name}/C/${dname}
done
install -d -m 755 $RPM_BUILD_ROOT/%{_datadir}/applications
install -m 644 %{SOURCE2} \
$RPM_BUILD_ROOT/%{_datadir}/applications/%{name}.desktop
%clean
rm -rf $RPM_BUILD_ROOT
%post
scrollkeeper-update
exit 0
%postun
scrollkeeper-update
exit 0
%files
%defattr(-, root, root,-)
%docdir %{_datadir}/fedora/doc/%{name}
%{_datadir}/fedora/doc/%{name}/*
%dir %{_datadir}/omf/%{name}
%{_datadir}/omf/%{name}/*
%{_datadir}/applications/%{name}.desktop
%changelog
--- NEW FILE titlegrab.py ---
#!/usr/bin/python -d
import sys
import xml.dom.minidom
from xml.dom.minidom import Node
xml_files = sys.argv[1:]
if xml_files == []:
print "Usage: titlegrab.py xml_file..."
sys.exit (2)
for file in xml_files:
doc = xml.dom.minidom.parse(file)
title = ""
for node in doc.getElementsByTagName("articleinfo"):
T = node.getElementsByTagName("title")
for node2 in T:
for node3 in node2.childNodes:
if node3.nodeType == Node.TEXT_NODE:
title += node3.data
if title == "":
# Hmm, must not be an <article> then
for node in doc.getElementsByTagName("bookinfo"):
T = node.getElementsByTagName("title")
for node2 in T:
for node3 in node2.childNodes:
if node3.nodeType == Node.TEXT_NODE:
title += node3.data
print title
18 years, 7 months