3. Adding Options

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:

--enable-*/--disable-* arguments

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.

--with-*/--without-* arguments

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

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.

3.1. AC_ARG_ENABLE and AC_ARG_WITH

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.

Warning

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.


3.1.1. The Help Strings

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, …).

3.2. Automatic Dependencies with AC_ARG_WITH

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.


3.3. Environment Variables as Arguments

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).