"The good news about computers is that they do what you tell them to do. The bad news is that they do what you tell them to do."

-- unsure; often attributed without source to information philosopher Ted Nelson

Software development

Software development guidelines by Ken Gaillot

Installation

Every package should have a text file "INSTALL" in its top-level directory describing how to install the package.

Every package should also provide a Makefile in its top-level directory with at least the targets "all" to compile all programs and libraries, "install" to build and install all programs and other files needed for the package to operate, and "clean" to remove all temporary files (like .o's) from the package directory.

Every package that has C or C++ sources should provide a file config.h in its top-level directory defining PACKAGE and VERSION. For example:

#define PACKAGE "hello"
#define VERSION "1.0.0"

The automake and autoconf tools described below do all this automatically.

Portable installation

The GNU tools automake and autoconf provide a powerful capability to enable a software package to be installed on virtually any Unix-like operating system. Some of their benefits:

This is much preferable to the practice of requiring the user to hand-edit a header file to define symbols appropriate to the local system, or using different Makefiles for different systems.

The process works like this:

  1. The developer creates files "configure.in", "acconfig.h" and "stamp-h.in" in the package's top-level directory, and "Makefile.am" files in each directory that needs a Makefile.

  2. The developer runs aclocal to generate an "aclocal.m4" file, autoconf to create a shell script "configure", autoheader to create a file "config.h.in", and automake to create "Makefile.in" files.

  3. The user installing the package runs the configure script, which determines the local system capabilities, then generates appropriate Makefiles and a config.h header file which are used to build the package.

Creating configure.in

An initial "configure.in" should look something like this:

AC_INIT(src/main.c)
AM_INIT_AUTOMAKE(hello, 0.1.0)

AM_CONFIG_HEADER(config.h)

AC_OUTPUT([
Makefile
src/Makefile
doc/Makefile
])

The file name in the first line (src/main.c) is the name of any file in the package. It is simply used to make sure configure is called from the right place. Edit the AM_INIT_AUTOMAKE line to specify your package name (or a filename-safe equivalent) and version number. The AC_OUTPUT section at the end will specify which files will be created by autoconf, and generally will be a Makefile in each subdirectory that needs one. Each of the files in AC_OUTPUT requires a ".in" template (typically created from Makefile.am files by automake).

See the autoconf and automake documentation for macros that can be defined between "AM_CONFIG_HEADER" and "AC_OUTPUT". There are macros to check for the existence, location and behavior of commonly used programs, libraries, header files, library functions, and more. The list of possible macros gives a good idea of what features vary from system to system. For example, "AC_PROG_CC" is needed if the package includes any C source code, and "AC_PROG_CXX" is needed for C++.

Creating acconfig.h and stamp-h.in

acconfig.h will contain a list of symbols that your source code might want to use. Initially, it can be empty, so create it with something like "touch acconfig.h".

stamp-h.in is just used as a timestamp, so it can be empty. Create it initially with something like "touch stamp-h.in".

Creating Makefile.am

The developer should create a Makefile.am file in each directory that requires a Makefile (generally, directories containing source code and/or files that need to be distributed with the package).

Every Makefile.am should begin with the comment:

## Process this file with automake to produce Makefile.in

Makefile.am files in directories containing subdirectories should have a "SUBDIRS" macro. For example, the top-level Makefile.am for hello might look something like this:

## Process this file with automake to produce Makefile.in
SUBDIRS = doc libhello src

Makefile.am files in source code directories should additionally specify everything that needs to be installed, using the "bin_PROGRAMS" macro for most compiled programs and the "bin_SCRIPTS" macro for most interpreted scripts. Each program should specify its source code and header files with a "*_SOURCES" macro. For example, the hello package's src/Makefile.am might look like this:

## Process this file with automake to produce Makefile.in
bin_PROGRAMS = hello
hello_SOURCES = main.c sub.c hellomain.h
hello_INCLUDES = -I../libhello

There are special macros for programs intended to be run by system administrators or by other programs, for shell scripts, for man pages, for data files, and a few other categories. Essentially, any file that will be included with the distribution must be specified in some macro. Read the automake documentation for details.

Running the tools

After you've defined a configure.in, and whenever it changes, run aclocal to regenerate the "aclocal.m4" file and run autoconf to regenerate the "configure" script.

After you've defined a acconfig.h, and whenever it changes, run autoheader to regenerate the "config.h.in" file.

After you've defined Makefile.am files, and whenever they change, run automake --foreign --add-missing from the top-level directory to regenerate the "Makefile.in" files in all subdirectories. The "--foreign" option turns off certain GNU requirements, such as requiring an AUTHORS file. The "--add-missing" option copies certain support files to your package. Generally, this is not a problem, but check the files to see if their licenses impose any restrictions on your package. For example, GPL'd files like the script named "missing" require that your package also be GPL'd; if you don't want that, you'll have to replace such files.

Finally, if any of the above changes, re-run the "configure" script to regenerate the config.h and Makefiles for the development system.

Once everything is set up, the generated Makefiles will automatically run the tools when needed, so you don't have to remember any of the above.

Using other packages

Sometimes, a package requires or can optionally use other software packages which are already installed. Autoconf provides an easy method for configuring this behavior when the package is installed.

From the installer's perspective, the installer gives "--with-XXX" or "--without-XXX" arguments to "configure." For example, if your package can optionally use the "foo" package, the installer might run:

./configure --with-foo

An optional argument can be given to "--with-XXX." "--with-foo" is equivalent to "--with-foo=yes" and "--without-foo" is equivalent to "--with-foo=no".

To use a "--with" option, the developer adds an AC_ARG_WITH macro to "configure.in". An example:

dnl Configure support for foo.
AC_ARG_WITH(foo,
[  --with-foo              use foo for freeing ornery objects
  --without-foo           do not use foo (default)],
	opt_foo=$withval, opt_foo=no
)
if test $opt_foo = "yes"; then
	AC_DEFINE(WITH_FOO, 1, Configure support for foo)
fi

The second AC_ARG_WITH argument (enclosed in brackets) is a help string to be printed by "./configure --help" (the columns should line up as above). "opt_foo=no" says the default value is "no". The AC_DEFINE will #define the preprocessor macro WITH_FOO in config.h. The package's source files can then wrap foo-specific code with "#ifdef WITH_FOO" and "#endif".

In many cases of this sort, the package will need to find both the header files and the libraries for the other package. To allow the installer to specify a nonstandard location for these, two additional "--with-XXX" options can be used, "--with-XXX-includes" and "--with-XXX-libs". The installer can then specify something like:

./configure --with-foo --with-foo-includes=/home/me/foo/include
	--with-foo-libs=/home/me/foo/lib

With the two additional options, configure.in might look like this:

AC_ARG_WITH(foo,
[  --with-foo              use foo for freeing ornery objects
  --without-foo           do not use foo (default)],
	opt_foo=$withval, opt_foo=no
)
AC_ARG_WITH(foo-includes,
[  --with-foo-includes=DIR where to find foo header files],
	foo_includes="-I$withval",
	foo_includes='-I${prefix}/include/'
)
AC_ARG_WITH(foo-libs,
[  --with-foo-libs=DIR     where to find foo libraries],
	foo_libs="-L$withval -lfoo",
	foo_libs='-L${prefix}/lib/ -lfoo'
)
if test $opt_foo = "no"; then
	foo_includes=''
	foo_libs=''
else
	AC_DEFINE(WITH_FOO, 1, Configure support for foo)
fi
AC_SUBST(foo_includes)
AC_SUBST(foo_libs)

This will set variables for use in all Makefile templates. For source files that need to use foo, edit the Makefile.am in that directory and add @foo_includes@ to the INCLUDES macro, and @foo_libs@ to the LIBS macro.


Security

All files should be installed explicitly specifying their permissions. (Autoconf and automake will use reasonable permissions for most files.)

Tools