What a module exports

Questions

  • What does a generated modulefile actually export?

  • Which variables are always set, and how are they spelled?

  • What is the citable name of an installed package?

What you will be able to do

  1. Read a generated modulefile and say where each line came from.

  2. Name the variables EasyBuild always sets, and use one from an easyconfig.

  3. Say what a module naming scheme changes, and what a hierarchical one does to MODULEPATH.

The citable unit consists of name, version, toolchain, and versionsuffix, not the easyconfig filename nor EasyBuild. FORCE11 software citation requires the specific version that was executed. What “installed” means stated that the modulefile is the only artifact a user encounters, and then did not open one. An example is provided.

A real modulefile

QMCPACK 4.4.0, abridged

$ sed -n '1,34p' \
>  .../modulefiles/chem/QMCPACK/4.4.0-foss-2025a.lua
help([==[

Description
===========
QMCPACK is an open-source quantum Monte Carlo simulation code.

More information
================
 - Homepage: https://qmcpack.org
]==])

whatis([==[Description: QMCPACK is an open-source quantum Monte ...]==])
whatis([==[Homepage: https://qmcpack.org]==])
whatis([==[URL: https://qmcpack.org]==])

local root = ".../software/QMCPACK/4.4.0-foss-2025a"

conflict("QMCPACK")

depends_on("foss/2025a")
depends_on("Boost/1.88.0-GCC-14.2.0")
depends_on("HDF5/1.14.6-gompi-2025a")
depends_on("Python/3.13.1-GCCcore-14.2.0")
depends_on("libxml2/2.13.4-GCCcore-14.2.0")

prepend_path("CMAKE_PREFIX_PATH", root)
prepend_path("LD_LIBRARY_PATH", pathJoin(root, "lib"))
prepend_path("LIBRARY_PATH", pathJoin(root, "lib"))
prepend_path("PATH", pathJoin(root, "bin"))

Recorded: SURF Snellius, generated modulefile, 2026-09-10, EasyBuild 5.3.1

Nobody wrote that file. Every line came from somewhere in the easyconfig, and being able to point at the source of each is most of what this chapter is for. help and whatis come from description and homepage, which is why those parameters exist and why a one-line description is worth writing properly: it is what a user sees from module whatis. conflict("QMCPACK") comes from the name. Two versions of the same software cannot be loaded at once, and the module says so rather than letting a user discover it through a strange failure. Smith et al. [2016] require a citation to name the specific version and the platform variant. The module’s full name is that variant: software, version, toolchain, versionsuffix. A paper that writes “GROMACS” has not cited a module. depends_on is the dependencies list from Build dependencies are not dependencies, resolved to specific modules by the robot. Note it is depends_on and not load: Lmod counts references, so unloading QMCPACK unloads HDF5 only if nothing else still depends on it. The prepend_path lines are the standard set, added. No parameter asked for them.

The variables EasyBuild always sets

These entries are not shown in the excerpt above.

Variable

Contents

$EBROOTQMCPACK

the install directory

$EBVERSIONQMCPACK

the version

$EBDEVELQMCPACK

a path to the development-support file

convert_name converts characters to uppercase, translates - to min, + to plus, and removes periods. code-server is transformed into EBROOTCODEMINSERVER. netcdf-c is transformed into EBROOTNETCDFMINC rather than EBROOTNETCDFC. The min convention follows the easyblock filename pattern instead of merely stripping punctuation. The name entered by the user is constructed at this point. Modifying the toolchain or the suffix causes the module name and the .eb filename to change correspondingly.

name = 'QMCPACK'
version = '4.4.0'
toolchain = {'name': 'foss', 'version': '2025a'}
versionsuffix = '-HDF5-1.14.6'

$EBROOT* is used by a recipe. It shows how an easyconfig points at a dependency without hardcoding a path, as described in How a build executes’s --with-hdf5=$EBROOTHDF5. The dependency’s module was loaded during prepare, so the variable is set, and the build never needs to know where the site puts things.

Adding to the module

Four parameters are listed in approximate order of frequency of use. modextravars defines additional environment variables. A package whose runtime requires FOO_DATA_DIR located within its own installation receives it via this parameter. modextrapaths inserts a prefix into a path-like variable. This mechanism allows a Python package to add its own lib/python3.13/site-packages to $PYTHONPATH and an R package to extend $R_LIBS_SITE. modluafooter appends raw Lua code to the modulefile, and modtclfooter performs the same for Tcl. It provides an escape hatch for situations not covered by the other parameters. Use it with the understanding that it binds the easyconfig to a specific module syntax. modaltsoftname alters the filename under which the module is stored while preserving the software’s original name. It is uncommon and exists. A rule for all four parameters is that they affect what a user receives, not what the build receives. Setting modextravars does not assist a build that requires an environment variable, since the module is generated in the module step after the build has completed several steps earlier.

Naming schemes

The path in that transcript is modulefiles/chem/QMCPACK/4.4.0-foss-2025a.lua, and the chem comes from moduleclass. That is a categorised scheme, and it is one of several.

Flat, EasyBuild’s default, EasyBuildMNS: every module in one directory, named name/version-toolchain-versionsuffix. Everything is visible in module avail at once. Simple, and long lists.

Categorised: the same names, filed under moduleclass. What Snellius uses above.

Hierarchical, HierarchicalMNS: the toolchain moves out of the module name and into the path. Loading a compiler changes MODULEPATH, and only then are the modules built with it visible.

The hierarchical scheme is worth understanding even if a site does not use it. A module that cannot be seen is not absent; it is behind a toolchain that has not been loaded. That is A toolchain is a hierarchy’s hierarchy made into directories, with the advantage that the module system enforces it and the cost that discovery becomes a two-step process users find baffling until somebody explains it once.

--module-naming-scheme sets it, and it is a site decision made once. Changing it later renames every module a site has, so it is not a decision anyone revisits casually.

EB-Module-1 — Where did that line come from

Using the modulefile above:

  1. A user runs module whatis QMCPACK/4.4.0-foss-2025a and gets one line. Which easyconfig parameter produced it?

  2. They then run module unload QMCPACK and find HDF5 still loaded. Is that a bug?

  3. Your package installs data files in share/mydata and its binary needs $MYPKG_DATA to find them. Which parameter, and what is the wrong way to do it?

  4. A colleague adds modextravars = {'CC': 'mpicc'} so builds against the module pick up MPI. Why will that not do what they expect?

Solution

1 is description, via whatis. Which is the argument for writing a description that reads as a sentence: it is the one line most users ever see about your package.

2 is not a bug. depends_on is reference-counted, so HDF5 stays loaded while anything else still depends on it. If nothing does and it stays, that is worth investigating; if something does, Lmod is doing its job.

3 is modextravars = {'MYPKG_DATA': '%(installdir)s/share/mydata'}. The wrong way is modluafooter with a hand-written setenv, which works and ties the easyconfig to Lua, so it breaks for a site using Tcl modules.

4 will set $CC for a user who loads the module, and will do nothing for a build. A build’s environment is constructed in prepare, as What a build is allowed to see describes, and its $CC comes from the toolchain object rather than from any module. Those builds need toolchainopts = {'usempi': True} in the consuming easyconfig, which is What a toolchain injects.