"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 packages generally have many options that control their behavior. Configuration is the setting of these options, and can be divided into two types: compile-time and run-time.
Compile-time options are set during the installation process by the installer (typically a system administrator). Compile-time options are not changeable afterwards.
Run-time options are set when a program is invoked, and can be set either by the system administrator for the entire system, or by individual users for when they run the program. Three methods of run-time configuration are command line arguments, configuration files, and interactive configuration.
When possible, configuration should be done at run-time rather than compile-time. If it is possible to determine the value of the option when the program starts, run-time configuration should be used. However, some options will need to be set at compile-time, such as operating system-specific code and what components of a package to build.
A simple way to handle compile-time configuration is to isolate all
compile-time options in a header file config.h in the package's top-level
directory. The installer edits this one file and sets the desired
values. (The package's source code files must #include <config.h>
and their make files need a -I option in the compiler flags.)
The autoconf and automake tools provide a more user-friendly front-end to this process with the "configure" script. The tools will automatically build a config.h and write the Makefiles appropriately. Configure auto-detects operating system-specific features, so the installer doesn't have to know or specify those. Configure also provides a method of specifying arbitrary compile-time options for the package.
To configure a package to use other software packages, see the
Using Other Packages section of the Installation
guideline for information on how to define --with options for
configure.
If your software package can enable or disable support for certain
features at compile-time, autoconf provides the capability to define
--enable options. Enable options are not intended to modify the
behavior of certain features, but rather to completely enable or disable
them.
From the installer's perspective, the installer gives
--enable-XXX or --disable-XXX arguments
to configure. For example, if your package
optionally provides support for "breaking all rules" (B.A.R.), the installer
might run:
./configure --enable-bar
An optional argument can be given to --enable-XXX.
--enable-bar is equivalent to --enable-bar=yes
and --disable-bar is equivalent to
--enable-bar=no.
To use an --enable option, the developer adds an
AC_ARG_ENABLE macro to configure.in. An example:
AC_ARG_ENABLE(bar, [ --disable-bar disable breaking all rules (enabled by default)], opt_bar=$enableval, opt_bar=yes ) if test $opt_bar = "yes"; then AC_DEFINE(ENABLE_BAR, 1, Configure support for bar) fi
The second AC_ARG_ENABLE argument (enclosed in brackets) is a help string
to be printed by ./configure --help (the columns should line up
as above). opt_bar=yes says the default value is
yes. The AC_DEFINE will #define the preprocessor macro
ENABLE_BAR in config.h. The package's source files can then wrap BAR-specific
code with #ifdef ENABLE_BAR and #endif.
Most programs modify their behavior depending on the value of arguments that the user specifies when invoking the program.
Traditionally, command-line arguments are grouped in three categories: short-form options, long-form options and regular arguments.
Short-form options consist of a single dash followed by a single letter,
for example -V to display version information. Some short-form
options can be followed by a space or equals sign and a value,
for example -o myfile.out to redirect output to the file
myfile.out. Multiple short-form options can be specified together with a
single preceding dash as long as they don't take values (for example,
-aq is equivalent to -a -q).
Long-form options consist of two dashes followed by a descriptive
keyword, optionally followed by a space or equals sign and a value.
For example, --version might display version information and
--output=myfile.out might redirect output to myfile.out. Long-form
options often have a short-form equivalent (for example, --version
and -V might do the same thing).
Regular arguments should normally be used to specify input files.
Some commonly used command-line options:
--version (-V),
as described in the Version Control guideline.--help (-h), --usage (-?),
--quiet (-q), --silent (-s), and
--verbose (-v),
as described in the Documentation guideline.--output=FILE (-o FILE) to specify an output file.
Specifying a dash ("-") for the FILE means send output to stdout.- typically means to read input from stdin.-- typically means to consider all following arguments
as regular arguments, not options. This is used to allow input files
to begin with a dash.Programs can parse their command-line arguments using:
Programs with fairly simple command-line options can stick with the first option for maximum portability. However, programs with many or complex options might prefer the popt library, as it is available for all Unix-like operating systems, and does not impose restrictions on how the package can be licensed.
An example of how to use popt:
#include <stdio.h>
#include <popt.h>
/*
This program accepts the following options:
--help (or -h) display help information and exit
--usage (or -?) display usage information and exit
--version display version information and exit
--output=FILE redirect output to FILE
Regular command-line arguments are input files.
*/
int main(int argc, char **argv)
{
char *opt_output = NULL; /* output file name */
char **opt_input = NULL; /* list of input file names */
poptContext opt_context; /* context for parsing arguments */
int opt_status; /* return code from parsing routine */
/* define accepted command-line options */
struct poptOption options[] = {
{ "help", 'h', POPT_ARG_NONE, NULL, 1,
"Display this message", NULL },
{ "usage", '?', POPT_ARG_NONE, NULL, 2,
"Display brief summary of command-line arguments",
NULL },
{ "version", 0, POPT_ARG_NONE, NULL, 3,
"Display program version", NULL },
{ "output", 0, POPT_ARG_STRING, NULL, 4,
"Redirect output to file (default stdout)", "FILE" },
{ NULL, 0, 0, NULL, 0, NULL, NULL }
};
/* parse command-line arguments */
/* "hello" is name of program, for popt's aliasing feature */
opt_context = poptGetContext("hello", argc, argv, options, 0);
while ((opt_status = poptGetNextOpt(opt_context)) != -1) {
switch (opt_status) {
case 1: /* help */
poptPrintHelp(opt_context, stdout, 0);
printf("Report bugs to nobody@nowhere.com.\n");
exit(0);
case 2: /* usage */
poptPrintUsage(opt_context, stdout, 0);
exit(0);
case 3: /* version */
printf("Hello 1.0\n");
exit(0);
case 4: /* output */
opt_output = poptGetOptArg(opt_context);
break;
default: /* error */
fprintf(stderr, "%s: %s\n",
poptBadOption(opt_context, 0),
poptStrerror(opt_status));
poptPrintUsage(opt_context, stdout, 0);
exit(1);
}
}
opt_input = poptGetArgs(opt_context);
poptFreeContext(opt_context);
return(0);
}
See the popt(3) man page for details.
(TO DO: rc files, config file naming, useful libraries, etc.)
(TO DO: command line, GUI)
Each program's User's Guide should have an "Invoking program-name" section documenting command-line arguments, and a "Configuring program-name" section documenting other run-time configuration.
(TO DO)
(explicitly set and document permissions on config files; protection of sensitive configuration data including encryption)