What a toolchain injects¶
What you will be able to do
Say which environment variables a toolchain sets during a build, and where they come from.
Read a
toolchainoptsdictionary and say what each option changes.Say what
optarchdoes and why it decides where a binary can run.
A toolchain is a hierarchy covered the dependencies a toolchain makes visible. This chapter addresses the other half: the impact on the compiler.
The variables, and where they are not¶
What a build is allowed to see measured the surprising part, and it is worth restating.
Loading a toolchain module provides EBROOTFOSS and EBVERSIONFOSS.
It does not provide $CC.
EasyBuild’s toolchain object sets the compiler variables during prepare inside the build.
A foss build receives, among others, the following variables:
Variable |
Contents |
|---|---|
|
the compiler drivers |
|
the MPI wrappers |
|
optimisation and architecture flags |
|
library and include paths for every dependency |
|
the link lines for the numerical libraries |
The final row explains why a foss easyconfig seldom names a BLAS.
The toolchain identifies the BLAS and supplies the build with its link line.
An easyconfig that hardcodes -lopenblas describes a specific toolchain and will become incorrect for subsequent toolchains.
The practical consequence matches that described in What a build is allowed to see.
Reproducing a build’s environment requires more than loading its toolchain; eb --dump-env-script is necessary, as explained in Standing where the build stood.
toolchainopts is a dictionary of switches¶
Each key determines the values placed by the toolchain object into those variables.
foss in EasyBuild 5.3 accepts roughly thirty entries, and the list is:
The options a foss build accepts, abridged
$ eb --avail-toolchain-opts=foss
Available options for foss toolchain:
cstd: Specify C standard (default: None)
debug: Keep debug symbols (default: None)
extra_cflags: Specify extra CFLAGS options. (default: None)
i8: Integers are 8 byte integers (default: False)
ieee: Adhere to IEEE-754 rules (default: False)
lto: Enable Link Time Optimization (default: False)
noopt: Disable compiler optimizations (default: False)
openmp: Enable OpenMP (default: False)
opt: High compiler optimizations (default: False)
optarch: Enable architecture optimizations (default: True)
pic: Use PIC (default: False)
shared: Build shared library (default: False)
static: Build static library (default: False)
strict: Strict (highest) precision (default: False)
usempi: Use MPI compiler as default compiler (default: False)
verbose: Verbose output (default: False)
veryloose: Very loose precision (default: False)
Recorded: SURF Snellius, int4 interactive node, 2026-09-10, EasyBuild 5.3.1
Four of them cover most of the entries found in real easyconfigs.
usempi sets $CC to the MPI wrapper instead of the bare compiler.
A package whose build system lacks MPI wrapper awareness and uses $CC receives MPI through this mechanism.
Use it for parallel software whose configure script does not provide --with-mpi.
openmp adds the compiler’s OpenMP flag.
This is required when the source contains #pragma omp and the build system does not supply the flag, a situation that occurs more often than expected.
pic adds -fPIC.
This is required when a static library is linked into a shared one, and the resulting error without it mentions a relocation rather than a recognizable symbol.
The precision family, strict through veryloose, should remain unchanged unless a specific reason exists.
It alters floating-point semantics, which in turn changes results.
A physics code that specifies strict asserts a claim about its own numerics, and altering it silently modifies the scientific outcome.
optarch decides where the binary runs¶
optarch is enabled by default and has the greatest impact.
When enabled, the compiler receives -march=native or the toolchain’s equivalent to optimise for the current microarchitecture.
That binary runs faster and may use instructions unavailable on other processors in the same cluster.
This mechanism underlies What “installed” means’s per-architecture install trees.
A site with mixed hardware maintains separate trees not for tidiness but.
There are two methods for a site to control this.
Specifying --optarch on the command line sets the flag globally.
The site can then build for a named baseline instead of the specific node where the build occurs.
Setting toolchainopts = {'optarch': False} disables it for a single package.
Use this option when a package is known to miscompile under aggressive optimisation.
An easyconfig requiring optarch: False must include an explanatory comment.
The comment represents a claim about the software, not the site, preventing future readers from assuming a cargo‑culted setting.
EB-Toolchainopts-1 — Four errors, four options
Four build failures, each fixed by one toolchainopts key.
undefined reference to `omp_get_num_threads'relocation R_X86_64_32S against `.rodata' can not be used when making a shared objectmpi.h: No such file or directory, from a Makefile that compiles with$(CC)The build succeeds on the build host and dies with
Illegal instructionon an older node in the same cluster.
Give the key for each. Then say which of the four is not really a toolchain question at all, and what you would rather do about it.
Solution
1 is openmp. The source uses OpenMP and nothing added the flag.
2 is pic. Something static is being linked into something shared.
3 is usempi, so $CC becomes the MPI wrapper and mpi.h is on the
include path. The alternative is patching the Makefile to use $(MPICC),
which is more honest and more work.
4 is optarch, and it is the one that is not really a toolchain
question. Setting optarch: False for this package would fix the symptom
by making the binary slower everywhere, to accommodate a node it was
never built for. The real answer is the site’s: either build per
architecture, as What “installed” means describes, or set a site-wide --optarch
baseline that every node can run. A per-easyconfig fix for a site-wide
hardware fact is the wrong layer.