## Structure of the toolchain scripts:

- `install_cp2k_toolchain.sh` is the main script that will call all
  other scripts.  It contains default flag settings, user input
  parser, calls to each package installation scripts and the
  generator of the CP2K arch files.

- `script/install_*.sh` are the installation scripts for individual
  packages. They are relatively independent, in the sense that by
  running `script/install_PKG.sh` it should install the package on its
  own. However, in practice due to dependencies to other libraries,
  sometimes for a package to be installed this way, it will depend
  on other libraries being already installed and the correct
  environment variables set. At the end of each script, it should
  write to __two__ files: `build/setup_PKG` and `install/setup`.
  - The `build/setup_PKG` file contains all the instructions to set
    the variables used by the `install_cp2k_toolchain.sh` and other
    `script/install_PKG.sh` scripts in order for them to correctly
    compile the toolchain and set the correct library flags for the
    arch files.
  - The `install/setup` file contains all the instructions for setting
    up the correct environment before the user can compile and/or
    run CP2K.

- `script/toolkit.sh` contains all the macros that may be used by all
  of the scripts, and provides functionalities such as prepending a
  path, checking if a library exists etc.

- `script/common_var.sh` contains all of the common variables used by
  each installation scripts. All of the variables in the file should
  have a default value, but allow the environment to set the values,
  using: `VAR=${VAR:-default_value}`.

- `script/parse_if.py` is a python code for parsing the `IF_XYZ(A|B)`
  constructs in the script. Nested structures will be parsed
  correctly. See
  [`IF_XYZ` constructs](./README_FOR_DEVELOPERS.md#the-if_xyz-constructs) below.

- `checksums.sha256` contains the pre-calculated SHA256 checksums for
  the tar balls of all of the packages. This is used by the
  `download_pkg` macro in `script/toolkit.sh`.

- `arch_base.tmpl` contains the template skeleton structure for the
  arch files. The `install_cp2k_toolchain` script will set all the
  variables used in the template file, and then do an eval to expand
  all of `${VARIABLE}` items in `arch_base.tmpl` to give the cp2k arch
  files.

## `enable-FEATURE` options

The `enable-FEATURE` options control whether a FEATURE is enabled or disabled.
Possible values are:
- `yes` (equivalent to using the option-keyword alone)
- `no`

## `with_PKG` and `PKG_MODE` variables:

The `with_PKG` options controls how a package is going to be
installed:
- either compiled and installed from source downloaded
(`install`, or the option-keyword alone),
- or linked to locations provided by system search paths (`system`),
- or linked to locations provided by the user
(`<path>`, path to some directory),
- or that the installer won't be used (`no`).

For most packages the `with_pkg` variables will act like a switch for
turning on or off the support for this package. However, for
packages serving the same purpose, with the installer needing only
one, an extra variable `PKG_MODE` (e.g. `MPI_MODE`) are used as a
selector.  In this case, while `with_PKG` controls the installation
method, the `PKG_MODE` variable picks which package to actually use.
This provides more flexibility.

## The IF_XYZ constructs

Due to the fact that `install_cp2k_toolchain.sh` needs to produce
several different versions of the arch files: `popt`, `psmp`, `pdbg`,
`sopt`, `ssmp` etc, it will have to resolve different flags for
different arch file versions.

The solution used by this script is to use a syntax construct:

```
IF_XYZ(A | B)
```

A parser will then parse this expression to *A* if *XYZ* is passed
to the parser (python `parse_if.py` filename XYZ); and to *B* if *XYZ*
is not passed as command line option (python `parse_if.py` filename).

The `IF_XYZ(A|B)` construct can be nested, so things like:

```
IF_XYZ(IF_ABC(flag1|flag2) | flag3)
```

will parse to *flag1* if both *XYZ* and *ABC* are present in the command
line arguments of `parser_if.py`, to *flag2* if only *XYZ* is present,
and *flag3* if nothing is present.

## To ensure portability:

- one should always pass compiler flags through the
  `allowed_gcc_flags` and `allowed_gfortran_flags` filters in
  `scripts/toolkit.sh` to omit any flags that are not supported by
  the gcc version used (or installed by this script).

- note that `allowed_gcc_flags` and `allowed_gfortran_flags` do not work
  with `IF_XYZ` constructs. So if you have something like:

```
FCFLAGS="IF_XYZ(flag1 flag2 | flag3 flag4)"
```

Then you should break this into:

```
XYZ_TRUE_FLAGS="flags1 flags2"
XYZ_FALSE_FLAGS="flags3 flags4"
# do filtering
XYZ_TRUE_FLAGS="$(allowed_gcc_flags $XYZ_TRUE_FLAGS)"
XYZ_FALSE_FLAGS="$(allowed_gcc_flags $XYZ_FALSE_FLAGS)"
```

So that:

```
FCFLAGS="IF_XYZ($XYZ_TRUE_FLAGS | $XYZ_FALSE_FLAGS)"
```

- For any intrinsic fortran modules that may be used, it is best to
  check with `check_gfortran_module` macro defined in
  `script/tool_kit.sh`. Depending on the gcc version, some intrinsic
  modules may not exist.

- Try to avoid as much hard coding as possible:
  e.g. instead of setting:

```
./configure --prefix=some_dir CC=mpicc FC=mpif90
```

use the common variables:

```
./configure --prefix=some_dir CC=${MPICC} FC=${MPIFC}
```

## To keep maintainability it is recommended that we follow the following practices:

- Reuse as much functionality from the macros defined in the
  `script/toolkit.sh` as possible

- When the existing macros in `script/toolkit.sh` do not provide the
  functionalities you want, it is better to write the new
  functionality as a macro in `script/toolkit.sh`, and then use the
  macro (repeatedly if required) in the actual installation
  script. This keeps the installation scripts uncluttered and more
  readable.

- All packages should install into their own directories, and with a
  lock file created in their respective directory to indicate
  installation has been successful. This allows the script to skip
  over the compilation stages of already installed packages if the
  user terminated the toolchain script at the middle of a run and
  then restarted the script.
