This page lists some of the things you should think about when distributing programs for Unix-like operating systems as source code — in particular, from the point of view of someone trying to produce binary packages for distribution.
You should also look at:
- Debian's Upstream Guide has lots of good advice, and links to other similar pages.
- The GNU Coding Standards describe The Release Process for GNU's software.
- How to Make Package Managers Cry is a great collection of war stories from a packager of scientific software.
I've tried to make the advice here as general as possible, but there's an inevitable slant towards the things I've discovered while packaging software for GARStow. If you're aware of anything I've missed, please let me know.
General advice
The most important thing I've got to say here: please, please, don't roll your own custom configuration system. Use GNU autoconf and automake instead. Yes, they're awkward for some things, but they make life very easy for packagers when used correctly. If you're not using automake, then it's very tricky to get everything below correct unless your program is absolutely trivial (and if it's trivial, then it'd be very easy to write an automake config for).
The exception is for add-on modules for programming languages where there's an existing packaging system that's widely-used: for Perl use CPAN, for Python use distutils, and so on.
Be very cautious about systems that have been designed to replace automake; all that I've encountered have been very convenient for developers, but cause problems for end users and packagers (for example, assuming standard locations for files, or not allowing environment variables to be passed to compilers, or not supporting installation staging). If you really have to use something other than automake, then make certain that it's actually possible to use it to install the software and produce packages.
Don't interleave building and installation steps; construct your build system so that the entire package is configured and built, and then the entire package is installed. Installation should not touch the source directory at all, nor should configuration or building touch the destination directories; it's recommended practice to compile software as a non-privileged user and only install as root.
If you're installing a shared library, also install a pkg-config file; this makes detecting and using the library in other packages easier and more reliable. (The uptake of pkg-config has been surprisingly rapid among libraries; even X uses it these days.)
Configuration
Do not do interactive configuration by default; it's important that package builds should be automatable. If you want an interactive configuration system, then do as the Linux kernel and busybox do, and make it generate a config file that can be machine-edited and stored by packagers.
Check the output from ./configure --help
to make sure
that all the options are listed, and that the defaults are sensible and
accurate.
Support cross-building the package for different architectures. automake will take care of most of this for you, but you need to be careful about things like internal tools used during the build process.
Source code
Don't hardcode paths into your source code; make them an option at configuration time. If your program automatically detects where its binary is, make sure it doesn't break in the presence of something like stow (i.e. that it isn't overly enthusiastic about following symlinks — Python has this problem).
Have a test suite for your program.
Even just checking that your program's executable can run and print a
help message will catch several kinds of build problems.
Make the test suite available via make check
, in order to
reassure users that the package basically works.
The tests should run to completion and exit 0 if they succeed; if any
of them fail, make check
must exit non-zero.
Don't rely on users inspecting the output to check the tests passed!
Installation
Follow the GNU standards for how prefix
and the related
variables work. In particular, note that bindir
and similar
variables should default to depending on prefix
at
install time; don't set bindir
to a fixed path at
configure time (unless the user's explicitly specified one). Don't make
up your own names for the variables (some packages use
PREFIX
or, worse, DESTDIR
to mean the same
thing as prefix
).
Support DESTDIR
. This is much more convenient for some
packaging systems, so people building RPMs or Debian packages will find
their jobs rather easier if you support it.
Don't assume that installation paths exist; use mkdir
-p
to make bindir
etc. before you try installing
files into them. (This applies even if your build depends on a
directory existing — remember that the prefix you install into may
be different from the one you had at build time.)
Don't assume you can edit or replace existing files and directories in your installation prefix, since at install time it might just be a staging directory. This means that each file should only be provided by one source package. If you want several packages to provide data for another program, have them write to different files in a shared directory (which is the approach taken by pkg-config, among others).
Similarly, don't assume that you can check for the existence of files in your installation prefix at install time.
Don't install things in a directory that you haven't been told about.
I don't necessarily want config files installed in /etc
,
particularly if I'm not root.
Don't explicitly set ownership of installed files unless they're suid — you don't know what the administrator's conventions for file ownership are. If you're installing suid stuff, add a configure-time option not to do so, for people who're installing your software without being root.
Distribution
If your program is named gnomovision
and it's at
version 3.4, then your distribution tarball should be named
gnomovision-3.4.tar.gz
(or .bz2
) and it should
contain a single directory called gnomovision-3.4
. If you
release a bug-fix version, make sure the directory name is changed to
match the tarball name. If you release patch files, generate them with
diff -Naur old-version new-version
, so they can be applied
with patch -p1
.
Use GPG to sign your distribution files. Provide a detached
signature file, named the same as the matching distribution file plus
.asc
or .sig
(invoking gpg --detach-sign
-a your-file
will do the right thing).
Document your package's dependencies somewhere — such as the
download web page for your project, or the INSTALL
file in
the distribution. If you're depending on another package that's uncommon
or otherwise hard to search for, give the URL where it can be
found.
Make certain that your package actually contains all the files
necessary to build it. It's easy to leave out a source file by accident,
or change configure.ac
before release and forget to
regenerate configure
(which will produce interesting errors
for users who don't have the same version of autoconf as you), or to
forget to clean out version control or object files from your tree.
Make your version control repository public (or at least provide daily snapshots), and make sure you check changes into it before you release a tarball. If a user finds a bug in your package, it's useful to be able to check the repository first to see if it's already been fixed.
Finally, make sure that you build, test and install your package, from the exact distribution file you ship, on a different machine from the one you developed it on, with only the package's documented dependencies installed. (Ideally, on several machines with different operating systems and architectures.) It's depressingly common to find packages where the test suite clearly wasn't run before release!