discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

A quick introduction to building RPMs (was Re: ANN: GNUstep Gui/Back ver


From: Aredridel
Subject: A quick introduction to building RPMs (was Re: ANN: GNUstep Gui/Back version 0.8.9)
Date: Sat, 30 Aug 2003 16:49:36 -0600

> Hmm.  I have no experience with (s?)rpms... do they run ./configure 
> first?  Or should they contain preconfigured config.h files?  Are they 
> contained in the package?  It should be located in gui/Source/config.h 
> or in a target specific subdir in ./Source depending on how the package 
> was configured.

Just for the record, a little overview of how RPM works (because knowing
makes one write better software):

RPMs are built from source (except in kludgy, hackish cases where source
isn't available).  The process is scripted using a "spec" file -- it
contains all the package metadata, reference to the original source (as
the author created it, verbatim).  It then lists any patches that the
creator applied to get it to build properly -- in this case, I'm
applying the patch that Adam sent me to correct for the
--disable-flattened case, since that's not part of the 0.8.9 release of
-gui.

The spec file then instructs RPM to unpack the source, apply the patches
(this is done with predefined macros, %setup and %patch, since untarring
a tarball and applying patches is so common) -- this is called the
"prep" stage.

After the prep stage is the build stage, which contains a shell fragment
(with some macro expansion to handle common cases like running
./configure with all the right optimization options and target
directories -- in my case, PLD defines about twenty flags, to make
packages FHS-2.2 compliant and leave very little up to the author's
defaults.)  The build stage usually ends with the make command, so
what's left afterward is a build directory with binaries.

After the build stage, the install stage is executed: this is another
shell fragment, usually consisting of a make install command. The single
most problematic thing for RPM is that builds should not be executed as
root, according to good form: this means that a DESTDIR variable or
equivalent must be supported by the makefiles, as the files are usually
placed in /tmp/packagename-builderuser/$prefix.  If the only option is
to install into $prefix, as specified to configure, then there's
problems.  It's the #1 thing patched by RPM maintainers, it's also the
#1 reason programs are not included in distributions: maintenance is
hell that way.  Sometimes a patch to configure.in, and putting autoconf
into the build stage is enough.  Sometimes not.  When not, packages get
left out of the distribution unless they're important or coveted by one
of the developers enough to warrant time to make it work.

The remainder of the spec is a list of files, relative to the root of
the installed files, to be packaged.  Usually, headers and .la and .lo
files end up in a -devel subpackage, the main libraries end up in the
main package or a -libs subpackage, the contents of /usr/share end up in
the main package, and any .a files end up in a -static subpackage, or
sometimes in -devel.  Each distro has different policies on this, but
they're fairly sane and not too much to worry about for individual
developers.

There's a lot of subtle points in here:

   * Not building as root means that the builder system won't have it's
files damaged by an install run amok. Also, it makes detecting
dependencies much easier (and modern RPM detects library dependencies
automatically, via a search of the files in the installed root)

   * Pristine source is distributed with patches. That means that if you
check and see what patches a distro has to apply to your source to make
it work, you can improve the package by applying those patches to your
tree and make the distro maintainers lives easier, and make your
software easier to include, and therefore more popular because it's
easier to install.   Pristine source also means that upgrading between
versions is easier: you know what changes have to be ported, and you can
often apply a patch for one release to the next, usually with no change.

   * Some dependency metadata is encoded automatically.  Sometimes is
has to be provided by the maintainer.  Making clear what packages are
depended on by your package is a boon to maintenance, especially if you
include version numbers.  Instead of listing in the readme what packages
depend on the one you're distributing (as GNUstep does), saying what it
depends on is more useful.  gnustep-make shouldn't have to say
gnustep-base depends on it; gnustep-base should say it depends on
gnustep-make.

   * .spec.in files munged by autoconf are nearly useless.  If you have
to start the build process to get the .spec, it's too late: you need the
spec to start.  If you include a sample .spec file to aid maintainers,
provide it pre-built, not generated by autoconf.  If your package is
well designed, all that will change between releases is the version
number, and perhaps the file list -- the build process will consist of
the same commands.

   * RPM discourages resuming a build in the middle: the idea is to get
a clean build from pristine source to output with no human
intervention.  RPM never or nearly never executes make clean, make
distclean or any other cleanup.

I hope this sheds some light on an often mysterious subject, and
illuminates the sources of troubles.  I personally don't install /any/
software without making an RPM first.  If I can make an RPM, I can
submit it to PLD's source tree, and I can uninstall it, completely,
every time.  It is also a measure of software quality -- if it's
buildable with no intervention, then it's good.  If not, it needs work.

Aredridel

P.S. A note to any developer: Stop assuming ncurses.h is available as
<ncurses.h>.  In PLD, and many other more modern systems, it's in
<ncurses/ncurses.h>, or you need -I/usr/include/ncurses.  Same for other
headers.

Attachment: signature.asc
Description: This is a digitally signed message part


reply via email to

[Prev in Thread] Current Thread [Next in Thread]