eb-local¶
Build your own code and install software on top of EESSI (the European Environment for Scientific Software Installations) 2026.06, without knowing EasyBuild’s RPATH wrappers, buildenv or LD_LIBRARY_PATH.
Documentation: https://stackhands.github.io/eb-local/
Compile your own code¶
eval "$(eb-local dev FFTW/3.3.10-GCC-15.2.0)"
gcc -O2 -fopenmp prog.c -lfftw3 -o prog
./prog # runs in a new shell or a job, with no modules loaded
eb-local dev loads EESSI, the modules you name, and a build environment last, so gcc, mpicc, make, CMake and meson record where each library lives.
The program then runs without LD_LIBRARY_PATH; do not set it, because it can mix the host’s libraries into EESSI’s.
Load the modules you link against on the dev line, not after it.
These were checked on Snellius with EESSI 2026.06, each program then run with no modules at all:
task |
the line before building |
|---|---|
C with FFTW and OpenMP |
|
MPI |
|
CMake against GSL |
|
a Python venv, with packages that compile C |
|
R packages into your own library |
|
Load EESSI on the node type that will run the program: it picks the binaries for the CPU it finds when it loads.
Install software with EasyBuild¶
Build inside a Slurm allocation on the node type that will run the software, because EasyBuild targets the CPU of the node it runs on:
salloc -p <partition> -n 16 -t 02:00:00 # on nodes with a node-local disk
eb-local GSL-2.8-GCC-15.2.0.eb --robot
To use what you installed in a new shell or job:
eval "$(eb-local env)"
module avail
For a group install, the project owner creates the directory once with the project group and the setgid bit:
mkdir -p /path/to/project/eessi && chgrp myproj /path/to/project/eessi && chmod 2770 /path/to/project/eessi
eb-local --project /path/to/project/eessi GSL-2.8-GCC-15.2.0.eb --robot
A successful build removes its workspace; a failed one keeps it for inspection until the allocation ends.
Where things go¶
what |
where |
|---|---|
installs |
|
build, temporary, cache and EESSI setup directories |
a unique workspace in the allocation’s node-local mount |
downloaded source archives |
|
build logs |
|
A build needs a Slurm allocation whose node-local directory is its own mount, of the configured file system type, owned by you. Shared parallel-file-system paths, tmpfs, enclosing mounts and symbolic-link aliases are refused before anything is created.
Clean up¶
eb-local clean --dry-run # what would go
eb-local clean # logs older than 30 days, to the trash with rtrash
eb-local clean --sources # downloaded archives too
eb-local clean --workspaces --no-logs # inside an allocation: its leftover workspaces
With rtrash on PATH, files go to the trash (rtrash list, rtrash restore); without it, nothing is deleted unless you pass --delete.
clean never follows a symbolic link out of the installation directory.
To remove something you installed, for every CPU target you built it for:
eb-local uninstall pigz/2.8-GCCcore-15.2.0 --dry-run
eb-local uninstall pigz/2.8-GCCcore-15.2.0 # to the trash with rtrash, or --delete
EasyBuild leaves installations read-only, so rm -rf fails on them; uninstall makes them writable first, and removes the module files with them.
Configuration¶
Settings come from, lowest first: built-in defaults, the site file, a site profile, your file, your profile, EB_LOCAL_* variables, options.
eb-local config prints every setting and where it came from; eb-local profiles lists the profiles.
# ~/.config/eb-local/config.toml
default_profile = "mine"
[profile.mine]
dev.modules = ["FFTW/3.3.10-GCC-15.2.0"]
[profile.group]
project = "/projects/0/myproj/eessi"
[profile.gpu]
dev.modules = ["CUDA/13.3.0"]
eb-local --profile gpu dev or EB_LOCAL_PROFILE=gpu selects a profile.
The keys are prefix, project, stack.module, stack.extend, dev.buildenv, dev.modules, build.allocation_hint, clean.trash (auto, rtrash or none), clean.logs_older_than_days and [secrets]; the variables are EB_LOCAL_PREFIX, EB_LOCAL_PROJECT, EB_LOCAL_STACK_MODULE, EB_LOCAL_STACK_EXTEND, EB_LOCAL_DEV_BUILDENV, EB_LOCAL_DEV_MODULES, EB_LOCAL_BUILD_ALLOCATION_HINT, EB_LOCAL_CLEAN_TRASH and EB_LOCAL_CLEAN_LOGS_OLDER_THAN_DAYS.
An unknown key, a wrong type, a duplicate key or an unsafe module name is an error naming its file and line, in every profile, selected or not.
The site file (/etc/eb-local/config.toml, or config.toml beside the program) also holds the storage settings, which only it may set:
[storage]
node_local_root = "/scratch-node" # allocation mounts are <root>/<user>.<job id>
node_local_fstype = "xfs"
shared_scratch = ["/scratch-shared", "/gpfs/scratch1"]
[build]
allocation_hint = "salloc -p rome -n 16 -t 02:00:00 --constraint=scratch-node"
A configuration file is used only when it is a regular file, not a symbolic link, not writable by group or others, and owned by root, the program’s owner or you (a site file) or by you (your file); otherwise eb-local stops.
A 1.x eb-local.conf is read as before.
Secrets¶
A build that needs a credential, such as a licence server or a token for a private source mirror, names where it comes from; the value is never written in a configuration file:
[secrets]
LM_LICENSE_FILE = "nimvault:licences/flexlm" # nimvault get licences/flexlm
SOURCE_TOKEN = "file:~/.secrets/source-token" # your file, mode 600
MIRROR_PASSWORD = "env:MY_MIRROR_PASSWORD"
Values are read only for a build, after every other check, and go only into the environment of
eband what it runs.eb-local config --checkreads each secret and reportsokor why not, never the value.After the build, the logs written during it (in
.eb-local/logsand each installation’seasybuild/) have each value, and its base64 and percent-encoded forms, replaced with<secret NAME removed by eb-local>; the log directory is private meanwhile. A value shorter than 4 bytes, or a log that is too large or too deep to check, is reported instead. A secret reaches every program the build runs, and a build killed before it ends leaves its logs unchecked.A secret cannot set
PATH,LD_*,EESSI_*,EASYBUILD_*or another variable the build depends on.nimvault runs with a 30-second deadline; on failure eb-local shows its error output, never what it printed as the value.
Install¶
The static binary, one file per architecture, from a release, or zig build --release=safe with Zig 0.17.1.
The Bash script (eb-local, 1.x) needs GNU coreutils, util-linux findmnt, Lmod and an EESSI 2026.06 mount, and has no configuration files, profiles or secrets.
A site’s easyconfig installs the program and its site configuration.
Test¶
python3 -m unittest discover -s tests # the Bash script
zig build unit && zig build -Dtest-ops=true test # the Zig build: unit tests, then the same suite
tests/site/ holds the acceptance scripts run on Snellius: the development tasks above, and a build inside an allocation.
License¶
MIT, see LICENSE.