The versioninfo mechanism
=========================

This describes the versioninfo mechanism which automatically generates
the version information for use in `configure.ac` and then the rest of
the autotools build system.


The basic idea
--------------

The main goals are

  * Avoid the need for avrdude maintainers to edit the avrdude version
    in the autotools buildsystem's `configure.ac` in addition to the
    cmake buildsystem's main `CMakeLists.txt` file.

  * Have the autotools buildsystem generate the same version message as
    the cmake buildsystem in both the `avrdude.conf` file and the
    `avrdude -?` output version message.

To achieve this, we need to replicate some of the logic from the
top-level `CMakeLists.txt` which creates the `AVRDUDE_FULL_VERSION`
variable.

We run this logic mostly at bootstrap/autoreconf time, with the
`configure` propagating the information, so that some `make` time
checks can determine whether the bootstrap code needs to be re-run,
and re-run it automatically if possible.


All the different build types
-----------------------------

There are many ways to build avrdude.

There are three types of source trees:

  * a git clone's working directory with a `.git/` directory

  * an extracted GitHub tarball/zipfile (contains the same as a git
    clone's working directory, but no `.git/` directory with its
    associated git commit information)

  * from a dist tarball as generated by the autotools buildsystem's
    `make dist` or `make distcheck` commands (contains the required
    git commit information inside the versioninfo-stamp file)

In any of these cases, this can be an avrdude release or non-release,
determined by whether the latest commit's hash is equal to the latest
tag's commit's hash (`GIT_COMMIT_HASH == GIT_TAG_HASH`).

In principle, any of these source types could be built with either the
cmake buildsystem or the autotools buildsystem. With `configure.ac`
being rooted in the `src/` subdirectory though, the dist tarball
generated by `make dist` cannot contain files outside of `src/` which
are required for a cmake build.

In all types of builds, we want the same version message when building
using the autotools buildsystem as the cmake buildsystem creates:

  * `7.3` for a release
  * `7.3-20240213 (9634fd15)` with commit date and commit hash for a
    non-release.

If we abbreviate those types of version messages with `R` for release
and `H` for hash, we can put all cases into a table. `BS` stands for
buildsystem, obviously.

```
                               Version_Message
SOURCE TYPE     BS  Release?   Wanted  Actual
git clone wd    cm  yes        R       R
git clone wd    cm  no         H       H
github tarball  cm  yes        R       R
github tarball  cm  no         H       R (wrong/missing info)
dist tarball    cm  yes        R       cmake build N/A at this time
dist tarball    cm  no         H       cmake build N/A at this time

git clone wd    am  yes        R       R
git clone wd    am  no         H       H
github tarball  am  yes        R       R
github tarball  am  no         H       R (wrong/missing info/like cmake)
dist tarball    am  yes        R       R
dist tarball    am  no         H       H
```

As the github tarball (like the github zipfile) does not contain any
commit/tag information, it is impossible for any buildsystem to
determine whether building a release or non-release.

The dist tarball generated by the autotools buildsystem's `make dist`
does contain the commit/tag information, so builds from such a dist
tarball can correctly determine whether they are building a release or
a non-release source tree. However, only builds using the autotools
buildsystem are possible as long as the `configure.ac` file is located
inside the `src/` subdirectory instead of the top-level directory.


The `build-helpers/versioninfo.sh` script file
----------------------------------------------

The `versioninfo.sh` script tries to determine the version and git
information from the raw sources:

  * The version number (`7.3`) is determined from the top-level
    `CMakeLists.txt` file's `project(... VERSION ...)` line.

  * The information on the latest git commit date and hash and git tag
    hash is determined from the `.git/` subdirectory corresponding to
    the top-level `CMakeLIsts.txt` file.

The `versioninfo.sh` script then prints these items, one per line.


The `build-helpers/versioninfo.m4` m4 include file
--------------------------------------------------

This defines the two parts of the m4 code:

  * The m4 code which calls `versioninfo.sh`, parses its output, and
    defines some m4 macros before `AC_INIT`:

      * The `versioninfo_items` macro describes the sequence of
        versioninfo items printed in lines by the `versioninfo.sh`
        script

      * The `versioninfo_init` macro runs the `versioninfo.sh` script
        and parses its output, `m4_define`ing a `versioninfo_<ITEM>`
        macro for each `ITEM` from `versioninfo_items`

      * The `versioninfo_stampfile` macro contains the name of the
        stamp file which caches the versioninfo items for use in
        tarballs.

      * The `versioninfo_init` macro is evaluated once, so that
        `versioninfo.sh` is only run once as well.

    The m4 macros with the parsed results can then be evaluated using
    `m4_defn(...)` both in the `AC_INIT(...)` invocation for the
    `PACKAGE_VERSION`, and also later for defining
    `AVRDUDE_FULL_VERSION` and git commit information.

  * The m4 code `AC_DEFUN`s the `VERSIONINFO_SETUP` macro, which in
    turn defines `AC_SUBST` substitution and make variables for each
    of the versioninfo items, and also defines a few
    stubstitution-only (not make) variables for use in make rules in
    `versioninfo.mk` and `GNUmakefile.in`, which write, read, parse,
    and compare the versioninfo items as defined in
    `versioninfo_items`.


The `build-helpers/versioninfo.mk` Makefile include file
--------------------------------------------------------

To be `include`d into the top-level `Makefile.am`, this does two things:

  * Hooks into the `dist` and `distcheck` targets to check the
    recorded version information is the same one `versioninfo.sh`
    would detect right now, and prevents builds with out of date
    versioninfo items.

  * Writes the stamp file with the versioninfo data when creating a
    dist tarball.


The `configure.ac` file
-----------------------

Before `AC_INIT`, uses m4 logic to evaluate what the `PACKAGE_VERSION`
should be.

Expands the `VERSIONINFO_SETUP` macro both to run its content and to
force `aclocal` to pull in `versioninfo.m4` into `aclocal.m4` so that
the m4 code from `versioninfo.m4` is evaluated before `AC_INIT`.

Evaluates the `AVRDUDE_FULL_VERSION` message and adds it as both a C
preprocessor macro and a autoconf substitution and make variable.


The `GNUmakefile.in` and `GNUmakefile` files
--------------------------------------------

If you are running GNU make, the `GNUmakefile` file generated from the
`GNUmakefile.in` file will update the versioninfo automatically before
executing any possible make recipes.

If you are not running GNU make, you will need to run the command to
update the versioninfo update command manually. You will be shown that
command if necessary.
