
REQUIREMENTS
============

Development-Time
----------------

--------------- --------- --------------- -------------------------------------
Component       Component Version Version Component
Name            Type      Minimum Used    URL
--------------- --------- ------- ------- -------------------------------------
CVS             mandatory 1.12    1.12.13 http://www.nongnu.org/cvs/
Perl            mandatory 5.8.0   5.8.8   http://www.perl.com/
GNU m4      [0] mandatory 1.4.0   1.4.11  http://www.gnu.org/software/m4/
GNU autoconf    mandatory 2.59b   2.62    http://www.gnu.org/software/autoconf/
GNU automake    mandatory 1.8     1.10    http://www.gnu.org/software/automake/
GNU libtool     mandatory 1.5     2.2.6   http://www.gnu.org/software/libtool/
GNU gettext     mandatory 0.16    0.17    http://www.gnu.org/software/gettext/
--------------- --------- ------- ------- -------------------------------------

Build-Time
----------

--------------- --------- --------------- -------------------------------------
Component       Component Version Version Component
Name            Type      Minimum Used    URL
--------------- --------- ------- ------- -------------------------------------
ISO C Compiler  mandatory -       -       e.g. http://gcc.gnu.org/
POSIX make      mandatory -       -       e.g. http://www.gnu.org/software/make/
Perl            mandatory 5.8.0   5.8.8   http://www.perl.com/
POPT            mandatory 1.9     1.14    http://rpm5.org/files/popt/
BeeCrypt        mandatory 4.0     4.1.2   http://beecrypt.sourceforge.net/
Mozilla NSS     optional  3.11    3.11.7  http://www.mozilla.org/projects/security/pki/nss/
OpenSSL         optional  0.9.8   0.9.8g  http://www.openssl.org/
Neon            optional  0.26.0  0.28.1  http://www.webdav.org/neon/
Berkeley-DB [1] optional  4.5     4.7.25  http://www.oracle.com/database/berkeley-db.html
SQLite      [1] optional  3.3     3.5.9   http://www.sqlite.org/
Lua         [2] optional  5.1     5.1.4   http://www.lua.org/
ZLib        [3] optional  1.2     1.2.3   http://www.zlib.net/
Bzip2           optional  1.0     1.0.5   http://www.bzip.org/
LZMA Utils      optional  4.42.2  4.999.3 http://tukaani.org/lzma/
File/magic  [4] optional  4.0     4.24    ftp://ftp.astron.com/pub/file/
GNU gettext     optional  0.16    0.17    http://www.gnu.org/software/gettext/
GNU iconv       optional  1.11    1.11    http://www.gnu.org/software/libiconv/
PCRE            optional  7.0     7.7     http://www.pcre.org/
OSSP uuid       optional  1.6.0   1.6.1   http://www.ossp.org/pkg/lib/uuid/
XAR         [5] optional  1.5.2   1.5.2   http://code.google.com/p/xar/
DMalloc         optional  5       5.5.2   http://dmalloc.com/
Electric Fence  optional  2.1     2.1.13  http://perens.com/FreeSoftware/ElectricFence/
Linux KeyUtils  optional  1.2     1.2     http://people.redhat.com/~dhowells/keyutils/
System libelf   optional  -       -       e.g. http://www.mr511.de/software/english.html
--------------- --------- ------- ------- -------------------------------------

[0] m4:        NOTICE: Do not use GNU m4 1.4.10, it breaks GNU autoconf.

[1] db/sqlite: Modified Berkeley-DB copy bundled with RPM.
               Building RPM against stock external Berkeley-DB not officially supported.
               Building RPM against SQLite-only not officially supported.
               Building RPM against at least one of Berkeley-DB or SQLite required.
               Use modified bundled Berkeley-DB copy, please!

[2] lua:       Modified Lua copy bundled with RPM.
               Building RPM against stock external Lua not recommended
               as it reduces its RPM-specific functionality.

[3] zlib:      Modified ZLib copy bundled with RPM.
               Building RPM against stock external Zlib not recommended
               as it reduces its RPM-specific functionality.

[4] file:      Unmodified File/magic copy bundled with RPM for convenience reasons.
               Building RPM against this internal File/magic requires also internal Zlib.
               Building RPM against stock external File/magic supported, too.
               NOTICE: File 4.24 is unportable because uses asprintf(3) without fallbacks.

[5] xar:       Modified XAR copy bundled with RPM.
               Building RPM against stock external XAR currently still not recommended.
               The 1.5 and 1.5.1 releases of XAR needs some patching, before they work.

Run-Time
--------

--------------- --------- --------------- -------------------------------------
Component       Component Version Version Component
Name            Type      Minimum Used    URL
--------------- --------- ------- ------- -------------------------------------
GNU zip         optional  -       -       http://www.gzip.org/
Bzip2           optional  -       -       http://www.bzip.org/
LZMA Utils      optional  -       -       http://tukaani.org/lzma/
GNU tar         optional  -       -       http://www.gnu.org/software/tar/
GNU cpio        optional  -       -       http://www.gnu.org/software/cpio/
UnZip           optional  -       -       http://www.info-zip.org/UnZip.html
GnuPG           optional  -       -       http://www.gnupg.org/
PGP2            optional  2.6.3   2.6.3   http://www.pgpi.org/
PGP6            optional  6.5.8   6.5.8   http://www.pgpi.org/
--------------- --------- ------- ------- -------------------------------------

PROCEDURE
=========

Development-Time
----------------

$ ./devtool jbj|standalone

Build-Time
----------

$ ./configure --prefix=<prefix> [...]
$ make
$ make install [DESTDIR=...]

Run-Time
--------

$ <prefix>/bin/rpm --initdb
$ <prefix>/bin/rpm --rebuild foo.src.rpm
$ <prefix>/bin/rpm -Uvh /path/to/binary/package/foo.*.rpm
$ <prefix>/bin/rpm -qa
$ <prefix>/bin/rpm -e foo

Application Build-Time
----------------------

CPPFLAGS = `pkg-config rpm --cflags-only-I`
CFLAGS   = `pkg-config rpm --cflags-only-other`
LDFLAGS  = `pkg-config rpm --libs-only-other`
LIBS     = `pkg-config rpm --libs-only-l`

BUILDING RPM ON A CLUSTER OF SERVERS
====================================

Assume you have...

- a cluster of time-synchronized Unix servers
  (usually of different Unix flavors to make sense in this context),
- each server allowing you to login under your personal account and
  access your central home directory (usually via NFS) and
- each server providing you the full set of development tools,

...then you can build RPM in parallel on an arbitrary number of servers
in this cluster by using the following procedure:

1. Build Environment Preparation:

   On a single arbitrary server of the cluster prepare the RPM source
   tree at least once.

   server1$ cd ~/work
   server1$ cvs -d rpm-cvs@rpm5.org:/v/rpm/cvs co rpm
   server1$ cd rpm
   server1$ . devtool.bashrc

   server1$ devtool checkout
   server1$ devtool autogen

2. Platform Preparation:

   on every(!) server of the cluster prepare its platform-specific
   environment (includes building local copies of all third-party
   libraries).

   serverN$ cd ~/work/rpm
   serverN$ . devtool.bashrc

   serverN$ devtool setup-platform
   serverN$ devtool standalone prepare
   serverN$ devtool standalone configure

3. Development:

   now you can develop RPM on any number of servers of the cluster in
   parallel.

   serverN$ cd ~/work/rpm
   serverN$ . devtool.bashrc

   serverN$ cd {build,lib,rpmdb,rpmio,misc,...}
   serverN$ vi *.c
   serverN$ devtool make

4. Test-Drive:
   
   on an arbitrary server of the cluster you can test-drive RPM via:

   serverN$ cd ~/work/rpm
   serverN$ . devtool.bashrc

   serverN$ devtool make install
   serverN$ /tmp/rpm/bin/rpm [...]

LIBRARY ISSUES
==============

RPM is a rather comphrehensive tool with both internal dependencies and
optional external dependencies. The current internal structure is (in
partly dependency order from top to bottom):

  RPM Executables:       rpm
  (stage 0)              rpmbuild

  RPM Libraries:         librpm
  (stage 1)              librpmbuild
                         librpmconstant
                         librpmdb
                         librpmio
                         librpmmisc

  Third-Party Libraries: libpopt     (mandatory)
  (stage 2)              libbeecrypt (mandatory)
                         libdb       (mandatory)
                         libsqlite3  (optional)
                         liblua      (optional)
                         libz        (optional)
                         libbz2      (optional)
                         libintl     (optional)
                         libiconv    (optional)
                         libxar      (optional)
                         libdmalloc  (optional)
                         libefence   (optional)
                         libkeyutils (optional)
                         libelf      (optional)
                         libneon     (optional)

  Third-Party Libraries: libxml2     (required by libxar)
  (stage 3)              libz        (required by libxar)
                         libexpat    (required by libneon)
                         libssl      (required by libneon)
                         libcrypto   (required by libssl)
                      
  System Libraries:      libc        (required by all)
  (stage 4)              libm        (required by some)
                         [...]

The most important aspects to notice are: librpmbuild requires mainly
librpm, librpm in turn requires both librpmdb and librpmio, and all
librpm* require librpmmisc. Additionally; librpmmisc is a container for
the internal local copies of third-party libraries, and librpmconstant
provides RPM API constants (usually to language bindings). Finally,
notice that the set of third-party libraries at stage 2 can be dynamically 
chosen at build-time and are not a fixed set.

Unfortunately, there are many link-time approaches to handle these
internal and external dependencies. The currently implemented approach
is a portable compromise balancing the following particular issues:

- Dynamic/Static Libraries:
  librpmXXX can be built and installed statically (librpmXXX.a) or
  dynamically (librpmXXX.so). This is handled by GNU libtool and
  controlled by Autoconf options --{enable,disable}-{shared,static}.

- Installed/Uninstalled Libraries:
  libfoo can be in an installed (after "make install") or uninstalled
  (just after "make") state. Both are supported by GNU libtool but in
  totally different ways. GNU libtool especially treats the linking of a
  library against an uninstalled one specially by _copying_ all objects
  of the dependency library into the to be be built library.

- Regular/Convenience Libraries:
  GNU libtool knows a special "convenience" library. These are
  uninstalled libfoo.la's which are linked into another (still
  uninstalled) libbar.la.

- Library Type Combinations:
  GNU libtool knows how to handle all situations caused by _combinding_
  the different types of libraries: installed/uninstalled,
  static/dynamic and regular/convinience. And in RPM nearly _ALL_ of
  those combinations actually occur under various Autoconf options.
  Although the processing abstracted, the resulting libraries have
  different characteristics and affects how RPM-based applications are
  able to link about the RPM libraries.

- External Dependencies:
  librpmXXX and librpmYYY usually depend on the _same_ third-party
  library libfoo. Although GNU libtool handles this seamlessly, one can
  easily end up with multiple copies of a code in the same RPM-based
  application.

- Non-Fixed Third-Party Libraries:
  RPM supports to be built against a non-fixed set of third-party
  libraries, ranging from _none_ at all to half a dozen ones.
  Especially, the cases of "none" and "some" have to taken into account.

- Transitive Dependencies:
  libfoo usually has dependencies to other third-party libraries and
  those dependencies can be even just optional. For instance libneon
  can optionally depend on OpenSSL's libssl and libcrypto and the W3C
  libxml.

- Internal Modified Local Copies:
  because of optional but RPM-specific modifications, some third-party
  libraries are even provided as internal copies in the RPM source
  tree. Those libraries have to be handled specially as they are built
  together with RPM. This means that for instance one cannot test-link
  against them during configure-time.

- Dependency Encoding:
  there are multiple ways an inter-library dependency can be encoded:
  directly in an ELF librpmXXX.so as DT_NEEDED (not available
  everywhere), indirectly via "dependency_libs" in librpmXXX.la, via
  "Libs:" in rpm.pc, or either via a _FULL INCLUDED COPY_ of all objects
  or not at all in case of librpmXXX.a, etc.

Before complaining that the currently implemented library approach
of RPM is not "standard", doesn't "just work" as expected for your
particular situation, etc please first make sure you understood that
it is balanced compromise in order to portably take care of all of
the above issues at once. So, if you want to change the current
implementation please at least make sure that the above issues are still
taken care of and especially test it under _different_ Unix flavors.

DEBUGGING
=========

Memory Allocation Debugging with DMalloc
----------------------------------------

1. Install DMalloc into /path/to/dmalloc

2. Build RPM with at least:

   $ ./configure [...]
         --prefix=/tmp/rpm \
         --with-dmalloc=/path/to/dmalloc
         [...]
   $ make
   $ make install

3. Enable dmalloc debugging with:
   
   $ . .dmalloc.bashrc
   $ dmalloc -l dmalloc.log
   $ dmalloc debug3

4. Run RPM:

   $ /tmp/rpm/bin/rpm [...]

5. Inspect the results:
   (notice that some used functions like gethostbyname(3) or dirname(3)
   from the vendor libc inherently leak memory because of their API
   style and because libc isn't DMalloc instrumented you will often see
   some memory leaks reported without any source location -- just be not
   confused)

   $ vi dmalloc.log

OS DEPENDENCIES
===============

Under Red Hat Linux all libraries (in fact all files distributed with
the OS) are under RPM control and this section is not an issue.

RPM will need to be informed of all the dependencies which were
satisfied before RPM was installed.  Typically this only refers to
libraries that are installed by the OS, but may include other
libraries and packages which are availible at the time RPM is
installed and will not under RPM control.  Another common example of
libraries which may need dependency provisions are precompiled
libraries which are installed by the OS package manager during system
build time.  The list of dependencies you will wish to load into RPM
will depend on exactly how you bootstrap RPM onto your system and what
parts of the sytem you put into packages as well as on the specific OS
you are using.

The script vpkg-provides.sh can be used to generate a package which
will satisfy the dependencies on your system.  To run it you will need
to create a specfile header for this empty package and run the progam
with:

    --spec_header '/path/to/os-base-header.spec

and if you wish to ensure that some directories are not traversed you
can use the option: 

    --ignore_dirs 'egrep|pattern|of|paths|to|ignore

By default the generated rpm will include a %verifyscript to verify
checksum of all files traversed has not changed.  This additional
check can be surpressed with:

    --no_verify

The result of running the script will be a specfile which will create
a package continging all the dependencies found on the system.  There
will be one provides line for each depednecy. The package will contain
none of the actual OS library files as it is assumed they are already
on your system and managed by other means.  Here is a example
(truncated) of the provides lines used by one user of Digital Unix. (I
have put several provides on the same line for brevity)

provides: /bin/sh /usr/bin/ksh /usr/bin/csh 
provides: libc.so.osf.1 libm.so.osf.1 libcurses.so.xpg4 libdb.so.osf.1
provides: libX11.so libXaw.so.6.0 libXext.so libXm.so.motif1.2 libXmu.so
provides: libdnet_stub.so.osf.1 libsecurity.so.osf.1 libpthread.so.osf.1
provides: libexc.so.osf.1 libmach.so.osf.1 libdps.so libdpstk.so 


The script vpkg-provides2.sh is underdevelopment as a more advanced
version of vpkg-provides.sh which is aware of many different unix
vendor packaging schemes.  It will create one "dependency package" for
each unix package your OS vendor installed.


rpmfilename:
-----------

If you plan on packaging for more then one OS you may want to edit
/etc/macros or /usr/lib/rpm/macros and change the line which has
rpmfilename to something which include both the %{_target_os} and
%{_target_cpu}.  This will cause the name of the generated rpm files
to the operating system name as well as the architecture which the rpm
runs under.  The line to change looks like:

%_rpmfilename           %%{ARCH}/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm

you may wish to include both the %{_target_os} and %{_target_cpu} in
the final base name, so that it's easier to distinguish between what
package is appropriate for a particular arch-os-version combo.  We
suggest:

%_rpmfilename           %%{_target_platform/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{_target_platform}.rpm

There is no %{_target_os_version} tag, so if you need to also
distinguish between RPMs for certain versions of the OS, you can
hard-code the version in the macros on the build machine, so that
.rpm files are generated with the version as part of the filename.

For example when one user builds RPMs for Digital Unix 4.0b and 4.0d,
optimization is important and he will build one set of RPMs for the
EV4 processor and another set for the EV56 processor.  He specifies
both the OS version (if it's important, as it is for a few packages)
and the processor version by default by setting a special rpmfilename:
on the particular build machine.

The "rpmfilename: "tag on one machine (Digital Unix 4.0d, EV56 PWS 433)
looks like:

rpmfilename: %{_target_os}/4.0d/%{_target_cpu}/%{name}-%{version}-%{release}.%{_target_os}-%{_target_cpu}ev56.rpm

For package `foo-1.1', at build time that would translate into:

    osf1/4.0d/alpha/foo-1.1-1.osf1-alphaev56.rpm

The hyphen between the %{_target_cpu} and ev56 is left out for compatibility
with GNU Config.guess and because `alphaev56' looks more "normal" to
people with an alpha than alpha-ev56 for someone on an Intel Pentium
Pro would want `i586pro' over `i586-pro', but it does make parsing
this filename by other programs a bit more difficult.


GPG/PGP/PGP5
------------

To use the signing features of rpm, you will need to configure certain
rpm macros.

Here's what I use for gpg:

    /etc/rpm/macros for per-system (or ~/.rpmmacros for per-user) configuration
	%_signature     gpg
	%_gpg_name      Jeff Johnson (ARS N3NPQ) <jbj@redhat.com>
	%_gpg_path      /home/devel/jbj/.gnupg

Here's what I use for pgp2.6:

    /etc/rpm/macros for per-system (or ~/.rpmmacros for per-user) configuration
	%_signature	pgp
	%_pgpbin	/usr/bin/pgp
	%_pgp_name	Jeff Johnson <jbj@redhat.com>
	%_pgp_path	/home/jbj/.pgp

In order to use pgp5, you will need to change:

	%_signature	pgp5
	%_pgpbin	/path/to/pgp5/binary
	%_pgp_path	/path/to/pgp5/keyring

(Note: Only one of pgp and pgp5 may be used because of name conflicts.)

You may also need Red Hat GPG/PGP public keys. These can be found in the
rpm source tarball, in /usr/share/doc/rpm*, or from http://www.redhat.com. In
order to verify a package signed by Red Hat you will need to import these
keys onto you key ring. See the GPG/PGP documentation for how to do this.
