One of the most important features available to developers who use autoconf is certainly the ability to add new options to the ./configure execution, to provide optional build-time support to users. Unfortunately, because of the importance of this feature, it's also one the most commonly misused.
There are three types of options (or properly arguments )
that can be added to the configure
script:
The arguments starting with --enable- prefix are usually used to enable features of the program. They usually add or remove dependencies only if they are needed for that particular feature being enabled or disabled.
The arguments starting with --with- prefix are usually used to add or remove dependencies on external projects. These might add or remove features from the project.
Environment variables that are used by the
configure
script should also be declared
as arguments; their use will be explained below in detail.
The first two kinds of parameters differ just for the displayed
name and from the macro used, but are in effect handled mostly in
the same way. They both are actually used to pass variables, in
the form of --(enable|with)-foo=bar and both
provide defaults for when the variable is omitted (the value
yes
for --enable and
--with and the value no
for --disable and
--without).
While there is no technical difference between the two, it's helpful for both users and distribution to follow the indications given above about the use of the two parameters' kind. This allows to identify exactly what the parameters are used for.
The environment variables are a recent addition to autoconf and are indeed used by a minority of the projects based on this build system.
For declaring the arguments with --enable and
--with prefixes, you have two different
macros that work in basically the same way:
AC_ARG_ENABLE
and
AC_ARG_WITH
. Because they work in the same
way, the following explanation will only talk about the former,
but the same applies for the latter.
Keeping in mind what has been said above, about the parameters
actually taking a value, and defaulting to either
yes
or no
, the
parameters of the macro are as follows
AC_ARG_ENABLE(option-name, help-string, action-if-present, action-if-not-present)
option-name
Name of the argument, this will be used for both the actual argument option and for the variable to store the result in. It's useful to keep to a subset of characters here, since it'll be translated to a string compatible with sh variable names.
help-string
This is the string used to describe the parameter when running ./configure --help. Often it's passed raw directly to the macro, but that will likely make the text not align or fill properly in the help text. It's customary to use then the AS_HELP_STRING parameter to create the string.
action-if-present
This is the M4sh code used when the user has passed a
parameter through --enable-foo; the
value of the parameter, if any, is given through the
$enableval
(or
$withval
) local variable.
action-if-not-present
This is the M4sh code executed when no parameter of any kind for the given option name has been given at ./configure; this allows to set the default value for variables that are otherwise calculated in the previous action.
The most common mistake for this macro is to consider the two
actions as action-if-enabled
and
action-if-disabled
.
This is not the case!
Since using --disable-foo or --enable-foo=no are equivalent, for the macro, you cannot really use this macro with those meanings.
For most uses, there is no actual need to define actions, since
the default for autoconf when no
action is defined for the case the user gives a parameter is to
set a special variable named with the enable_
(or with_
) prefix, like
enable_foo
.
Example 1.1. Using AC_ARG_ENABLE
without actions
dnl Example of default-enabled feature AC_ARG_ENABLE([foo], AS_HELP_STRING([--disable-foo], [Disable feature foo])) AS_IF([test "x$enable_foo" != "xno"], [ dnl Do the stuff needed for enabling the feature ]) dnl Example of default-disabled feature AC_ARG_ENABLE([bar], AS_HELP_STRING([--enable-bar], [Enable feature bar])) AS_IF([test "x$enable_bar" = "xyes"], [ dnl Do the stuff needed for enabling the feature ])
In the above example, only the recognised options of
no
and yes
(respectively for each case) are used; any other value given
(e.g. --enable-foo=baz or
--enable-bar=fnord) would be ignored and
treated in the same way as the default value of no parameter
given.
Further safety checking of the value to exclude anything but
yes
or no
can be
added, but is usually not necessary for the simplest cases.
Some discussion of the help strings used for declaring parameters with both
AC_ARG_ENABLE
and AC_ARG_WITH
is
warranted; since past versions have changed autoconf and
they tend to be often mistakenly used.
The second parameter for the two macros above is the
description string as output by ./configure
--help; since proper formatting of that string is
almost impossible to achieve by hand, there is a macro that
autoconf provides to generate it:
AS_HELP_STRING
(replacing the former,
deprecated macro AC_HELP_STRING
, which is
virtually identical, but has a less clear name).
This macro takes care of properly aligning the text, breaking the lines where needed. For instance take the following fragment:
dnl configure.ac text… dnl to give an example of default-provided help text AC_HEADER_ASSERT AC_ARG_ENABLE([foo], [ --enable-foo enable the use of foo through this very long and boring help text]) AC_ARG_ENABLE([bar], AS_HELP_STRING([--enable-bar], [enable the use of bar through this very long and boring help text]) ) # output from ./configure --help --disable-assert turn off assertions --enable-foo enable the use of foo through this very long and boring help text --enable-bar enable the use of bar through this very long and boring help text
As you can see the text that is not typeset through the use of
AS_HELP_STRING
is not properly aligned
(the distance used in the example is two tabulations, at most
sixteen spaces, depending on the length of the option text,
which falls short of two spaces).
It's not really important for what concerns the functionality
of the script, but it's useful to keep for consistency. Also,
this allows software inspecting
configure.ac
files to identify the
available options (for eventual graphical frontends to
./configure or auto-generation of
packaging description files (RPM specifications, Gentoo
ebuilds, …).
Sometimes, the external dependencies of a project can be a hassle, especially if they enable optional features that not every operating system supports or that some users don't really care about. For this reason, they are often made optional, non-mandatory.
When the option is non-mandatory, but it's desirable if certain software is present in the system, it's usual to make the dependency automatic. Automatic dependencies are enabled only if the needed libraries are found, and “soft-fail” in disabling the features if they are not. Distributions further specialise this class in automatic and automagic dependencies; this latter name is used for those dependencies that don't allow being overridden, and thus will always enable the features if the libraries are found, and always soft-fail when they are not found. For distributions like Gentoo Linux that build on users' systems, this situation is actually problematic and has to be resolved to properly package the software ([GentooAutomagic]).
To avoid this kind of problem, the best thing is to implement a
--with parameter that allows overriding
automatic detection: forcing it to yes
would make the code fail
entirely when the library is not detected, and forcing it to no
would make the code skip over the check entirely.
Example 1.2. Using AC_ARG_WITH
to declare
automatic dependencies.
AC_ARG_WITH([foo], AS_HELP_STRING([--without-foo], [Ignore presence of foo and disable it])) AS_IF([test "x$with_foo" != "xno"], [CHECK_FOR_FOO([have_foo=yes], [have_foo=no])], [have_foo=no]) AS_IF([test "x$have_foo" = "xyes"], [do_whatever_needed], [AS_IF([test "x$with_foo" = "xyes"], [AC_MSG_ERROR([foo requested but not found]) ]) ])
Once again, the empty value, and any other value from
yes
and no
are
handled together as a default case (that we could call the
auto
case), and no extra sanity check is
added.
The library is checked for unless explicitly requested not to,
and the $have_foo
variable is set
accordingly. If foo hasn't been found, but there was an
explicit request for it, an error message is displayed and the
configure
script stops there.
The AC_ARG_VAR
macro is used to declare a
particular (environment) variable as an argument for the script,
giving it a description and a particular use. While this feature
has been added relatively recently in the history of
autoconf, it is really important.
Reflecting its more recent presence, the macro does not need the
AS_HELP_STRING
helper, and only takes two
parameters: the name of the variable and the string printed
during ./configure --help:
AC_ARG_VAR(var-name, help-string)
By default, configure
picks up the
variables from the environment like any other sh script. Most of
those are ignored. Those that are not should be
declared through this macro. This way they are marked as
a precious variable.
A variable marked as precious gets replaced
in the Makefile.in
without having to call
an explicit AC_SUBST
, but that's not the
most important part of the definition. What is important is that
the variable is cached.
When running ./configure with the variable set (both when setting it in the environment and when setting it just for the execution via ./configure FOO=bar), its value is saved in either the proper cache file (if requested, see Section 7, “Caching Results”) or in the configuration status. This in turn produces two effects:
the variable is compared for consistency between different cached runs, to avoid re-using an incompatible cache file;
the variable is saved for re-execution when using ./config.status --recheck (as used by maintainer mode).