Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv831
Added Files:
rpm-guide-packaging-guidelines-en.xml
Log Message:
--- NEW FILE rpm-guide-packaging-guidelines-en.xml ---
<!-- $Id: -->
<chapter id="ch-packaging-guidelines">
<title>Packaging Guidelines</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>
*Avoiding common mistakes
</para>
<para>
*Following good practices
</para>
<para>
RPM is a complex system that helps manage thousands of packages for
a complex operating system. Furthermore, RPM is very, very flexible.
This flexibility makes it important that you follow the rules to
create packages the proper way. Otherwise, you���ll face a host of
problems with your RPMs. Following some best practices guidelines
will help you avoid future problems as you release RPM updates.
</para>
<para>
This chapter covers ways to avoid common problems as well as
best-practice guidelines for creating your own RPMs.
</para>
<sect1>
<title>Avoiding Common Problems</title>
<para>
Developers creating RPMs seem to hit many of the same roadblocks.
This section covers some of the most common problems faced by RPM
users and package builders.
</para>
<para>
Warning
</para>
<para>
Never, never, never build RPMs logged in as the root user. See the
section on Building for details.
</para>
<sect2>
<title>Scan the mailing lists</title>
<para>
Many people have tried to solve a lot of serious problems that
arise when using RPM, so if you are facing difficulties, chances
are someone else has tackled those issues before. The RPM
mailing list provides a technical forum for discussing RPM
issues and problems. In many, if not most, cases, you can find
answers to problems by scanning the mailing list archives.
</para>
<para>
You can also sign up for the mailing list so that you can send
in requests and see the responses.
</para>
<para>
Cross Reference
</para>
<para>
For details on viewing the RPM mailing list archives and signing
up for the list, see
www.rpm.org/mailing_list/. See
<ulink
url="http://groups.yahoo.com/group/rpm-list/messages">http:/...
for an archive of the list.
</para>
<para>
If you are working with RPMs and pushing the envelope for other
operating systems or complicated packages, this list is
definitely worth a look.
</para>
<para>
Before sending any messages, though, be sure to look through the
message archives to see if the message has already been
answered. You will save time waiting for a response if you can
get an archived response right away.
</para>
<para>
You should also ask any questions in a way that will generate
the most helpful responses. This includes:
</para>
<para>
Do your homework first. Check to see if your question has
already been answered by looking at the mailing list or
newsgroup archives. In the end, this saves you the most time, as
you don���t have to wait for answers.
</para>
<para>
Describe the problem and the symptoms as clearly as possible.
After all, this is what you want help with.
</para>
<para>
Use clear subject headers. This is the first part of your
message that people will read. If you are not clear, the key
people who could answer your questions may never even read your
message. And, if they don���t read the message, you will never
get an answer.
</para>
<para>
Send your message in plain text, not HTML. Do not include a
separate HTML copy of your message. This just makes it harder to
read, especially for people who read collected digests of
mailing lists.
</para>
<para>
Make it easy for people to reply to you. Include your email
address in your message. You might want to include a line that
states something like ���Please send your reply to me at��� and
then provide your email address.
</para>
<para>
Cross Reference
</para>
<para>
These tips on asking questions come from the Internet document
on How to Ask Questions the Smart Way by Eric Steven Raymond and
Rick Moen, available at multiple sites, including
www.owlriver.com/tips/smart.
</para>
<para>
In addition to the RPM mailing list, there is also a Usenet
newsgroup, named linux.redhat.rpm. You can read this newsgroup
with any newsreading program.
</para>
<para>
Note
</para>
<para>
Newsgroups are sometimes called discussion groups.
</para>
</sect2>
<sect2>
<title>Use rpmbuild</title>
<para>
In older versions of RPM, you called the rpm ���ba command to
build RPMs. With RPM 4.1, you must use the rpmbuild command. If
you have the rpmbuild command available, even if you are running
an older version of RPM, run rpmbuild instead of rpm to build
your RPMs.
</para>
<para>
You���d be surprised at how such a simple item is one of the
most-asked questions on the RPM mailing list. That���s because
the rpm ���ba command, and the other ���b options, no longer
work in RPM 4.1. These options are supported by the rpmbuild
command.
</para>
</sect2>
<sect2>
<title>Don���t try to defeat the system</title>
<para>
If you are finding your spec files getting more and more
complex, and that you are trying to disable RPM features,
chances are you are trying to defeat the system. This is not a
good idea.
</para>
<para>
The RPM system works in a certain way. You may not always agree
with the way it works, but if you try to make it work in
contrary ways, in most cases you���ll end up fighting RPM to no
avail.
</para>
<para>
There are certain rules, and more importantly certain
conventions that RPMs should follow. The previous chapters in
this section on building RPMs have outlined those conventions.
Follow them. When you go against these conventions, you are
really trying to defeat how the RPM system works.
</para>
</sect2>
<sect2>
<title>Turn off automatic dependency generation</title>
<para>
When you build an RPM, the rpmbuild command will automatically
generate dependencies on Linux shared libraries and other system
commands. You can turn this off if you need to, using a number
of means.
</para>
<para>
You can disable the automatic generation of dependencies by
placing the following directive in your spec file:
</para>
<para>
Autoreq: 0
</para>
<para>
A better approach, though, is to override the %{__find_requires}
and %{__find_provides} macros, or just one of these as needed.
You can null out either of these macros by adding commands like
the following to your spec file:
</para>
<para>
%define __find_requires %{nil}
</para>
<para>
This approach is better because it allows you to override only
the requires checks. In addition, you can get more specific and
simply change how the automatic dependency checks are performed.
For example, you can also change the definitions of these macros
to perform normal dependency generation except for any
problematic files or packages. These two macros resolve to shell
scripts that perform the automated dependency checks, as you can
see with the rpm --eval command:
</para>
<para>
$ rpm --eval "%__find_provides"
</para>
<para>
/usr/lib/rpm/find-provides
</para>
<para>
rpm --eval "%__find_requires"
</para>
<para>
/usr/lib/rpm/find-requires
</para>
<para>
You can override these scripts to filter out any dependencies
that cause problems for your packages.
</para>
</sect2>
<sect2>
<title>Don't list directories in %files</title>
<para>
Unless you really mean it, don���t list directories in your
%files section in your spec files. That is because the rpmbuild
program will automatically add all files in that directory to
your RPM. If this is a system directory, such as /usr/bin, your
RPM has now claimed ownership for all the files, regardless of
the source package.
</para>
<para>
To avoid all files in the directory becoming part of the
package, list the files explicitly, perhaps generating the list
of files as the program builds.
</para>
<para>
If you do need a directory installed as part of your package,
use the %dir directive, described in Chapter 10.
</para>
</sect2>
<sect2>
<title>Handling circular dependencies</title>
<para>
If two packages each depend on the other, you don���t want each
package���s spec file to list the other in a Requires section.
If this occurs, the packages won���t install without one of the
force options, since each package will require the other to be
installed first.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 4 covers how to install or upgrade packages while
ignoring dependency checks. In general, you do not want to
ignore these checks.
</para>
<para>
You can work around this issue by using the PreReq directive
instead of Requires. For example, if package A depends on B and
package B depends on A, you can place the following in the
package B spec file:
</para>
<para>
PreReq: A
</para>
<para>
In addition, you can install both packages at the same time to
avoid some of the problems with circular dependencies. Simply
include both packages on the rpm ���Uvh command line.
</para>
</sect2>
</sect1>
<sect1>
<title>Following Good Practices</title>
<para>
Working through problems is one thing. It���s best, however, to
set up an environment to help avoid problems all together. The
following sections cover what are considered the best practices
for creating RPMs.
</para>
<para>
Before you make an RPM, you should plan out what you intend to
build and how it will be structured. As you build the RPM, you
want to watch out for things that can go wrong, and work from a
known clean environment.
</para>
<sect2>
<title>Preparation</title>
<para>
Before you start to make an RPM, you need to follow a few steps
to ensure you have everything ready.
</para>
<sect3>
<title>Create a Source RPM</title>
<para>
Having a source RPM allows you to transfer all the sources for
a package from one system to another, along with all the
instructions coded in the spec file for actually building the
binary package. This is very handy for keeping track of
software, and it is also very important since you can
regenerate the binary RPM at any time from the source RPM. In
other words, make the generation of RPMs follow the RPM
conventions and fit this into your normal software build
process.
</para>
<para>
This means that for each RPM you want to build, you really
need two: a source and a binary RPM. This isn���t that hard to
do, since you can easily make a source RPM into a binary RPM
with the rpmbuild command.
</para>
</sect3>
<sect3>
<title>Start with Pristine Sources</title>
<para>
In addition to planning on making a source RPM, you should
also start with pristine, unmodified sources for the
application you plan to package as an RPM. Starting with
pristine sources means you can reproduce the entire process
and recreate the RPM from scratch if necessary. (Quality
control and configuration management people really appreciate
this.)
</para>
<para>
The pristine sources should be exactly the sources you got
when you downloaded the application, or acquired it in house.
This doesn���t mean that you won���t have to modify the
sources eventually. For that, you create patches. The key is
just to start the process with unmodified sources.
</para>
<para>
Some RPMs have nearly 100 patches that the rpmbuild command
applies when building the RPM. That is a lot of patches, too
many for most applications. Even so, the process is the same.
Create a patch or patches for all the changes you need to
make. You can easily specify patches in the spec file.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 10 covers the spec file.
</para>
<para>
Keeping your patches separate from the original sources makes
it easier to reproduce the RPM from scratch, and makes it
easier to integrate a new version of the base software, since
your code, in the form of patches, is separated from the base
software code.
</para>
</sect3>
<sect3>
<title>Decide What Goes In Each Package</title>
<para>
You don���t have to stuff all your software into one RPM.
Instead, you can often simplify your RPM by dividing it into
two or three separate (but likely dependent) RPMs.
</para>
<para>
For example, the RPM system itself has one RPM for the basic
system, rpm, one for developers of the RPM system, rpm-devel,
and one for those building RPMs, rpm-build. Yet another RPM
provides the Python programming API, rpm-python.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 17 covers Python programming.
</para>
<para>
This last division is important. The Python RPM draws in as a
dependency the Python system itself. Adding this into, say,
the core RPM package would needlessly complicate the
dependencies for that package.
</para>
<para>
When dividing your software into RPMs, keep two main issues in
mind:
</para>
<para>
*You want to divide the software into RPMs that fit the model
for users of the system.
</para>
<para>
*You want to divide the software into RPMs such that the
separate RPMs are simpler to create and manage.
</para>
<para>
The RPM system follows these guidelines, especially the first.
Few users will extend the RPM system itself, which allows RPM
team to shed this functionality from the core RPM and contain
it in rpm-devel. Those who build RPMs fit into a different
category than those who use RPMs since just about everybody
needs to use RPMs to install packages, but few users actually
build RPMs. Again, the separation works from a user���s
perspective.
</para>
<para>
You also want your package divisions to make each package
easier to specify. You can break particularly tough
dependencies into smaller units and simplify things. If the
package division doesn���t simplify things, then it may not be
a good idea.
</para>
</sect3>
<sect3>
<title>Create a Test RPM Database</title>
<para>
You don���t always have to work with the system RPM database.
In fact, while developing RPMs, you probably don���t want to
change the system database.
</para>
<para>
If you have a test RPM database, you can install your RPMs
into this test database. To do so, use the --justdb, --dbpath,
--prefix, and --badreloc options. These options allow you to
install an RPM into just the database, using a different
database, with a different root file location (into a test
directory, for example) and handle all files that were not
marked for relocation, respectively.
</para>
<para>
Note
</para>
<para>
The --test option when installing also allows you to just test
the install, not actually perform it.
</para>
<para>
Combined, all these options mean you can use an RPM database
just set up for testing and that problems won���t impact your
working Linux systems. To make this work, though, you need a
test RPM database.
</para>
<para>
To be rigorous, you should create the test RPM database from
scratch from a known set of packages. This will allow you to
exactly verify the behavior of your RPM under different system
configurations. This is the best choice since you should
install the packages under a known, and non-root, directory
hierarchy to avoid having file problems with the working
system.
</para>
<para>
If you want to cheat, you can copy your real RPM database to
another directory and use that. Note that in this case, the
file paths in the database will point to the real file
locations on disk.
</para>
<para>
Regardless of how you create a test database, recreate the
database each time you run a test, so that you are sure of a
known starting state. Usually this is as simple as copying a
master test RPM database into a directory you use for running
tests.
</para>
</sect3>
</sect2>
<sect2>
<title>Building</title>
<para>
Building RPMs isn���t as easy as it should be. You���ll often
need to try again and again to get the rpmbuild command to
create a working RPM. This section covers best practices to
follow when performing the actual build of the RPM.
</para>
<sect3>
<title>Use Tools</title>
<para>
Using tools can help speed up the RPM-making process, as well
as give you a head start in learning how RPMs work.
RPM-building tools such as the Red Hat plugin for the Eclipse
Integrated Development Environment have proven really helpful.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 13 covers RPM-building tools. Appendix F covers the
Eclipse Integrated Development Environment.
</para>
<para>
Even though so-called real Linux hackers can make a working
virtual memory system with just the cat command, don���t scoff
at tools. Your time is too valuable.
</para>
<para>
Another useful tool is the gendiff program that comes with the
RPM release. The gendiff program makes it easier to create
patches by avoiding the need to keep a separate directory of
the original sources, The gendiff program also works on all
changed files within a directory, making a patch for
everything you modified.
</para>
<para>
To work with gendiff, you need to first save a backup copy of
each file you intend to edit prior to editing. Use a
consistent file-name extension for the saved copies of the
files, such as .orig, short for original. After you edit some
files, run the gendiff command as follows:
</para>
<para>
$ gendiff directory_name .saved_extension >
patch_name.patch
</para>
<para>
For example, if you saved the original files to a .orig
extension, you can create a patch in a directory named src
(short for sources) with a command like the following:
</para>
<para>
$gendiff src .orig > mypatch.patch
</para>
<para>
The patch file mypatch.patch will contain all the differences
detected for all files in the given directory.
</para>
</sect3>
<sect3>
<title>Never Build RPMs as Root</title>
<para>
Never, never, never build RPMs logged in as the root user.
Always build your RPMS while logged in as a normal user. This
is hard to remember since you must be logged in as root to
install an RPM. And you���ll want to test each RPM you create
to see if it can install cleanly.
</para>
<para>
Even so, never build RPMs logged in as the root user. The RPM
spec file has a number of scripts and commands. An error in
any of these could cause damage to your system. This includes
modifying files, removing files, or copying new contents on
top of system files. The root user has permission to perform
all these operations.
</para>
<para>
To avoid all this, build your RPMs while logged in as a normal
user. Any problematic scripts should generate errors.
</para>
</sect3>
<sect3>
<title>Create a Digital Signature</title>
<para>
RPM 4.1 and later revisions place more importance on signing
your packages. The rpm command will, by default, verify
signatures on each package it reads.
</para>
<para>
Therefore, you should create a digital signature for your
packages, if only to meet user expectations. In addition, you
should place a copy of your digital signature on your
organization���s Web site and public key servers. Having
multiple copies in multiple locations helps prevent malicious
users from impersonating your keys.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 12 covers signing packages.
</para>
</sect3>
<sect3>
<title>Copy Smartly</title>
<para>
Your Linux distribution probably includes more than one CD-ROM
chock full of RPMs. Each of these RPMs has a spec file. You
can examine these spec files and see how others choose to
build their RPMs. Rather than starting from scratch, you can
copy declarations from these spec files into your spec file.
</para>
<para>
Not all these packages were made smartly. Some spec files, as
you will see, are a large mess. Obviously, don���t copy these.
Look for clean spec files with clear directives.
</para>
</sect3>
<sect3>
<title>Set Up the BuildRoot</title>
<para>
A BuildRoot directive sets the location where your code will
be built. The convention is for you to define a subdirectory
beneath the _tmppath directory. For example:
</para>
<para>
BuildRoot: %{_tmppath}/%{name}-buildroot
</para>
<para>
Once set, rpmbuild defines the RPM_BUILD_ROOT environment
variable to the value specified for the BuildRoot.
</para>
<para>
With the rpmbuild command, you can use the --buildroot option
to specify a directory to use to override the BuildRoot
directive in the spec file.
</para>
<para>
Using a BuildRoot set to a directory that normal users have
write access to allows you to build the package logged in as a
normal user. It also helps separate the contents of your
package from those of other RPMs.
</para>
<para>
Always define a BuildRoot.
</para>
</sect3>
<sect3>
<title>Add changelog entries for each new version</title>
<para>
Each time you create a new version in RPM format, you should
add an entry to the change log. This allows administrators to
get a better idea about what changed from the previous
version.
</para>
<para>
The change log can help people decide whether or not to
upgrade a package. A log entry about a security fix, for
example, provides useful information to users.
</para>
</sect3>
<sect3>
<title>Define the Group For Your Package</title>
<para>
Packages are categorized into groups. These group names, while
not always the best, appear in the graphical tools such as the
Red Hat package manager. If your application is a Linux shell
program, then users will expect to find it in the System
Environment/Shells group and not the Development/Languages or
System Environment/Daemons groups. This is a rather small
detail, but it helps users find your package in the huge array
of Linux RPMs.
</para>
<para>
The official list of RPM groups is located in
/usr/share/doc/rpm-4.1/GROUPS for RPM 4.1, and similarly-named
directories for other RPM versions.
</para>
</sect3>
</sect2>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter covers guidelines for avoiding problems when creating
RPMs and following best practices to avoid future problems as
well.
</para>
<para>
When trying to avoid common problems, your best starting point is
the RPM mailing list and newsgroup.
</para>
<para>
For best practices, you should start at the very beginning when
you are planning what to build into an RPM. Always start with
pristine sources and then patch as needed. Your RPM should include
the pristine sources and any necessary patches. You should always
create a source RPM, so that you can reproduce your RPM anywhere.
</para>
<para>
When building RPMs, copy good examples of spec files, as this will
get you going far more quickly than any other technique. Use tools
to help automate parts of your RPM-building process.
</para>
<para>
Never build RPMs when logged in as the root user.
</para>
<para>
This chapter ends the section on building RPMs. The next section
covers programming to the RPM APIs.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->