.. _build_system:
.. index:: Build system
Hacking the build system
******************************
.. index:: Autotools
Using the Autotools
=============================
The build system of :program:`libvdwxc` is based on the Autotools,
which automate a lot of common operations related to the build,
distribution, and installation, of software packages, as soon as they
comply with a reasonable set of software programming good
practices. By default, the structure of the source code has to follow
the `GNU Coding Standards `_.
Having some familiarity with them will help understanding why some
files must be present within the source tree.
While end-users can safely ignore the Autotools, developers have to
know a minimum about them. For any question, you can always refer to
their official documentation:
* `Autoconf `_
* `Automake `_
* `Libtool `_
* `GNU M4 `_
or to these books and tutorials:
* `Autotools Mythbuster `_
* `Autotools Guide `_
* `Autotools Tutorial `_
However, most of the common development-related tasks are sufficiently
self-explanatory to be performed without consulting these documents.
In the following sections, we describe the tasks a developer has to
perform in different situations, by increasing complexity. We will
suppose that you are already familiar with `make` and the use of
`makefiles`. If not, please consult the `GNU Make Manual
`_ and practice a little
bit before continuing.
Synchronising the build system
========================================================================
The simplest task a developer has to perform is to synchronise the
build system with the source tree every time the structure of the
latter has changed. It requires the execution of a series of
predefined operations in a particular order. In order to facilitate
this task, a script called `autogen.sh` is present at the top of the
Git working tree of the package. It is particularly useful to
bootstrap a freshly cloned Git repository. To run it, just type::
./autogen.sh
from the top source directory. Once the `configure` script and the
`Makefile.in` files have been created, later synchronisations can be
performed by running the `autoreconf` convenience script::
autoreconf -i
The `-i` option tells the script to install or re-install possibly
missing files used by the Autotools. Most of these files are stored in
the `config/gnu/` subdirectory and must always be left untouched.
In very rare circumstances, the synchronisation may fail repeatedly,
due to some inconsistencies between the Autotools files. In such a
case, you may run the `wipeout.sh` script. Be warned though that this
script will remove many files and basically bring back to Git working
tree to its pristine state. In particular, it will remove any file or
directory named `tmp`, starting with `tmp-`, or ending in `.tmp`.
Please note that synchronisation has to occur only when there is a
change in the source tree structure: adding, removing, or renaming, a
file or a directory, or when changing something in the build system
itself. It is usually the last task to perform when one of these
changes occurs.
Adding a source file
========================================================================
When adding a source file, the build system has to be made aware of
the new file by adding it to the corresponding Makefile.am, usually in
the same directory. Where to add it mainly depends on the nature of
the file.
Before going into the details, we would like to attract your attention
on the most common mistakes people do when modifying `Makefile.am`
files:
* using wrong names: in a `Makefile.am`, all names have a meaning for
Automake, which means that you cannot change them because they look
"inaesthetic" to you; what feels inadequate to you is actually a
programming language;
* forgetting the final `\\` continuation characters in multiline
descriptions;
* leaving a final `\\` continuation character on the last line of a
multiline description.
All these mistakes will likely cause `Automake` to fail. We thus
highly recommend that you use an editor with syntax highlighting when
modifying a `Makefile.am`.
If the file is a `.c` source, it will go to a `_SOURCES`
variable. Finding which one is just a question of common sense, since
you already know what this file is for.
If the file is a `.h` source, it will go to a `_HEADERS` variable. If
it is supposed to be installed, it will most likely fit into
`include_HEADERS`. If it is purely internal, then it should be
registered within `noinst_HEADERS`.
If the file can be considered as inert data from the perspective of
the build system, it should go to the `EXTRA_DIST` variable. `.c`
files included in other `.c` files enter in this category. Another
typical example is a local `README` file.
Once done with `Makefile.am`, synchronise the build system with the
source tree.
Adding a library
========================================================================
Every library defined within :program:`libvdwxc` is managed by
Libtool. Therefore, it must be declared as `libname.la`, where `name`
is its distinctive name, in one of the `_LTLIBRARIES` variables. If it
is supposed to be installed, it will have to be declared in
`lib_LTLIBRARIES`. If not, it should go into `noinst_LTLIBRARIES`.
Any new library must have a corresponding `libname_la_SOURCES`
variable, containing the list of its source files. Please be careful
not ot mix different languages in the same directory, as it creates a
lot of portability issues. In particular, C and Fortran files must go
into separate libraries located in different directories.
If the new library depends on another internal :program:`libvdwxc`
library, it will require a `libname_la_LIBADD = libother.la`
declaration as well.
Once done with `Makefile.am`, synchronise the build system with the
source tree.
Adding a program
========================================================================
Every program must be declared in a `_PROGRAMS` variable, either:
* in `bin_PROGRAMS` if it is installed;
* in `noinst_PROGRAMS` if it is not installed;
* in `check_PROGRAMS` if it is a test program executed by `make check`.
Just as libraries, a program named `myprog` requires a
`myprog_SOURCES` variable.
If the program depends on internal libraries, it will require a
`myprog_LDADD = libname.a libother.a` declaration as well.
Once done with `Makefile.am`, synchronise the build system with the
source tree.
Adding a subdirectory
========================================================================
If a new subdirectory only contains data, it can then be managed from
the `Makefile.am` of its parent directory, through the `EXTRA_DIST`
variable.
If it contains source files that will be compiled, then it must
contain a `Makefile.am`. To ease the process, you can copy a similar
`Makefile.am` to the new directory and modify it as explained in the
previous sections.
Once done with the new `Makefile.am`, you have to add the new
directory to the `SUBDIRS` variable of the parent `Makefile.am`.
The following step is to add the `Makefile` (**NOT** the
`Makefile.am`) to the `AC_CONFIG_FILES` list in `configure.ac`
(located at the end of the file).
Once done, synchronise the build system with the source tree.
Adding an optional feature trigger
========================================================================
Optional features are controlled by the `--enable-feature` options of
the `configure` script and linked to the source code through the
definition of `HAVE_FEATURE` preprocessing options. All the relevant
code is stored in `configure.ac`, the source of the `configure`
script.
Here is the procedure we recommend to add a new option:
#. Inform the other developers of what you are up to.
#. Look in `configure.ac` at the `enable_debug` and `enable_timing`
options. They are represented respectively by the
`vdw_debug_enable` and `vdw_timing_enable` internal build-system
variables.
#. Once you understand enough how things work, duplicate the code
associated to `vdw_debug_enable`, renaming it to match your new
option.
#. Synchronise the build system with the source code and run
`configure` twice, once without your new option and once with
it. In both cases, look at the contents of `config.h` to confirm
that your option is correctly defined.
#. Build :program:`libvdwxc` with `make` after configuring with your
option enabled. Check that the corresponding code is actually
built.
Adding an external dependency
========================================================================
If you need to add a new external dependency to :program:`libvdwxc`,
it is necessary to openly discuss it with the other developers. Unless
you have a solid experience in writing Autotools-based build systems,
you will have to do the corresponding work in tight collaboration with
an expert and delegate a significant part of it. We thus recommend you
to define clear specifications by answering to the following questions
beforehand:
#. Will the new dependency be mandatory or optional? Examples: FFTW3
is mandatory, while PFFT is optional.
#. Will the new dependency be auto-detected or ignored by default?
Examples: MPI is auto-detected by default, PFFT only if MPI is
present.
#. Is the new dependency available through libraries, or does it use
another mechanism? Examples: FFTW3 and PFFT provide libraries,
while MPI provides compilers.
#. Does the new dependency require already known dependencies?
Examples: MPI does not, PFFT depends on MPI.
#. Is the configuration of the new dependency affected by other
dependencies? Examples: PFFT has only one configuration, while
FFTW3 provides different libraries for the serial and MPI cases.
Adding an external dependency requires the writing of new M4 macros,
stored in the `config/m4/` subdirectory of the source tree. Although
M4 is a relatively simple language, its mastery in the context of the
Autotools requires a lot of practice. This is why at least pair
programming will be necessary to achieve the creation of the new
options and related detection mechanisms. Most probably, the
specifications agreed upon will be transmitted to experts and the
details of the implementation left up to them.