Skip to content

9. One fobos, many machines ​

quad is built on a laptop and on a cluster. The two differ in a few values (here, the processor the code is tuned for), and a project may be built with other compilers too. Copying the modes for each machine would double the fobos; this chapter keeps one set of modes and moves what differs into values chosen at build time.

Values chosen by machine: varsets ​

A varset is a named set of $variables. The machines get their own file, included by the fobos, which also lists an optional file of the developer's own:

ini
[include]
paths = machines.fobos
        ?fobos.local
console
$ cat machines.fobos
[varsets]
default = laptop

[varset:laptop]
$TUNE = -mtune=native

[varset:cluster]
$TUNE = -mtune=znver3

The release mode uses $TUNE, and adds a flag only when the compiler is gfortran:

ini
[release]
help          = Optimised
template      = template-gnu
build_profile = release
cflags        = -c $TUNE
cflags.gnu    = -fimplicit-none
cflags.intel  = -warn all
post_build    = smoke
build_dir = ./build/release/
target    = $PROGRAM

fobis introspect shows the varsets and the flags they give:

console
$ fobis introspect --varsets
{
  "varsets": {
    "default": [
      "laptop"
    ],
    "varsets": {
      "laptop": {
        "$TUNE": "-mtune=native"
      },
      "cluster": {
        "$TUNE": "-mtune=znver3"
      }
    }
  }
}
console
$ fobis introspect --buildoptions --mode release
{
  "buildoptions": {
    "mode": "release",
    "build_dir": "./build/release/",
    "obj_dir": "./obj/",
    "mod_dir": "./mod/",
    "mklib": "",
    "jobs": 1,
    "qualified_keys": [
      {
        "key": "cflags.gnu",
        "kind": "compiler",
        "value": "-fimplicit-none",
        "applied": true,
        "how": "appended",
        "result": "-O3 -funroll-loops -c -mtune=native -fimplicit-none"
      },
      {
        "key": "cflags.intel",
        "kind": "compiler",
        "value": "-warn all",
        "applied": false
      }
    ]
  }
}

--varset cluster selects the other one:

console
$ fobis introspect --buildoptions --mode release --varset cluster
{
  "buildoptions": {
    "mode": "release",
    "build_dir": "./build/release/",
    "obj_dir": "./obj/",
    "mod_dir": "./mod/",
    "mklib": "",
    "jobs": 1,
    "qualified_keys": [
      {
        "key": "cflags.gnu",
        "kind": "compiler",
        "value": "-fimplicit-none",
        "applied": true,
        "how": "appended",
        "result": "-O3 -funroll-loops -c -mtune=znver3 -fimplicit-none"
      },
      {
        "key": "cflags.intel",
        "kind": "compiler",
        "value": "-warn all",
        "applied": false
      }
    ]
  }
}

qualified_keys reports what cflags.gnu and cflags.intel did: the first was appended because the mode's compiler is gfortran, the second was not applied. A key qualified by a system (cflags.linux, ext_libs.windows) works the same way.

Build for the cluster ​

The first build compiles with the default varset, laptop. cflags_heritage = True (from the template) records the flags, so building for the cluster compiles everything again:

console
$ fobis build --mode release --quiet --force-compile

Building src/integrate.F90
Compiling .fobis_deps/penf/src/lib/penf_global_parameters_variables.F90 serially
Compiling .fobis_deps/penf/src/lib/penf_b_size.F90 serially
Compiling .fobis_deps/penf/src/lib/penf_stringify.F90 serially
Compiling src/quad_rules.F90 .fobis_deps/penf/src/lib/penf_allocatable_memory.F90 serially
Compiling src/integrands.F90 .fobis_deps/penf/src/lib/penf.F90 serially
Compiling src/integrate.F90 serially
Linking build/release/integrate
Target src/integrate.F90 has been successfully built
Executing rule "smoke"
   Command => ./build/release/integrate | tail -n 1
Simpson, 64 intervals: 2.0000000645300013
console
$ fobis build --mode release --varset cluster --quiet
The present cflags are different from the heritages one: forcing to (re-)compile all

Building src/integrate.F90
Compiling .fobis_deps/penf/src/lib/penf_global_parameters_variables.F90 serially
Compiling .fobis_deps/penf/src/lib/penf_b_size.F90 serially
Compiling .fobis_deps/penf/src/lib/penf_stringify.F90 serially
Compiling src/quad_rules.F90 .fobis_deps/penf/src/lib/penf_allocatable_memory.F90 serially
Compiling src/integrands.F90 .fobis_deps/penf/src/lib/penf.F90 serially
Compiling src/integrate.F90 serially
Linking build/release/integrate
Target src/integrate.F90 has been successfully built
Executing rule "smoke"
   Command => ./build/release/integrate | tail -n 1
Simpson, 64 intervals: 2.0000000645300013

A varset that does not exist stops the build and lists the defined ones:

console
$ fobis build --mode release --varset nowhere
Error: varset 'nowhere' is not defined.
  Available varsets: cluster, laptop
[exit status 1]

A developer's own values ​

?fobos.local is optional: without the file nothing happens. A developer who wants other values writes it, and it wins over machines.fobos because it comes later in paths. It is ignored by git, so it never reaches the repository:

console
$ cat fobos.local && git status --short
[varset:laptop]
$TUNE = -mtune=generic
 M .gitignore
 M fobos
?? machines.fobos
console
$ fobis introspect --buildoptions --mode release
{
  "buildoptions": {
    "mode": "release",
    "build_dir": "./build/release/",
    "obj_dir": "./obj/",
    "mod_dir": "./mod/",
    "mklib": "",
    "jobs": 1,
    "qualified_keys": [
      {
        "key": "cflags.gnu",
        "kind": "compiler",
        "value": "-fimplicit-none",
        "applied": true,
        "how": "appended",
        "result": "-O3 -funroll-loops -c -mtune=generic -fimplicit-none"
      },
      {
        "key": "cflags.intel",
        "kind": "compiler",
        "value": "-warn all",
        "applied": false
      }
    ]
  }
}

What you learned

[varset:NAME], [varsets] default, --varset, keys qualified by a compiler (cflags.gnu), [include] paths with an optional ?file, fobis introspect --varsets and --buildoptions. Reference: varsets, qualified keys, includes.

Next: several programs and a library for others.