i'm not sure what the user population is on this group
by now, but i've just finished another revision of my
"building rpms" doc and am already on to the next revision.
i'm interested in any feedback regarding corrections or
ambiguities in this one.
rday
--
Robert P. J. Day
Eno River Technologies, Chapel Hill NC
Unix, Linux and Open Source corporate training
"The Right seems determined to prove that government is
bad by giving us spectacularly bad government."
* Overview -- building a noarch RPM
This document describes, using a concrete example, how to build
a non-architecture-specific (or "noarch") RPM that you might use
to distribute non-binary-program-related files and directories such
as text files, audio or video files, font files or even script
programs such as shell or Perl programs, along with some
accompanying documentation files such as README or COPYRIGHT
files.
Building a noarch RPM is typically simpler than building one
involving compiled programs, since the latter almost always involves
compiling source files into binary executables using steps like
"configure" and "make". While building a noarch RPM is clearly
a simpler and more restrictive thing to do, it's still often
just what you want and, in addition, I've deliberately explained
it in a way that teaches you how to easily extend to the more
complicated binary program case. In other words, this is a
good place to start if you want to go further.
Before we start, I'll assume that you're already familiar with
how to use the "rpm" command to do basic things like install,
examine and remove RPMs. In addition, if you haven't already, you
should install the "rpm-build" RPM, which is essential for rolling
your own RPMs.
Finally, there are all kinds of ways you can customize, extend
and just plain fancy up how to do this. I'm going out of my way
to keep it simple and use the rules for good RPM construction as
I understand them.
(Toward the end, I'll throw in how to construct the corresponding
source RPM, just in case you want to allow others to build the
noarch RPM themselves, or to see how you did it.)
* The hypothetical scenario
Imagine that, as employee Fred Berferd of Pics 'r' Us, Inc., your
job is to build an RPM consisting solely of images of various
cats, along with the documentation files README and COPYRIGHT.
Since this will be the company's very first cat-pic-related RPM,
it will have the designations:
package name: catpics
version: 1.0
release: 1
which suggests that the final RPM should have the name
catpics-1.0-1.noarch.rpm. You've been told to build this RPM file
so that, when the customer installs it on their system, it will
unload files and directories in the locations:
/usr/local/catpics/<cat image files>
/usr/share/doc/catpics-1.0/{README, COPYRIGHT}
So, let's start building catpics-1.0-1.noarch.rpm.
* The RPM building directory structure
If you're using Red Hat Linux, there is already a pre-defined
directory structure set up to support building your own RPMS.
If you look under /usr/src/redhat, you'll notice a number of
directories and subdirectories, which would be used automatically
if you try to build your own RPMs as root.
Since it's generally considered a hanging offense to build
RPMs as root, you're *strongly* encouraged, as a normal user,
to duplicate that directory structure under your home directory
somewhere and use those directories for all builds. Pick a
reasonable top-level name (say, "rpm"), and duplicate those
directories:
$ cd
$ mkdir -p rpm/{SOURCES,SPECS,BUILD,RPMS,SRPMS}
$ mkdir -p rpm/RPMS/{i386,i586,i686,noarch}
$ mkdir rpm/tmp # to be explained shortly
In addition, force the "rpm" command to use these directories by
creating the config file ~/.rpmmacros with the contents:
%_topdir /home/fred/rpm
%_tmppath /home/fred/rpm/tmp
OK, so what are all these ~/rpm/ directories for? In chronological
order of use:
SOURCES: where you'll load your initial collection of image
files and documentation files, in some form, from
which to build the RPM
SPECS: where you'll define the "spec" file for this new
RPM, which will define how you want to build it and
what the final noarch RPM should look like
BUILD: the build directory, where the files from the SOURCES
directory will be loaded to be processed or "built"
in preparation for constructing the RPM
tmp: your "temporary" directory for each RPM to be built,
where you construct the directory structure for each RPM
just the way it should look when it is later installed.
RPMS/noarch: where the new RPM will be placed for your inspection
and approval at the very end of the process
In chronological order, then, let's start with what you have to
load into your SOURCES directory to get this process rolling.
* Building the tarball
While there are various ways to generalize this step, I'll keep it
simple. Your first step is to copy into the SOURCES directory the
collection of image files, documentation files and whatever else you
want to build into your new RPM. But in what format?
The best format is to create a "tarball" -- that is a gzipped
tar archive -- from which you can extract the files later. Tradition
suggests that, in your case, you name this file catpics-1.0.tar.gz, or
catpics-1.0.tgz for short. One possibility for its contents (assuming
a collection of four cats) might be:
$ tar tvf catpics-1.0.tgz
catpics-1.0/
catpics-1.0/pics/
catpics-1.0/pics/jones.jpg
catpics-1.0/pics/xena.jpg
catpics-1.0/pics/clarence.jpg
catpics-1.0/pics/elliott.jpg
catpics-1.0/COPYRIGHT
catpics-1.0/README
Things to notice about the tarball:
- It does, in fact, contain all the files you need for the new RPM.
- It should have a top-level directory name that matches the RPM
name and version, which will keep your life simple later.
- The location of the tarball files do *not* have to match their
eventual location in the RPM or where they're going to be
installed -- as long as you know where they are in the tarball,
and can get at them later, that's all that counts.
- Specifically, the location of the documentation files don't
have to match their eventual location in the new RPM. In fact,
if you place documentation files immediately below the top-level
directory in the tarball, you can use a convenient shortcut
later, so that's what we'll do.
All right, now that you have your tarball, it's time to design your
spec file.
* The spec file
** What's a spec file?
A spec file contains, among other things, a preamble, which
defines information about your new RPM, followed by one or more
of the prep, build, install and clean stages, which explain how
to extract files from the tarball, how to possibly make and
configure those files to generate new files, how to construct
(or "install") those files into a new directory structure that
will match the final directory structure in the RPM, and a cleaning
stage to remove all of the intermediate results you don't need
anymore, finally followed by a files list of precisely which
files you want to load into your new RPM and at exactly which
locations, which is where they will be unloaded by the new
user.
Technically, the spec file can be created anywhere, but it's
traditional to create it in your SPECS directory.
We can explain these parts of the spec file one at a time.
(If, at any time, you want to see the spec file in its
entirety, see Appendix A.)
** The preamble
Consider a possible preamble for our catpics-1.0 RPM:
----- begin preamble -----
Summary: CatPics, a collection of feline images
Name: catpics
Version: 1.0
Release: 1
Copyright: GPL
Group: Amusements/Graphics
Source: ftp://ftp.picsrus.com/pub/%{name}-%{version}.tgz
URL: http://www.picsrus.com/pub/pics/catpics.html
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-root
Vendor: Pics R Us, Inc.
Packager: Fred Berferd <[EMAIL PROTECTED]>
Provides: CatPics
Requires: ee
%description
This package contains CatPics, just a collection of
feline images in various graphics formats, along with a
couple of documentation files.
----- end preamble -----
The preamble represents the information someone can see if
they query the eventual RPM with:
$ rpm -qpi catpics-1.0-1.noarch.rpm
Some of these values should be obvious; some observations about
the rest:
- The Group value should be one of the values from the file
/usr/share/doc/rpm-4.0.3/GROUPS. Strictly speaking, it
doesn't *have* to be, but you're strongly encouraged to use
one of those combinations.
- The Source value represents two things: the full name points
at the tarball's location on the Internet, while only the last
component of that pathname represents the name of the tarball
in the SOURCES directory. So, really, it's only that last
component that matters here. Similarly, the URL value is
not essential, and is a pointer to documentation for the package
available on the 'Net, if anyone wants to go hunting for it.
- BuildRoot represents the location where you plan on building
the directory structure that will ultimately match the final
structure in the RPM -- where things will go when the RPM is
installed on the target host.
As shown above, it's traditional to put all new build roots
in the ~/rpm/tmp directory, in a subdirectory matching the name
of the package. In our case, this RPM's build root will be the
directory ~/rpm/tmp/catpics-root, and it will be your job to
copy under that directory what you want as the eventual file
and directory layout of the final RPM.
The rest of the preamble is fairly straightforward, and even
demonstrates a simple package prerequisite -- an RPM that must
already be installed on the target host before this RPM can be
installed.
And now, on with the actual construction.
** The script variables (a huge footnote, really)
Given that the rest of the spec file represents commands to be
run that will unload, process and build a new RPM, it's worth
pointing out that, at this point, the following variables are now
available to use in any of these upcoming steps (shown with their
values for our example):
RPM_PACKAGE_NAME catpics
RPM_PACKAGE_VERSION 1.0
RPM_PACKAGE_RELEASE 1
RPM_ARCH i386
RPM_OS linux
RPM_SOURCE_DIR /home/fred/rpm/SOURCES
RPM_BUILD_DIR /home/fred/rpm/BUILD
RPM_BUILD_ROOT /home/fred/rpm/tmp/catpics-root
If you want to refer to any of them, you can use either, for
example, ${RPM_BUILD_ROOT} or just $RPM_BUILD_ROOT.
One important note here: Don't confuse the "build directory"
with the "build root" -- the build directory is where the tarball
will be unloaded and processed, while the "build root" is where
you will construct, piece by piece, an exact image of the files
and directories to be contained in the RPM. (It's unfortunate that
this directory was called the "build root" -- calling it the
"install root" would have made much more sense.)
Now, on to the first stage -- the "%prep" stage.
** The %prep stage
Consider the entire %prep stage from our spec file:
%prep
%setup -q
The purpose of the %prep stage of the spec file is to start
the entire build process by unloading the tarball from the SOURCES
directory into the BUILD directory under the appropriate package
and version name subdirectory.
You can do this manually with Linux commands, or you can use
the shortcut macro "%setup", or its quiet form "%setup -q", to
do this automatically. This macro automatically moves to the
BUILD directory, fetches the appropriate tarball from SOURCES,
extracts it, then moves into that new subdirectory. In our case,
we will suddenly find ourselves in the new directory
/home/fred/rpm/BUILD/catpics-1.0, looking at the contents of
the tarball.
In other words, as long as you create your initial tarball
with a top-level directory name of {package}-{version}, as in
catpics-1.0, your %prep stage can really be this simple.
At this point, then, we're in the .../BUILD/catpics-1.0 directory,
which contains:
pics/jones.jpg
pics/xena.jpg
pics/clarence.jpg
pics/elliott.jpg
COPYRIGHT
README
Now what? On to the %build stage.
** The %build stage
If you were building a binary RPM from source, possibly using
configure files or makefiles, this is where you'd start running
"./configure" or "make" to create the object files and eventual
executables.
In our case, however, there's really nothing to build, which
is why our spec file has an empty %build stage of:
%build
exit 0
And since we didn't have to build anything, we can head right
into the "%install" stage.
** The %install stage
Assuming that the purpose of the previous %build stage was
to ultimately create (in the directory .../BUILD/catpics-1.0
in our case) every single file to be placed in the new RPM,
it's the job of the %install stage to copy the files we want
in the new RPM into the "build root" directory, in exactly the
location they should be installed on the target host. So if
our original job was to create an RPM which would install,
on the target host:
/usr/local/catpics/<cat image files>
/usr/share/doc/catpics-1.0/{README, COPYRIGHT}
then the %install stage has to load the build root (the
directory /home/fred/rpm/tmp/catpics-1.0, remember?) so that
we end up with the corresponding directory structure:
/home/fred/rpm/tmp/catpics-1.0/usr/local/catpics/<image files>
/home/fred/rpm/tmp/catpics-1.0/usr/share/doc/catpics-1.0/<docs>
In short, the build root has to contain the entire contents of
the new RPM, from the root directory on down. It's our job to
make that happen, which explains the spec file's %install stage:
%install
rm -rf ${RPM_BUILD_ROOT} # remove old copy, play it safe
mkdir -p ${RPM_BUILD_ROOT}/usr/local/catpics
cp pics/* ${RPM_BUILD_ROOT}/usr/local/catpics
Note well that the directory structure we build into the new RPM
does not need to match the way the files and directories came out
of the tarball. We have the ability to copy the files we want
where we want, so we can structure the new RPM any way we want.
At this point, we're almost ready to build our new RPM, but
you'll notice the %install stage didn't say anything about the
documentation files we wanted in the RPM. We'll return to that
shortly but, assuming that we've built everything we need under
this package's build root directory, we can define how to get
rid of all this mess once our RPM is built.
** The %clean stage
While this stage is defined after %install stage, it's not
actually run until the very end of the RPM creation process,
and its job is to remove anything we don't want to keep around
once the RPM has been built.
In our case, we need little more than the %clean stage that's
in our spec file now, which gets rid of the build root for the
RPM:
%clean
rm -rf ${RPM_BUILD_ROOT}
** The %files stage
Once you've built the directory structure for the new RPM under
the build root, the final stage in the spec file, the %files stage,
is used to identify (among other things) *precisely* the files and
directories you want to copy from the build root into the new RPM.
Let me say that another way: just because you copied something
into the build root does not mean it will end up in the new RPM --
you have to explicitly list that file or directory in this stage
or it will not be copied. In other words, while it's a bad idea,
you can be sloppy and copy extraneous stuff into the build root,
but you don't need to select it for inclusion in the new RPM.
But the %files section lets you say more than that.
Consider our entire %files section:
%files
%defattr(-,root,root)
/usr/local/catpics
%doc COPYRIGHT README
What does all this mean?
First, your %files section can contain at most one %defattr
directive, which will dictate the default permissions, owner
and group for the contents of the new RPM. You can, however,
override this default on a line-by-line basis with the %attr
directive, as in:
%attr(444,root,root) /usr/local/catpics
but let's not get carried away.
Following the optional %defattr directive, you will list every
file or directory you want to add to the new RPM (you're allowed
to put more than one entry on a line if you want.) But there's
one more feature to explain.
Documentation files can be treated in a special way. As long
as these doc files were immediately under the top level of the
original tarball, you don't need to identify them in the normal
way in either the %install stage or the %files stage.
Instead, you can abbreviate their mention the way you see
above, and this means that they will not only be automatically
selected for copying to the build root, but they will copied
to the subdirectory /usr/share/doc/<package>-<version>, and
also automatically selected for inclusion in the new RPM.
In our case, these doc files will end up being installed in
the directory /usr/share/doc/catpics-1.0 on the target host,
a perfectly respectable location for a Linux host.
You could, if you wanted, treat documentation files as
normal files, but this is a much cleaner shortcut. It does,
however, require you to put such doc files just under the
top level of the tarball, or this shortcut will fail.
At this point, it might be worth reviewing the spec file
in its entirety in Appendix A.
* Building the noarch RPM
Now that you've finally designed the "catpics.spec" file,
you can create a noarch RPM from it and the original tarball
with:
$ rpm -bb catpics.spec
This command will, in order, unload the SOURCES tarball into
the BUILD/catpics-1.0 directory, install the image files and
documentation files under the corresponding build root to
match the directory structure of the eventual RPM, then consult
the %files section of the spec file to finally build that
RPM which, in our case, gets placed in your RPMS/noarch
directory.
Now that you have your new noarch RPM, you can examine it with
any of:
$ rpm -qpi catpics-1.0-1.noarch.rpm (preamble info)
$ rpm -qpl catpics-1.0-1.noarch.rpm (file list)
$ rpm -qplv catpics-1.0-1.noarch.rpm (long file list)
Make sure every file is there and seems to be in the right
location.
In addition to just building the final RPM, you can see the
intermediate results of the construction process by choosing to
run only certain stages of the build process:
$ rpm -bp catpics.spec (%prep stage only)
$ rpm -bc catpics.spec (%prep, %build stages)
$ rpm -bi catpics.spec (%prep, %build, %install stages)
After any of these stages, you're free to check the contents
of any of the directories to see if they appear to have the
correct contents. In particular, it's useful to check the
contents of the build root directory after the "rpm -bi"
invocation.
* Building a source RPM
Finally, it's possible that you want to bundle up the original
tarball and the spec file in such a way that others can unload
it to build it themselves, or just so they can poke around the
tarball or spec file. In our case, the source RPM would have
the name catpics-1.0-1.src.rpm, and would be automatically
built in the SRPMS directory with one of:
$ rpm -bs catpics.spec (build just the source RPM)
$ rpm -ba catpics.spec (build both types of RPM)
What someone can do once they receive your source RPM file is
up to them.
* Summary
In closing, building your own noarch RPMs is fairly straightforward,
and consists of two major steps:
1) Create a tarball containing all the image, text, documentation
and any other kinds of files to be added to the RPM, and
2) Write an appropriate spec file to build it.
If you have any comments or corrections, I'd like to hear about
them. Email me at [EMAIL PROTECTED]
* Legal stuff
This document is copyright Robert P. J. Day, 2001. All rights
reserved, for the time being.
* Appendix A: the spec file
The spec file "catpics.spec":
Summary: CatPics, a collection of feline images
Name: catpics
Version: 1.0
Release: 1
Copyright: GPL
Group: Amusements/Graphics
Source: ftp://ftp.picsrus.com/pub/%{name}-%{version}.tgz
URL: http://www.picsrus.com/pub/pics/catpics.html
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-root
Vendor: Pics R Us, Inc.
Packager: Fred Berferd <[EMAIL PROTECTED]>
Provides: CatPics
Requires: ee
%description
This package contains CatPics, just a collection of
feline images in various graphics formats, along with a
couple of documentation files.
%prep
%setup -q
%build
exit 0
%install
rm -rf ${RPM_BUILD_ROOT}
mkdir -p ${RPM_BUILD_ROOT}/usr/local/catpics
cp pics/* ${RPM_BUILD_ROOT}/usr/local/catpics
%clean
rm -rf ${RPM_BUILD_ROOT}
%files
%defattr(-,root,root)
/usr/local/catpics
%doc README COPYRIGHT