Against Default Modules

Environment Modules allow users to dynamically modify the $PATHs in their shell environment. In particular, it provides the ability to switch between different software applications and versions. It is a very handy tool for developers who want to test against multiple versions or compilation options of an application and for users on a multi-user system (e.g., high performance computing) where both consistency and the opportunity to introduce newer features needs to exist for different research groups. The two major environment modules systems are the older, Tcl-based system, and the newer Lua-based system (Lmod). Both allow default versions of a software application to be set as in the $PATH when invoked. This can cause problems and should be disabled.

With a standard module system, one can see the modules for an application. For example, using a LMod system:


$ module av GCC/
------------------------------------ /apps/easybuild-2022/easybuild/modules/all/Core ----------------------------
GCC/11.3.0 (L) GCC/12.3.0 GCC/13.3.0 (D)

This illustrates that from the GNU Compiler suite (GCC), the application GCC/11.3.0 is loaded (by default in this case as part of the login) and that GCC/11.3.0 is the default as part of a wider toolchain. That is, if the command

module load GCC

is invoked, the existing environment $PATH will change so that it points to the binary, libraries, etc for GCC/12.3.0 instead of GCC/11.3.0. In the older, Tcl-based modules system, it was possible to have both versions loaded simultaneously; the most recent version would be the initial search path, but if a particular library, for example, couldn't be found, it would search whatever was in the $PATH. That could be an interesting issue for the replication of results.

Having a default obviously saves a few keystrokes, but problems can result. The major issue is that when new software is introduced by the local friendly HPC engineers, then the default changes. For example, the latest version of GCC, at the time of writing, is 15.1 (April 2025). If that was installed on a system, one would witness:


$ module av GCC/
------------------------------------ /apps/easybuild-2022/easybuild/modules/all/Core ----------------------------
GCC/11.3.0 (L) GCC/12.3.0 GCC/13.3.0 GCC/15.1.0 (D)

Instead of loading GCC/12.3.0 from the

module load GCC

command, LMod will add GCC/15.1.0 to the $PATH. Is this a problem? Most certainly because when software (version, compiler) changes, the results can change. For example, with the release of GCC/13 it included the statement: -Ofast, -ffast-math and -funsafe-math-optimizations will no longer add startup code to alter the floating-point environment when producing a shared object with -shared. In a nutshell, this means that one can get different numerical results by compiling the same code between GCC/12 and GCC/13 due to different ways the compiler would handle rounding, precision, and exceptions when using floating-point calculations. This could be very interesting if one cares about that supposed hallmark of science, "reproducibility".

To avoid this, at a user-level, one should always use the fully-qualified version of a software application. For example, instead of loading a module with

module load GCC

, whether in an interactive session or job script, one should use the specific version, e.g.,

module load GCC/13.3.0

. Of course, sometimes users don't follow the friendly and sensible advice from their system engineers, and that's where a blunter tool needs to be invoked.

Site-wide LMod configuration (at let's face it, LMod is the overwhelmingly dominant version of environment modules these days) occurs in the lmod_config.lua file,

$LMOD_DIR/../init/lmod_config.lua

. Adding the following lines is sufficient:


-- Do not automatically pick a version when multiple options are available
always_load_default = false
-- Do not automatically swap modules from the same family
auto_swap = false
-- Disallow default-version resolution and force the user to specify which version
site_defaults = {
load_default = false,
}

Another option is to export optins in

/etc/profile.d/lmod.sh

or equivalent. This avoids making changes to the lmod_config file.


export LMOD_DISABLE_NAME_AUTOSWAP=yes
export LMOD_DISABLE_VERSION_AUTODEFAULT=yes

If a system is using EasyBuild for software installs (and many of us are), EasyBuild will create

.version

files which include the default; this can be removed by changing the

easybuild.cfg

file to have

module_install_defaults = False

.

One issue that arises from the above, from a support perspective, is that existing user expectations and job submission scripts may come into conflict with a new policy. For example, if a job submission script included

module load GCC

, the job would fail as LMod would be asking for user input on which specific version of GCC they wish to load.

This is a valid concern in the short term, but in the longer term, the benefits of providing consistent environment variables, reproducibility, and educating users far outweigh the costs. Further, the longer one persists with the policy of allowing application defaults the greater the damage.