Autotools and bash-completion scripts
Whenever a command-line utility has a lot of options, it's helpful to have automatic command-line tab-completion support for those in the shell. I recently tried adding this support to the libbitcoin-explorer project, but found that the whole process is rather arcane and undocumented. This guide will hopefully shed some light on things, at least for your typical autotools-based open-source project.
The first task is to actually write the bash completion script. Fortunately, there is already a nice guide for how to do this:
Once you have your script, the first question is where to put it in the source tree. While there isn't any documentation on this, the best place seems to be somewhere inside the
data directory. This is the standard location for ancillary support files like icons, stylesheets, desktop entries, and such, so a command-line completion script fits right in.
Now that the file exists, the next step is to integrate it with the build system so
make install actually puts it somewhere on the user's sytem. The problem is, that "somewhere" is different from one distro to the next, and some distros don't even have bash. There is no solution that makes everyone happy, so the best compromise is to let the user control this via the configure script.
Autoconf options come in two standard flavors. "With" options control integration with external software, like optional libraries. If a program can use
libfoo to provide enhanced features, the user should be able to configure that with options like
--without-libfoo. "Enable" options, on the other hand, turn optional parts of the program on or off at compile time. Options like
--disable-utilites, for example, might determine whether or not some optional utilites are built.
Since bash is an external program, we definitely want a "with" option. I've seen a few packages that provide an
--enable-bash-completion option, but this is a mistake! The correct, semi-standard configure option seems to be
--with-bash-completion-dir. To add this flag to the configure script, put the following lines in
AC_ARG_WITH([bash-completion-dir], AS_HELP_STRING([--with-bash-completion-dir[=PATH]], [Install the bash auto-completion script in this directory. @<:@default=yes@:>@]), , [with_bash_completion_dir=yes])
Once this block of code runs, a variable called
with_bash_completion_dir will exist with one of three possible values:
- A path, as provided by the user.
- "no" - The user specified
- "yes" - The user specified
--with-bash-completion-dir, but didn't give a path. This is also the default.
Now that this option exists, the configure script needs to do something with it. The first step is turn a "yes" answer into a default location:
if test "x$with_bash_completion_dir" = "xyes"; then PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0], [BASH_COMPLETION_DIR="`pkg-config --variable=completionsdir bash-completion`"], [BASH_COMPLETION_DIR="$datadir/bash-completion/completions"]) else BASH_COMPLETION_DIR="$with_bash_completion_dir" fi
This code snippet uses the
bash-completion package to determine the default install location if that package happens to be available. Otherwise, the snippet uses
$datadir/bash-completion/completions, which is a reasonable default location for many modern distros.
The only thing left for the configure script to do is to pass these options to the makefile:
AC_SUBST([BASH_COMPLETION_DIR]) AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "x$with_bash_completion_dir" != "xno"])
Compared to the configure script, the makefile is easy:
if ENABLE_BASH_COMPLETION bashcompletiondir = $(BASH_COMPLETION_DIR) dist_bashcompletion_DATA = data/your-script endif
This code snippet goes in your top-level
Makefile.am. If you are still using old-fashioned recursive make, you could also put it in your
data/Makefile.am sub-file. In either case, be sure to change
data/your-script to the correct relative path for your bash completion script.