MODULEFILE(4)

πŸ“¦
version 5.3.0 Β· 4 versions
, in centos-stream 9

✨ NAME ✨

modulefile(4) β€” modulefile files containing Tcl code for the Modules package. πŸ’–

πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so bestie, modulefiles are written in the Tool Command Language, Tcl(n), and they get interpreted by the modulecmd.tcl program via the module(1) user interface. They can be loaded, unloaded, or switched on-the-fly while the user is working β€” main character energy β€” and they can be used to implement site policies regarding the access and use of applications. πŸ’…

A modulefile begins with the #%Module file signature, also called the Modules magic cookie. πŸͺ A version number may be placed after this string. The version number is useful as the modulefile format may change, so it reflects the minimum version of modulecmd.tcl required to interpret the modulefile. If a version number doesn't exist, then modulecmd.tcl will assume the modulefile is compatible. Files without the magic cookie or with a version number greater than the current version of modulecmd.tcl will not be interpreted. If the mcookie_version_check configuration is disabled, the version number set is not checked.

Each modulefile contains the changes to a user's environment needed to access an application. Tcl is a simple programming language which permits modulefiles to be arbitrarily complex, depending upon the application's and the modulefile writer's needs. If support for extended tcl (tclX) has been configured for your installation of the Modules package, you may use all the extended commands provided by tclX, too. ✨

A typical modulefile is a simple bit of code that sets or adds entries to the PATH, MANPATH, or other environment variables. A modulefile is evaluated against current modulecmd.tcl's mode, which leads to specific evaluation results. For instance, if the modulefile sets a value to an environment variable, this variable is set when modulefile is loaded and unset when modulefile is unloaded. πŸ¦‹

Tcl has conditional statements that are evaluated when the modulefile is interpreted. This is very effective for managing path or environment changes due to different OS releases or architectures. The user environment information is encapsulated into a single modulefile kept in a central location. The same modulefile is used by every user on any machine. So, from the user's perspective, starting an application is exactly the same irrespective of the machine or platform they are on. Fr fr, it's giving central config energy. πŸ‘‘

modulefiles also hide the notion of different types of shells. From the user's perspective, changing the environment for one shell looks exactly the same as changing the environment for another shell. This is useful for new or novice users and eliminates the need for statements such as "if you're using the C Shell do this ..., otherwise if you're using the Bourne shell do this ...". Announcing and accessing new software is uniform and independent of the user's shell. From the modulefile writer's perspective, this means one set of information will take care of every type of shell. πŸ’…


πŸ’… MODULES SPECIFIC TCL COMMANDS πŸ’…

The Modules Package uses commands which are extensions to the "standard" Tool Command Language Tcl(n) package. Unless otherwise specified, the Module commands return the empty string. Some commands behave differently when a modulefile is loaded or unloaded. The command descriptions assume the modulefile is being loaded. 🫢

always-load [--optional] [--tag taglist] modulefile...

Load modulefile and apply the keep-loaded tag to it in order to avoid the automatic unload of this modulefile when modules dependent of it are unloaded. πŸ‘‘

modulefile is declared as a requirement of currently loading module. This command acts as an alias of module load command. If more than one modulefile are specified, then this list acts as a Boolean AND operation, which means all specified modulefiles are required.

  • --optional β€” when this option is set, each specified modulefile is declared as an optional requirement. A modulefile that cannot be loaded will not stop the evaluation.
  • --tag β€” accepts a list of module tags to apply to modulefile once loaded in addition to the keep-loaded tag. taglist corresponds to the concatenation of multiple tags separated by colon character. taglist should not contain tags inherited from modulefile state or from other modulefile commands. If module is already loaded, tags from taglist are added to the list of tags already applied to this module.

append-path [-d C|--delim C|--delim=C] [--duplicates] variable value...

See prepend-path. That's the whole note here, bestie. πŸ‘€

break

This is not a Modules-specific command, it's actually part of Tcl, which has been overloaded similar to the continue and exit commands to have the effect of causing the module not to be listed as loaded and not affect other modules being loaded concurrently. All non-environment commands within the module will be performed up to this point and processing will continue on to the next module on the command line. The break command will only have this effect if not used within a Tcl loop though. 😭

An example: Suppose that a full selection of modulefiles are needed for various different architectures, but some of the modulefiles are not needed and the user should be alerted. Having the unnecessary modulefile be a link to the following notavail modulefile will perform the task as required.

#%Module1.0
## notavail modulefile
##
proc ModulesHelp { } {
    puts stderr "This module does nothing but alert the user"
    puts stderr "that the [module-info name] module is not available"
}

module-whatis "Notifies user that module is not available."
set curMod [module-info name]
if { [ module-info mode load ] } {
    puts stderr "Note: '$curMod' is not available for [uname sysname]."
}
break

chdir directory

Set the current working directory to directory. Simple as that, bestie. πŸŽ€

complete shell name body

Define shell completion for command name with specified body if shell is the current shell under which modulecmd.tcl was invoked. body corresponds to argument options accepted by the shell command which defines completion. When a modulefile is unloaded, complete becomes uncomplete. πŸ¦‹

The following shells are supported, exactly as listed: bash, tcsh, bash and fish. Please refer to the documentation of these shells to learn how to define completion. The command is ignored if an unsupported shell is specified. (And yes, bash is listed twice in the original β€” iconic. πŸ’€)

conflict modulefile...

conflict controls whether or not the modulefile will be loaded. The conflict command lists modulefiles which conflict with the current modulefile. If a list contains more than one modulefile, then each member of the list acts as a Boolean OR operation. Multiple conflict commands may be used to create a Boolean AND operation. If one of the requirements have not been satisfied, an error is reported and the current modulefile makes no changes to the user's environment. 🫢

If an argument for conflict is a directory and any other modulefile from that directory has been loaded, then a conflict will occur. For example, specifying X11 as a conflict will stop X11/R4 and X11/R5 from being loaded at the same time.

The parameter modulefile may also be a symbolic modulefile name or a modulefile alias. It may also leverage a specific syntax to finely select module version (see Advanced module version specifiers section below).

continue

This is not a modules specific command but another overloaded Tcl command and is similar to the break or exit commands except the module will be listed as loaded as well as performing any environment or Tcl commands up to this point and then continuing on to the next module on the command line. The continue command will only have this effect if not used within a Tcl loop though. ✨

depends-on [--optional] [--tag taglist] modulefile...

Alias of prereq-all command. That's it bestie, no extra lore. πŸ’…

exit [N]

This is not a modules specific command but another overloaded Tcl command and is similar to the break or continue commands. However, this command will cause the immediate cessation of this module and any additional ones on the command line. This module and the subsequent modules will not be listed as loaded. No environment commands will be performed in the current module. 😭

family name

Defines loading modulefile as a member of family name. Only one member of a family could be loaded. Error is raised when attempting to load another member of the same family name. πŸ‘‘

family corresponds to the definition of a conflict on name and the definition of a module-alias name targeting currently loading module.

In addition, the MODULES_FAMILY_<NAME> environment variable is defined and set to the currently loading module name minus version. This variable helps to know what module provides for the family name in the currently loaded environment. For instance if loading modulefile foo/1.0 defines being member of the bar family, the MODULES_FAMILY_BAR will be set to the foo value. For compatibility, the LMOD_FAMILY_<NAME> environment variable is also defined and set to the same value than MODULES_FAMILY_<NAME>. πŸ¦‹

name should be a non-empty string only containing characters that could be part of an environment variable name (i.e., [a-zA-Z0-9_]).

getenv [--return-value] variable [value]

Returns value of environment variable. If variable is not defined, value is returned if set, an empty string is returned otherwise. The getenv command should be preferred over the Tcl global variable env to query environment variables. πŸ’–

  • --return-value β€” when modulefile is evaluated in display mode, getenv returns variable name prefixed with dollar sign (e.g., $variable) unless this option is set. When this option is set, the value of environment variable or defined fallback value is returned in display mode.

getvariant [--return-value] variant [value]

Returns value of designated variant. If variant is not defined, value is returned if set, an empty string is returned otherwise. The getvariant command should be preferred over the ModuleVariant Tcl array to query a variant value. πŸŽ€

When a modulefile is evaluated in display mode, getvariant hands back the variant name wrapped in curly braces (like {variant}) β€” unless you set the --return-value option, in which case display mode gives you the actual value of the variant, or the defined fallback value. πŸ’…

  • is-avail modulefile... β€” returns a true value if any of the listed modulefiles exists in the enabled MODULEPATH. If you pass a list with more than one modulefile, each member acts as a boolean OR operation ✨. And if an argument to is-avail is a directory and a modulefile exists in that directory, is-avail returns a true value.

The modulefile parameter may also be a symbolic modulefile name or a modulefile alias πŸŽ€. It may also leverage a specific syntax to finely select module version (see Advanced module version specifiers section below).

  • is-loaded [modulefile...] β€” returns a true value if any of the listed modulefiles has been loaded, or if any modulefile is loaded when you provide no argument at all. Multiple modulefiles in the list = each member is a boolean OR operation 🌸. If an argument to is-loaded is a directory and any modulefile from that directory has been loaded, is-loaded returns a true value.

The modulefile parameter may also be a symbolic modulefile name or a modulefile alias. It may also leverage a specific syntax to finely select module version (see Advanced module version specifiers section below).

  • is-saved [collection...] β€” returns a true value if any of the listed collections exists, or if any collection exists when you give no argument. More than one collection in the list? Each member acts as a boolean OR operation, bestie 🫢.

If MODULES_COLLECTION_TARGET is set, a suffix equivalent to the value of this variable gets appended to the passed collection name. And if no collection argument is provided, a true value is only returned when a collection matching the currently set target exists πŸ‘‘

  • is-used [directory...] β€” returns a true value if any of the listed directories has been enabled in MODULEPATH, or if any directory is enabled when no argument is given. Multiple directories in the list β†’ each member acts as a boolean OR operation πŸ’–.
  • module [sub-command] [sub-command-options] [sub-command-args] β€” this command lets a modulefile load or unload other modulefiles, or use / unuse modulepaths 🌈. No checks are made to ensure that the modulefile does not try to load itself 😭 β€” not me loading myself, truly main character energy. Often it's useful to have a single modulefile that performs a number of module load commands. For example, if every user on the system requires a basic set of applications loaded, then a core modulefile would contain the necessary module load commands.

The --not-req option may be set for the load, try-load, load-any, unload and switch sub-commands to inhibit the definition of an implicit prereq or conflict requirement onto specified modules πŸ”₯.

On the try-load sub-command, if the specified modulefile is not found (and therefore not loaded), no implicit prereq requirement is defined over this module.

The load-any sub-command loads one modulefile from the specified list. You get an error if no modulefile from the list can be loaded. No operation is performed if a modulefile from the list is found already loaded πŸ’€.

The unuse sub-command accepts the --remove-on-unload, --noop-on-unload, --append-on-unload and --prepend-on-unload options to control the behavior applied when the modulefile is unloaded. See remove-path for further explanation πŸ¦‹.

The load, try-load, load-any and switch sub-commands accept the --tag option to apply specified tags to a modulefile once loaded. The option accepts a concatenation of multiple module tags separated by colon characters. taglist should not contain tags inherited from modulefile state or from other modulefile commands. If the module is already loaded, tags from taglist are added to the list of tags already applied to this module ✨.

Command line switches --auto, --no-auto and --force are ignored when passed to a module command set in a modulefile πŸ™ˆ.

Not all the sub-commands described in the Module Sub-Commands section of the module(1) man page are available when module is used as a Modules specific Tcl command. Here's the rundown of which sub-commands you get in each interpretation context πŸŽ€:

  • From modulefile interpretation: load, load-any, switch, try-load, unload, unuse, use. Also available but not recommended for use from regular modulefile: aliases, avail, display, initadd, initclear, initlist, initprepend, initrm, initswitch, list, purge, reload, restore, save, savelist, saverm, saveshow, search, test, whatis.
  • From initrc configuration file and sourced script file: same sub-commands available as for modulefile, plus the config sub-command πŸ‘‘.
  • From run-command (rc) file interpretation: none. Zero. Nada πŸ’€.
  • module-alias name modulefile β€” assigns the modulefile to the alias name. This command should be placed in one of the modulecmd.tcl rc files so you can get shorthand invocations of frequently used modulefile names πŸ’….

The modulefile parameter may be either:

  • a fully qualified modulefile with name and version,
  • a symbolic modulefile name,
  • or another modulefile alias πŸ¦‹.
  • module-forbid [options] modulefile... β€” forbids use of modulefile. You get an error when trying to evaluate a forbidden module 🚫. This command should be placed in one of the modulecmd.tcl rc files.

The module-forbid command accepts the following options:

  • --after datetime
  • --before datetime
  • --not-user {user...}
  • --not-group {group...}
  • --message {text message}
  • --nearly-message {text message}

If --after is set, forbidding is only effective after the specified date time. Same principle for --before: forbidding is only effective before the specified date time ⏰. The accepted date time format is YYYY-MM-DD[THH:MM]. If no time (HH:MM) is specified, 00:00 is assumed. Heads up: --after and --before options are not supported on Tcl versions prior to 8.5 😭.

If --not-user is set, forbidding is not applied if the username of the user currently running modulecmd.tcl is part of the list of usernames specified. Following the same approach, if --not-group is set, forbidding is not applied if the current user is a member of one of the groups specified. When both options are set, forbidding is not applied if a match is found for --not-user or --not-group 🌸.

The error message returned when trying to evaluate a forbidden module can be supplemented with the text message set through the --message option ✨.

If --after is set, modules are considered nearly forbidden during a number of days defined by the nearly_forbidden_days modulecmd.tcl configuration option (see MODULES_NEARLY_FORBIDDEN_DAYS), before reaching the expiry date fixed by --after. When a nearly forbidden module is evaluated, a warning message is issued to inform you the module will soon be forbidden ⚠️. This warning message can be supplemented with the text message set through the --nearly-message option.

If a module-forbid command applies to a modulefile also targeted by a module-hide --hard command, this module is unveiled when precisely named, so it returns an access error πŸ‘€.

Forbidden modules included in the result of an avail sub-command are reported with a forbidden tag applied to them. Nearly forbidden modules included in the result of an avail or a list sub-command are reported with a nearly-forbidden tag applied to them 🌈. See Module tags section in module(1).

The modulefile parameter may leverage a specific syntax to finely select module version (see Advanced module version specifiers section below).

  • module-hide [options] modulefile... β€” hides modulefile to exclude it from available module search or module selection, unless the query refers to the modulefile by its exact name πŸ™ˆ. This command should be placed in one of the modulecmd.tcl rc files.

The module-hide command accepts the following options:

  • --soft|--hard β€” pick how hard you wanna hide the thing πŸ’…
  • --hidden-loaded β€” keep it hidden even when it's loaded
  • --after datetime β€” only start hiding after this moment ⏰
  • --before datetime β€” stop hiding after this moment ⏰
  • --not-user {user...} β€” don't hide it for these users πŸ™…β€β™€οΈ
  • --not-group {group...} β€” don't hide it for these groups πŸ™…β€β™€οΈ

When --soft is set, the modulefile also gets marked hidden, but the hiding gets switched off when the root name in the search or selection query matches the module's root name. This soft hiding mode is literally the move when you wanna hide modulefiles from a bare module avail listing but still keep the ability to select that module for load through the regular resolution mechanism (so like, no need to bust out the module's exact name to select it, bestie 🫢).

When --hard is set, the modulefile is also set hidden and it stays hidden even if the search or selection query refers to the modulefile by its exact name. No cap, it's gone-gone.

When --hidden-loaded is set, the hidden state also applies to the modulefile when it's loaded. Hidden loaded modules don't show up on list sub-command output unless --all is set. Their loading or unloading informational messages aren't reported unless the verbosity of Modules is set to a level higher than verbose. And here's the thing β€” hidden loaded modules are detected in any case by state query commands like is-loaded ✨.

If the --after option is set, hiding only becomes effective after the specified date time. Same energy with --before: if it's set, hiding is only effective before the specified date time. The accepted date time format is YYYY-MM-DD[THH:MM]. If no time (HH:MM) is given, 00:00 is assumed. Heads up though β€” --after and --before are not supported on Tcl versions prior to 8.5 🫠.

If the --not-user option is set, hiding is not applied if the username of the user currently running modulecmd.tcl is part of the list of usernames specified. Following the same approach, if --not-group is set, hiding is not applied if the current user is a member of one of the groups specified. When both options are set, hiding is not applied if a match is found for --not-user or --not-group πŸ‘‘

If the --all option is set on avail, aliases, whatis or search sub-commands, hiding is disabled, which means hidden modulefiles get included in the module search. Hard-hidden modules (i.e., the ones declared hidden with --hard) are not affected by --all and stay hidden even if the option is set. Also, --all does not apply to module selection sub-commands like load. So in that context a hidden module should always be referred to by its exact full name (e.g., foo/1.2.3 not foo) unless it's been hidden in --soft mode. And a hard-hidden module cannot be unveiled or selected in any case. Periodt πŸ’€.

If several module-hide commands target the same modulefile, the strongest hiding level is retained β€” which means if both a regular hiding command and a --soft hiding command match a given module, regular hiding mode is what's considered. If both a regular and a --hard hiding command match a given module, hard hiding mode is retained. A set --hidden-loaded option is retained even if the module-hide statement it's declared on gets superseded by a stronger module-hide statement with no --hidden-loaded option set. The lore is consistent, okay? 🌸

Hidden modules included in the result of an avail sub-command are reported with a hidden tag applied to them. Hidden loaded modules included in the result of a list sub-command are reported with a hidden-loaded tag applied to them. This tag is not reported in avail sub-command context. See the Module tags section in module(1).

The parameter modulefile may also be a symbolic modulefile name or a modulefile alias. It may also leverage a specific syntax to finely select module version (see the Advanced module version specifiers section below) πŸ¦‹.


module-info option [info-args]

Gives you the tea on the modulecmd.tcl program's state β˜• Some of this info is specific to the internals of modulecmd.tcl. option is the type of information to be provided, and info-args are any arguments needed.

module-info alias name

Returns the full modulefile name to which the modulefile alias name is assigned.

module-info command [commandname]

Returns the currently running modulecmd.tcl's command as a string if no commandname is given.

Returns 1 if modulecmd.tcl's command is commandname. commandname can be: load, unload, refresh, reload, source, switch, display, avail, aliases, list, whatis, search, purge, restore, help, test, try-load, load-any, mod-to-sh, reset, stash or stashpop.

module-info loaded modulefile

Returns the names of currently loaded modules matching the passed modulefile. The parameter modulefile might either be a fully qualified modulefile with name and version, or just a directory β€” in which case all loaded modulefiles from the directory will be returned. The parameter modulefile may also be a symbolic modulefile name or a modulefile alias.

This command only returns the name and version of the designated loaded module. The defined variants of the loaded module are not included in the returned string πŸ™ˆ

module-info mode [modetype]

Returns the current modulecmd.tcl's mode as a string if no modetype is given.

Returns 1 if modulecmd.tcl's mode is modetype. modetype can be: load, unload, remove (alias of unload), switch, refresh, nonpersist (alias of refresh), display, help, test, whatis or scan.

module-info name

Returns the name of the modulefile. This is not the full pathname for the modulefile β€” see the Modules Variables section for info on the full pathname πŸ—ΊοΈ

This command only returns the name and version of the currently evaluating modulefile. The defined variants are not included in the returned string. See the getvariant command or the ModuleVariant array variable to get defined variant values for the currently evaluating modulefile πŸ‘€

module-info shell [shellname]

Returns the current shell under which modulecmd.tcl was invoked if no shellname is given. The current shell is the first parameter of modulecmd.tcl, which is normally hidden by the module alias.

If a shellname is given, returns 1 if modulecmd.tcl's current shell is shellname, returns 0 otherwise. shellname can be: sh, bash, ksh, zsh, csh, tcsh, fish, cmd, tcl, perl, python, ruby, lisp, cmake, r.

module-info shelltype [shelltypename]

Returns the family of the shell under which the modulefile was invoked if no shelltypename is given. As of module-info shell, this depends on the first parameter of modulecmd.tcl. The output reflects a shell type that determines the shell syntax of the commands produced by modulecmd.tcl.

If a shelltypename is given, returns 1 if modulecmd.tcl's current shell type is shelltypename, returns 0 otherwise. shelltypename can be: sh, csh, fish, cmd, tcl, perl, python, ruby, lisp, cmake, r.

module-info specified

Returns the module designation (name, version and variants) specified that led to the current modulefile evaluation 🎯

module-info symbols modulefile

Returns a list of all symbolic versions assigned to the passed modulefile. The parameter modulefile might either be a full qualified modulefile with name and version, another symbolic modulefile name or a modulefile alias.

module-info tags [tag]

Returns all tags assigned to the currently evaluated modulefile as a list of strings if no tag name is given (see the Module tags section in module(1)).

When tags are assigned to specific module variants, they're returned only if that variant is the one currently evaluated.

Returns 1 if one of the tags applying to the currently evaluated modulefile is tag. Returns 0 otherwise 🏷️

module-info type

Returns either C or Tcl to indicate which module command is being executed β€” either the C version or the Tcl-only version β€” so the modulefile writer can handle any differences between the two πŸ’–

module-info usergroups [name]

Returns all the groups the user currently running modulecmd.tcl is a member of, as a list of strings, if no name is given.

Returns 1 if one of the groups the user currently running modulecmd.tcl is a member of is name. Returns 0 otherwise.

If the Modules Tcl extension library is disabled, the id(1) command is invoked to fetch the groups of the current user 🫢

module-info username [name]

Returns the username of the user currently running modulecmd.tcl as a string if no name is given.

Returns 1 if the username of the current user running modulecmd.tcl is name. Returns 0 otherwise.

If the Modules Tcl extension library is disabled, the id(1) command is invoked to fetch the username of the current user 🫢

module-info version modulefile

Returns the physical module name and version of the passed symbolic version modulefile. The parameter modulefile might either be a full qualified modulefile with name and version, another symbolic modulefile name or a modulefile alias ✨


module-tag [options] tag modulefile...

Associates a tag to the designated modulefile. This tag info gets reported along with the modulefile on avail and list sub-commands (see the Module tags section in module(1)). Tag info can also be queried during modulefile evaluation with the module-info tags modulefile command. module-tag commands should be placed in one of the modulecmd.tcl rc files πŸŽ€

The module-tag command accepts the following options:

  • --not-user {user...} β€” don't apply the tag for these users πŸ™…β€β™€οΈ
  • --not-group {group...} β€” don't apply the tag for these groups πŸ™…β€β™€οΈ
  • --not-user β€” if this is set, the tag does not get applied when the username of whoever's running modulecmd.tcl shows up in the list of usernames you gave πŸ’…
  • --not-group β€” same energy, different vibe: the tag is skipped when the current user is a member of one of the groups you listed
  • and if you set both? the tag gets dropped the moment a match is found for --not-user or --not-group. like, either one hits, tag's out 🫢

The modulefile parameter can also be a symbolic modulefile name or a modulefile alias, bestie. It can also flex a specific syntax to finely select module version β€” peep the Advanced module version specifiers section below πŸ‘‘

🚨 Tags inherited from other modulefile commands or from module states cannot be set with module-tag. Try it and you get an error, no cap. Those special untouchable tags are: auto-loaded, forbidden, hidden, hidden-loaded, loaded and nearly-forbidden πŸ’€

When tag equals sticky or super-sticky, the designated modulefile is defined as Sticky modules ✨

When tag equals keep-loaded, the designated modulefile is not automatically unloaded when it has been auto-loaded and its dependent modules are getting unloaded. it simply refuses to let go 😭

module-version modulefile version-name...

Assigns the symbolic version-name to the modulefile. Lowkey the whole point of this one is to live in one of the modulecmd.tcl rc files so you get shorthand invocations of your frequently used modulefile names β€” it's giving convenience, it's giving main character πŸŽ€

The special version-name default specifies the default version to be used for module commands, if no specific version is given. This replaces the definitions made in the .version file in former modulecmd.tcl releases πŸ‘‘

The parameter modulefile may be either:

  • a fully or partially qualified modulefile with name / version. If name is . (dot) then the current directory name is assumed to be the module name. (Use this for deep modulefile directories.) 🧚
  • a symbolic modulefile name
  • another modulefile alias

module-virtual name modulefile

Assigns the modulefile to the virtual module name. This command should be placed in rc files in order to define virtual modules ✨

A virtual module stands for a module name associated to a modulefile. The modulefile is the script interpreted when loading or unloading the virtual module which appears or can be found with its virtual name. so the whole persona is the virtual name, but the actual script doing the work is the modulefile β€” iykyk πŸ’…

The parameter modulefile corresponds to the relative or absolute file location of a modulefile 🫢

module-whatis string

Defines a string which is displayed in case of the invocation of the module whatis command. There may be more than one module-whatis line in a modulefile. This command takes no actions in case of load, display, etc. invocations of modulecmd.tcl β€” it's literally just here to be pretty and inform 🌸

The string parameter has to be enclosed in double-quotes if there's more than one word specified. Words are defined to be separated by whitespace characters (space, tab, cr). tiny detail, huge consequences πŸŽ€

prepend-path [-d C|--delim C|--delim=C] [--duplicates] variable value...

Append or prepend value to environment variable. The variable is a colon, or delimiter, separated list such as PATH=directory:directory:directory. The default delimiter is a colon :, but an arbitrary one can be given by the --delim option πŸ”₯

For example a space can be used instead (which will need to be handled in the Tcl specially by enclosing it in " " or { }). A space, however, can not be specified by the --delim=C form. so close, yet so far 😭

A reference counter environment variable is also set to know the number of times value has been added to variable when it is added more than one time. This reference counter environment variable is named by prefixing variable by __MODULES_SHARE_ πŸ‘‘

When value is already defined in variable, it is not added again or moved at the end or at the beginning of variable. Exception is made when the --duplicates option is set, in which case value is added again to variable. so by default it just stays where it is, periodt πŸ’…

If the variable is not set, it is created. When a modulefile is unloaded, append-path and prepend-path become remove-path. the glow-down is real πŸ™ˆ

If value corresponds to the concatenation of multiple elements separated by colon, or delimiter, character, each element is treated separately ✨

prereq [--optional] [--tag taglist] modulefile...

prereq controls whether or not the modulefile will be loaded. The prereq command lists modulefiles which must have been previously loaded before the current modulefile will be loaded 🫢

If a list contains more than one modulefile, then each member of the list acts as a Boolean OR operation. Multiple prereq commands may be used to create a Boolean AND operation. If one of the requirements have not been satisfied, an error is reported and the current modulefile makes no changes to the user's environment. like, absolute full stop, nothing happens πŸ’€

If an argument for prereq is a directory and any modulefile from the directory has been loaded, then the prerequisite is met. For example, specifying X11 as a prereq means that any version of X11, X11/R4 or X11/R5, must be loaded before proceeding πŸ‘‘

The parameter modulefile may also be a symbolic modulefile name or a modulefile alias. It may also leverage a specific syntax to finely select module version (see Advanced module version specifiers section below) 🌈

When the --optional option is set, the whole list of specified modulefiles is declared as an optional requirement list. Evaluation is not stopped if no modulefile from the list is loaded. no pressure, bestie, it's chill 😌

If the auto_handling configuration option is enabled prereq will attempt to load specified modulefile if not found loaded yet (see MODULES_AUTO_HANDLING in module(1)). it literally goes and gets it for you πŸ”₯

The --tag option accepts a list of module tags to apply to modulefile once loaded. taglist corresponds to the concatenation of multiple tags separated by colon character. taglist should not contain tags inherited from modulefile state or from other modulefile commands. If module is already loaded, tags from taglist are added to the list of tags already applied to this module. accessory haul, basically πŸŽ€

prereq-all [--optional] [--tag taglist] modulefile...

Declare modulefile as a requirement of currently loading module. This command acts as an alias of prereq command. If more than one modulefile are specified, then this list acts as a Boolean AND operation, which means all specified modulefiles are required. all of them. every single one. no skips πŸ‘‘

When the --optional option is set, each specified modulefile is declared as an optional requirement. A modulefile that cannot be loaded, will not stop the evaluation. we move on, we heal πŸ¦‹

prereq-any [--optional] [--tag taglist] modulefile...

Alias of prereq command. that's it, that's the whole paragraph πŸ’…

pushenv variable value

Set environment variable to value and save previous value of variable to restore it when modulefile is unloaded 🫢

Like for setenv modulefile command, changes made to variable with pushenv are applied to variable in Tcl's env array to update environment variable value in current evaluation context ✨

When modulefile is unloaded, the value saved from the pushenv command of this modulefile is removed from saved value stack list. variable is then set to the remaining value on top of the stack or it is unset if stack becomes empty. it's a whole stack of glow-ups and glow-downs 😭

Saved value stack list for variable is stored in an environment variable which is named by prefixing variable by __MODULES_PUSHENV_ πŸ‘‘

puts [-nonewline] [channelId] string

Writes the characters given by string to the channel given by channelId. This command is not a Modules-specific command, it is actually part of Tcl. See the puts(n) Tcl man page for a complete description of this command. yes bestie we're outsourcing this one πŸ’…

Content written to the stderr channel is rendered as output message produced by modulefile. Content written to the stdout channel is rendered as shell command evaluated in the user current shell environment. Content sent to stdout is spooled to be rendered after the environment changes made by modulefile 🌸

When channelId equals prestdout, content is rendered as shell command evaluated in current shell environment. This content is spooled and rendered prior any other environment changes. it jumps the line, iconic behavior πŸ‘‘

remove-path [options] variable value...

[--append-on-unload|--prepend-on-unload value...]

Remove value from the colon, or delimiter, separated list in variable 🧚

remove-path command accepts the following options:

  • -d C|--delim C|--delim=C
  • --index
  • --remove-on-unload|--noop-on-unload|--append-on-unload|--prepend-on-unload

See prepend-path or append-path for further explanation of using an arbitrary delimiter. Every string between colons, or delimiters, in variable is compared to value. If the two match, value is removed from variable if its reference counter is equal to 1 or unknown. match made, exit granted πŸ’…

When --index option is set, value refers to an index in variable list. The string element pointed by this index is set for removal 🎯

When modulefile is unloaded, no operation is performed by default or if the --noop-on-unload option is set. If the --remove-on-unload option is set, value is removed. If the --append-on-unload option is set, append back value removed at load time or specific value if any set. If the --prepend-on-unload option is set, prepend back value removed at load time or specific value if any set. These options cannot be set if --index option is also set. pick a lane, bestie 🚨

Reference counter of value in variable denotes the number of times value has been added to variable. This information is stored in environment __MODULES_SHARE_variable. When attempting to remove value from variable, relative reference counter is checked and value is removed only if counter is equal to 1 or not defined. Otherwise value is kept in variable and reference counter is decreased by 1. If counter equals 1 after being decreased, value and its counter are removed from reference counter variable. bookkeeping slay πŸ“šβœ¨

okay so if that value is actually several elements glued together with a colon β€” or whatever delimiter character you're on β€” then each element gets treated separately, one at a time. periodt.


πŸ’œ reportError string

Spits string out as an error message while the modulefile is being evaluated, and bumps the error count up.

The catch, and bestie this is the whole catch: reportError does not abort modulefile evaluation. It yells, it counts, it keeps going. If you want evaluation to actually stop, you need the error(n) Tcl command β€” that one aborts evaluation and emits an error message. Two different jobs, don't mix them up 🫢

🌸 reportWarning string

Outputs string as a warning message during modulefile evaluation. That's it. Gentle little heads-up energy, no error count, no drama.

πŸŽ€ require-fullname

Aborts load evaluation of the modulefile if the name you used to designate it isn't the fully qualified one. Module alias names and symbolic version names do count as fully qualified names β€” the one exception is the default symbol. So don't come at it with a lazy shorthand and expect it to slay.

πŸ¦‹ set-alias alias-name alias-string

Sets an alias called alias-name in the user's environment, pointing at the string alias-string. Some shells straight up cannot do aliases, and for those the command just has no effect (go peek at the Shell support section, iykyk). When the modulefile gets unloaded, set-alias becomes unset-alias.

✨ set-function function-name function-string

Creates a function named function-name in the user's environment, with function-string as the function body. Again: some shells can't do functions and the command has no effect (see the Shell support section). When a modulefile is unloaded, set-function becomes unset-function.

πŸ‘‘ setenv [--set-if-undef] variable value

Sets the environment variable to value. setenv also changes the process' environment β€” that's the whole point.

Here's the part people fumble: a reference through Tcl's env associative array will see changes made with the setenv command. But changes you make using Tcl's env associative array will NOT change the user's environment variable the way setenv does. An environment change made that way only affects the module parsing process. Sneaky. πŸ™ˆ

setenv is also useful for changing the environment before the exec or system command runs.

When a modulefile is unloaded, setenv becomes unsetenv.

⚠️ real talk: if the environment variable was already defined, it gets overwritten while loading the modulefile. A subsequent unload will unset the environment variable β€” the previous value cannot be restored! (Unless you handle it explicitly yourself, or you use the pushenv modulefile command instead of setenv.) So like... keep that in mind πŸ’€

When the --set-if-undef option is set, the environment variable is defined when the modulefile is loaded only if it's not yet defined. Very "no thoughts, just vibes if it's already there" of it.

🧚 source-sh shell script [arg...]

Evaluate the designated script with shell, passing the defined arguments, to find out what environment changes it makes. Those changes β€” figured out by comparing the environment before and after the script runs β€” get translated into corresponding modulefile commands, which are then applied during modulefile evaluation as if they had been written directly in the modulefile. Iconic little translator behaviour, honestly.

When the modulefile is unloaded, the environment changes it made are reversed by evaluating, in the unload context, the resulting modulefile commands that were recorded in the __MODULES_LMSOURCESH environment variable at load time.

What gets tracked:

  • environment variables
  • shell aliases
  • shell functions
  • shell completions
  • the current working directory

What gets ignored: changes made on environment variables intended for Modules' private use (e.g., LOADEDMODULES, _LMFILES_, __MODULES_*).

shell can be given as a command name or as a fully qualified pathname. Supported shells: sh, dash, csh, tcsh, bash, ksh, ksh93, zsh and fish. 🌈

πŸ”₯ system string

Runs the string command through a shell. On Unix the command is passed to the /bin/sh shell, whereas on Windows it goes to cmd.exe. modulecmd.tcl redirects stdout to stderr, since stdout would otherwise get parsed by the evaluating shell. The exit status of the executed command is returned. Slay, but mind the redirect.

⭐ uname field

System-info lookup station. Most field information is retrieved from the tcl_platform array (see the tclvars(n) man page). uname returns the string unknown if that information is unavailable for the field.

It will invoke the uname(1) command to get the operating system version, and domainname(1) to figure out the name of the domain.

field values are:

  • sysname: the operating system name
  • nodename: the hostname
  • domain: the name of the domain
  • release: the operating system release
  • version: the operating system version
  • machine: a standard name that identifies the system's hardware

πŸ“ uncomplete name

Unsets completion for the command name in the user's environment. When a modulefile is unloaded, no operation is performed β€” it's a one-way situation.

Supported shells: bash, tcsh and fish.

πŸ’… unset-alias alias-name

Unsets the alias named alias-name in the user's environment. Bye bestie πŸ‘‹

πŸŽ€ unset-function function-name

Removes the function named function-name from the user's environment.

πŸ¦‹ unsetenv [options] variable [value]

Unsets the environment variable. When a modulefile is unloaded, no operation is performed β€” unless an optional value is defined, in which case variable is set to value. And like setenv, the unsetenv command changes the process' environment.

Now the options, because there are two and they matter:

  • --noop-on-unload β€” no operation is performed when the modulefile is unloaded.
  • --unset-on-unload β€” the environment variable is also unset when the modulefile is unloaded.

Both of these behaviours are applied even if an optional value is defined. So the flags win, no cap.

🌟 variant [--boolean] [--default value] name [value...]

Declares a module variant called name, with a list of accepted values, and instantiates it in the ModuleVariant array variable. This is the main-character command of module variants, fr fr.

The variant's value is selected through the module designation that leads to the modulefile evaluation. See the Advanced module version specifiers section to learn how variants can be specified.

The selected variant value is transmitted to the evaluating modulefile. A value must be specified for variant name, and it must correspond to a value in the accepted value list if such a list is defined. Otherwise an error is raised.

Exception: if the modulefile is evaluated in display mode, no error is raised when no value is specified for a given variant, and the variant is not instantiated in the ModuleVariant array variable.

And when no list of accepted values is defined at all? Then the variant can be set to any value. Freedom πŸ’«

When the --default option is set, variant name is set to the value associated with this option, in case no value is specified for the variant in the module designation.

If the --boolean option is set, variant name is defined as a Boolean variant. No list of accepted values should be defined in that case. All values recognised as Boolean values in Tcl are accepted β€” that's 1, true, t, yes, y, on, 0, false, f, no, n or off. Boolean variants are instantiated in ModuleVariant using the Tcl canonical form of the Boolean value (i.e., 0 or 1).

A variant that is not defined as a Boolean variant cannot define Boolean values in its accepted value list β€” the only exceptions are the integers 0 and 1. An error is raised otherwise.

Also: a variant cannot be named version. An error is raised otherwise. Sorry to anyone feeling creative 😭

⭐ versioncmp version1 version2

Compares the version string version1 against the version string version2. Returns -1, 0 or 1 depending on whether version1 is less than, equal to or greater than version2. Three possible answers, zero confusion.

🌈 x-resource [resource-string|filename]

Merges resources into the X11 resource database. Those resources are what control the look and behaviour of X11 applications.

The command attempts to read resources from filename. If the argument isn't a valid file name, then the string is interpreted as a resource. Whichever one it is β€” filename or resource-string β€” it gets passed down to the xrdb(1) command.

Modulefiles that use this command should, in most cases, contain one or more x-resource lines, each defining one X11 resource. The DISPLAY environment variable should be properly set and the X11 server should be accessible. If x-resource can't manipulate the X11 resource database, the modulefile will exit with an error message. So yeah, check your display situation first πŸ™ˆ

Examples:

x-resource /u2/staff/leif/.xres/Ileaf

The content of the Ileaf file is merged into the X11 resource database.

x-resource [glob ~/.xres/ileaf]

The Tcl glob function is used to have the modulefile read different resource files for different users.

x-resource {Ileaf.popup.saveUnder: True}

Merge the Ileaf resource into the X11 resource database.

Modulefiles and run-command (rc) files are differently interpreted, bestie β€” like, same family, different rules. Only a limited number of the Modules specific Tcl commands are available for rc file interpretation, because those files are meant to set parameters for modulefiles (think defining alias, hiding, tagging, etc.) and not to change the user environment. Here’s the vibe check on what’s allowed where:

  • Commands available from modulefile interpretation β€” All the Modules specific and standard Tcl commands ✨
  • Commands available from run-command (rc) file interpretation β€” is-loaded, is-used, module-alias, module-forbid, module-hide, module-info, module-tag, module-version, module-virtual, system, uname, versioncmp and standard Tcl commands
NOTE: Global and user run-command files are interpreted like modulefiles and benefit from all Modules specific Tcl commands. However it not advised to perform environment changes from such files. 🫢

🌸 MODULES VARIABLES 🌸

  • ModulesCurrentModulefile β€” This variable contains the full pathname of the modulefile being interpreted. Literally telling you where the current modulefile lives πŸ’…
  • ModulesVersion β€” This variable can be set in a .version file to designate the name of the modulefile version which should be considered as default in the current directory (see the Locating Modulefiles section below). Default-picker energy πŸ‘‘
  • ModuleTool β€” This variable contains the name of the module implementation currently in use. For this implementation, its value is set to Modules.
  • ModuleToolVersion β€” This variable contains the version of the module implementation currently in use. For this version of Modules, its value is set to 5.3.0.
  • ModuleVariant β€” This array variable contains an element entry for each defined variant associated to the value of this variant (e.g., the $ModuleVariant(foo) syntax corresponds to the value of variant foo if defined). A Tcl evaluation error is obtained when accessing an undefined variant in ModuleVariant array. Use preferably the getvariant command to retrieve a variant value when this variant state is not known.

The list of the currently defined variants can be retrieved with [array names ModuleVariant] Tcl code. Cute little array reveal πŸŽ€


πŸ¦‹ LOCATING MODULEFILES πŸ¦‹

Every directory in MODULEPATH is searched to find the modulefile. A directory in MODULEPATH can have an arbitrary number of sub-directories. If the user names a modulefile to be loaded which is actually a directory, the directory is opened and a search begins for an actual modulefile. First, modulecmd.tcl looks for a file with the name .modulerc in the directory. If this file exists, its contents will be evaluated as if it was a modulefile to be loaded. You may place module-version, module-alias and module-virtual commands inside this file.

Additionally, before seeking for .modulerc files in the module directory, the global modulerc file and the .modulerc file found at the root of the modulepath directory are sourced, too. If a named version default now exists for the modulefile to be loaded, the assigned modulefile now will be sourced. Otherwise the file .version is looked up in the module directory.

If the .version file exists, it is opened and interpreted as Tcl code and takes precedence over a .modulerc file in the same directory. If the Tcl variable ModulesVersion is set by the .version file, modulecmd.tcl will use the name as if it specifies a modulefile in this directory. This will become the default modulefile in this case. ModulesVersion cannot refer to a modulefile located in a different directory. No sneaky cross-directory defaults, bestie 🚫

If ModulesVersion is a directory, the search begins anew down that directory. If the name does not match any files located in the current directory, the search continues through the remaining directories in MODULEPATH.

Every .version and .modulerc file found is interpreted as Tcl code. The difference is that .version only applies to the current directory, and the .modulerc applies to the current directory and all subdirectories. Changes made in these files will affect the subsequently interpreted modulefile.

If a .modulecache file is found at the root of a modulepath directory, this file is interpreted as Tcl code to learn all .modulerc, .version and modulefiles available. Modulepath content is read from module cache file. Modulepath directory is only walked through to check if limited access modulefiles or directories are available to current user. Cache girlie behavior, honestly πŸ’…

If no default version may be figured out, an implicit default is selected when this behavior is enabled (see MODULES_IMPLICIT_DEFAULT in module(1)). If disabled, module names should be fully qualified when no explicit default is defined for them, otherwise no default version is found and an error is returned. If enabled, then the highest numerically sorted modulefile, virtual module or module alias under the directory will be used. The dictionary comparison method of the lsort(n) Tcl command is used to achieve this sort. If highest numerically sorted element is an alias, search continues on its modulefile target.

For example, it is possible for a user to have a directory named X11 which simply contains a .version file specifying which version of X11 is to be loaded. Such a file would look like:

#%Module1.0
##
##  The desired version of X11
##
set ModulesVersion "R4"

The equivalent .modulerc would look like:

#%Module1.0
##
##  The desired version of X11
##
module-version "./R4" default

If the extended default mechanism is enabled (see MODULES_EXTENDED_DEFAULT in module(1)) the module version specified is matched against starting portion of existing module versions, where portion is a substring separated from the rest of version string by a . character.

When the implicit default mechanism and the Advanced module version specifiers are both enabled, a default and latest symbolic versions are automatically defined for each module name (also at each directory level in case of deep modulefile). Unless a symbolic version, alias, or regular module version already exists for these version names. Automatic icons, lowkey iconic πŸ‘‘

Every file in searched directories is checked to see if it begins with the Modules magic cookie (i.e., #%Module file signature) to determine if it is a modulefile (see DESCRIPTION section). When the mcookie_check configuration is set to eval, this check is skipped and all files in search directories are considered modulefiles.

If user names a modulefile that cannot be found in the first modulepath directory, modulefile will be searched in next modulepath directory and so on until a matching modulefile is found. If search goes through a module alias or a symbolic version, this alias or symbol is resolved by first looking at the modulefiles in the modulepath where this alias or symbol is defined. If not found, resolution looks at the other modulepaths in their definition order.

When locating modulefiles, if a .modulerc, a .version, a directory or a modulefile cannot be read during the search it is simply ignored with no error message produced. Visibility of modulefiles can thus be adapted to the rights the user has been granted. Exception is made when trying to directly access a directory or a modulefile. In this case, the access issue is returned as an error message. So like, indirect misses are quiet; direct access problems get called out 🫢

Depending on their name, their file permissions or the use of specific modulefile commands, modulefile, virtual module, module alias or symbolic version may be set hidden which impacts available modules search or module selection processes (see Hiding modulefiles section below). Hidden but still doing main character things 🌈

🌸 HIDING MODULEFILES 🌸

Okay so bestie, picture this: a modulefile, a virtual module, a module alias, or a symbolic version gets called hidden when its nameβ€”or any element inside that nameβ€”starts with a dot character (.) ✨ OR when it's targeted by a module-hide command. That's the whole vibe check.

Hidden modules are not displayed or taken into account, except if they're explicitly named (e.g., foo/1.2.3 or foo/.2.0, not foo). iykyk 🫢

If a module got hidden with the --soft option of the module-hide command set, it is not considered hidden if the root name of the query searching for it matches the module root name. Like, searching foo will return a foo/1.2.3 modulefile targeted by a module-hide --soft command πŸ’–.

If a module got hidden with the --hard option of the module-hide command set, it is always considered hidden, so it is never displayed nor taken into account even if it's explicitly named. periodt. πŸ’€

A modulefile, virtual module, module alias, or symbolic version targeted by a module-hide --hard command and a module-forbid command, or whose file access permissions are restricted, is considered hard-hidden and forbidden. Such modules are not displayed or taken into account. When explicitly named for evaluation selection, such modules are unveiled to return an access error. 😭

NOTE: When the mcookie_check configuration is set to eval, file access permissions are not checked, so files with restricted permissions are included in search results but still lead to error if evaluated. πŸ™ˆ

A symbolic version-name assigned to a hidden module is displayed or taken into account only if explicitly named and if the module is not hard-hidden. A non-hidden module alias targeting a hidden modulefile appears like any other non-hidden module alias. Finally, a hidden symbolic version targeting a non-hidden module is displayed or taken into account only if not hard-hidden and explicitly named to refer to its non-hidden target. πŸ¦‹

The automatic version symbols (e.g., default and latest) are unaffected by hiding. Moreover, when a regular default or latest version is set hidden, the corresponding automatic version symbol takes the left spot. For instance, if foo/default which targets foo/1.2.3 is set hard-hidden, the default automatic version symbol will be set onto foo/2.1.3, the highest available version of foo. πŸ‘‘

When loading a modulefile or a virtual module targeted by a module-hide --hidden-loaded command, this module inherits the hidden-loaded tag. Hidden loaded modules are not reported among list sub-command results. πŸŽ€

If --all is set on avail, aliases, whatis or search sub-commands, hidden modules are taken into account in search. Hard-hidden modules are unaffected by this option.

If --all is set on list sub-command, hidden loaded modules are included in result output.


πŸ‘‘ ADVANCED MODULE VERSION SPECIFIERS πŸ‘‘

When the advanced module version specifiers mechanism is enabled (see MODULES_ADVANCED_VERSION_SPEC in module(1)), the specification of modulefile passed on Modules specific Tcl commands changes. After the module name, a version constraint and variants may be added. ✨

πŸŽ€ Version specifiers πŸŽ€

After the module name, a version constraint prefixed by the @ character may be added. It could be directly appended to the module name or separated from it with a space character. πŸ’…

Constraints can be expressed to refine the selection of module version to:

  • a single version with the @version syntax β€” for instance foo@1.2.3 syntax will select module foo/1.2.3
  • a list of versions with the @version1,version2,... syntax β€” for instance foo@1.2.3,1.10 will match modules foo/1.2.3 and foo/1.10
  • a range of versions with the @version1:, @:version2 and @version1:version2 syntaxes β€” for instance foo@1.2: will select all versions of module foo greater than or equal to 1.2, foo@:1.3 will select all versions less than or equal to 1.3 and foo@1.2:1.3 matches all versions between 1.2 and 1.3 including 1.2 and 1.3 versions

Advanced specification of a single version or list of versions may benefit from the activation of the extended default mechanism (see MODULES_EXTENDED_DEFAULT in module(1)) to use an abbreviated notation like @1 to refer to more precise version numbers like 1.2.3. Range of versions, on its side, natively handles abbreviated versions. 🫢

In order to be specified in a range of versions or compared to a range of versions, the version major element should corresponds to a number. For instance 10a, 1.2.3, 1.foo are versions valid for range comparison whereas default or foo.2 versions are invalid for range comparison. no cap

Range of versions can be specified in a version list, for instance foo@:1.2,1.4:1.6,1.8:. Such specification helps to exclude specific versions, like versions 1.3 and 1.7 in the previous example. πŸ’‘

If the implicit default mechanism is also enabled (see MODULES_IMPLICIT_DEFAULT in module(1)), a default and latest symbolic versions are automatically defined for each module name (also at each directory level for deep modulefiles). These automatic version symbols are defined unless a symbolic version, alias, or regular module version already exists for these default or latest version names. Using the mod@latest (or mod/latest) syntax ensures the highest available version will be selected. πŸ”₯

πŸ¦‹ Variants πŸ¦‹

After the module name, variants can be specified. Module variants are alternative evaluation of the same modulefile. A variant is specified by associating a value to its name. This specification is then transmitted to the evaluating modulefile which instantiates the variant in the ModuleVariant array variable when reaching the variant modulefile command declaring this variant. ✨

Variant can be specified with the name=value syntax where name is the declared variant name and value, the value this variant is set to when evaluating the modulefile.

Boolean variants can be specified with the +name syntax to set this variant on and with the -name or ~name syntaxes to set this variant off. The -name syntax is not supported on ml(1) command as the minus sign already means to unload the designated module. The ~name and +name syntaxes could also be defined appended to another specification word (e.g., the module name, version or another variant specification), whereas -name syntax must be the start of a new specification word. ⚠️

Boolean variants may also be specified with the name=value syntax. value should be set to 1, true, t, yes, y or on to enable the variant, or it should be set to 0, false, f, no, n or off to disable the variant. πŸ’–

Shortcuts may be used to abbreviate variant specification. The variant_shortcut configuration option associates a shortcut character to a variant name. With a shortcut defined, a variant could be specified with the <shortcut>value syntax. For instance, if character % is set as a shortcut for variant foo, the %value syntax is equivalent to the foo=value syntax. πŸŽ€

Specific characters used in variant specification syntax cannot be used as part of the name of a module. These specific characters are +, ~, = and all characters set as variant shortcut. Exception is made for the + character which could be set one or several consecutive times at the end of module name (e.g., name+ or name++). πŸ’…

πŸ’– DEPENDENCIES BETWEEN MODULEFILES πŸ’–

okay so this is the part where modulefiles start having relationships πŸ’… a modulefile can totally express dependencies on other modulefiles, and there are exactly two kinds: pre-requirement and conflict.

  • pre-requirement β€” the specified modulefiles should be loaded prior to the modulefile that's expressing the requirement. like, they gotta go first, no cutting the line ✨
  • conflict β€” the specified modulefiles should not be loaded for the modulefile that expresses the conflict to be loaded too. it's giving "we can't both be here" energy πŸ’€

Pre-requirement can be expressed with these modulefile commands: prereq, prereq-any, prereq-all, depends-on, always-load, module load, module switch, module try-load or module load-any.

When the auto_handling configuration option is disabled, the required modulefile should be manually loaded prior to their dependent modulefile β€” but only when it's expressed with the prereq, prereq-any, prereq-all or depends-on modulefile commands. For the other commands, or when auto_handling is enabled, pre-required modulefiles get automatically loaded 🫢

Conflict is expressed with the conflict or module unload modulefile commands. A conflicting loaded modulefile should be manually unloaded prior to loading the modulefile that expresses such conflict β€” when it's defined with conflict. It's automatically unloaded when expressed with module unload. slay, automation πŸŽ€


⚠️ bestie, listen up: it is strongly advised to define dependencies prior to environment changes in a modulefile. Dependency resolution should be done before any environment change to make sure the environment gets set in the same order whether pre-requirements are already loaded, or if they're automatically loaded when loading the modulefile that depends on them, or if all loaded modules are reloaded or refreshed. This is especially important when the modulefile updates an environment variable that's also altered by other modulefiles, like PATH. Since the order of the path elements in such a variable defines priority, it's important that this order does not change depending on the way the modulefiles are loaded. consistency is the whole vibe πŸ”₯

module keeps the environment consistent, which means a modulefile cannot be loaded if its requirements are not loaded, or if a conflicting module is loaded. In addition, a loaded module cannot be unloaded if other loaded modules depend on it. The automated module handling mechanisms attempt to solve the dependencies expressed by loading or unloading additional modulefiles. When the --no-auto option is set on the module command when loading or unloading a modulefile, the automated module handling mechanisms are disabled and dependencies have to be solved manually. When dependencies are not satisfied, the modulefile fails to load or unload 😭

Adding the --not-req option when expressing dependencies in a modulefile with the module command will attempt to load or unload the designated modulefile, but it will not mark them as pre-requirement or conflict. lowkey sneaky but valid πŸ’…

Adding the --optional option on prereq, prereq-any, prereq-all, depends-on or always-load modulefile commands declares the pre-requirement as optional. If an optional pre-requirement is not found loaded or cannot be automatically loaded, the dependency expressed is yet considered satisfied. And when an optional requirement is loaded afterward, the dependent module will get automatically reloaded if the auto_handling configuration option is enabled. the way it just ✨fixes itself✨

Adding the --force option to the module command when loading or unloading a modulefile means the consistency checks are by-passed πŸ’€ this option cannot be used when expressing dependencies in modulefiles. If a module has been force loaded whereas its requirements are not loaded, or whereas a conflicting module is also loaded, the user environment is said inconsistent. yes that's the actual technical term, no cap.

also: a pre-requirement should be found in the loaded module list prior to its dependent module. The user environment is considered inconsistent if a pre-requirement module is found loaded after the dependent module, because the environment changes may have been done in the wrong priority order πŸ™ˆ

When the user environment is considered inconsistent, the global operations achieved by the refresh, reload and save sub-commands cannot perform. This mechanism is there to avoid the situation getting worse by re-evaluating all loaded modules or recording this environment. protective queen behavior honestly πŸ‘‘

When the auto_handling configuration option is enabled: if a missing pre-requirement modulefile gets loaded, or a conflicting modulefile gets unloaded, the inconsistent loaded module will be automatically reloaded to make the user environment consistent again πŸ¦‹ periodt.


🌸 MODULEFILE SPECIFIC HELP 🌸

Users can request help about a specific modulefile through the module(1) command. The modulefile can print helpful info or start help-oriented programs by defining a ModulesHelp subroutine. That subroutine gets called when the module help modulefile command is used. so cute, so helpful πŸŽ€


⭐ MODULEFILE SPECIFIC TEST ⭐

Users can request a test of a specific modulefile through the module(1) command. The modulefile can perform some sanity checks on its definition or on its underlying programs by defining a ModulesTest subroutine. That subroutine gets called when the module test modulefile command is used.

the rule: the subroutine should return 1 in case of success. If no value β€” or any other value β€” is returned, the test is considered failed 😭

🌈 MODULEFILE DISPLAY 🌈

The module display modulefile command will detail all the changes that will be made to the environment. After displaying all of the environment changes, modulecmd.tcl will call the ModulesDisplay subroutine. The ModulesDisplay subroutine is a good place to put additional descriptive information about the modulefile. a whole little showcase moment πŸ’…βœ¨


🧚 COMPATIBILITY WITH LMOD TCL MODULEFILE 🧚

The modulecmd.tcl program supports Tcl modulefiles written for Lmod, the alternative module implementation developed in Lua. Such modulefiles can be evaluated by Modules without raising an error. The differences between the two implementations are listed below, bestie β€” read carefully πŸ‘€

  • The add-property, remove-property and extensions modulefile commands are evaluated as a no-operation command. No error is obtained if these commands are used in modulefiles, but no change occurs.
  • The break command does not accept any argument. A msg argument can be set on Lmod to provide a customized break error message.
  • Use of the reportError command aborts modulefile evaluation on Lmod. This command only reports an error message on Modules.
  • The require-fullname command only aborts load modulefile evaluation, whereas the Lmod implementation also aborts unload and display evaluations.
  • When processing a family command, the LMOD_FAMILY_<NAME> environment variable is also defined, to be compatible with modulefiles or scripts relying on such variable.
  • When unloading a modulefile, the pushenv command does not update the value of the environment variable if this modulefile was not defining the value currently in use.
  • The third optional argument of the append-path and prepend-path commands corresponds to a priority specification on Lmod, whereas these two commands accept multiple path element arguments on Modules.
  • The prereq command is equivalent to prereq-any on Modules, whereas on Lmod it's equivalent to prereq-all.
  • If the auto_handling configuration option is disabled, the requirements defined with the depends-on command are not automatically loaded, and an error is raised if none of these requirements are found loaded.
  • On the module load-any sub-command and modulefile command, a modulefile evaluation error is not reported, and module load-any continues to the next modulefile instead of aborting the whole process. No attempt to load listed modulefiles is made if one of these modulefiles is found already loaded.
  • On the module try-load modulefile command, each modulefile specified is considered an optional pre-requirement. If it is loaded afterward, and if the auto_handling configuration option is enabled, the dependent module will get automatically reloaded. self-healing behavior, we love 🫢

🐚 SHELL SUPPORT 🐚

The modulecmd.tcl program that evaluates modulefiles supports a whole variety of shells or languages: sh family shells (sh, bash, ksh and zsh), csh family shells (csh and tcsh), fish, cmd, python, perl, ruby, tcl, cmake, r, and lisp. a whole rainbow of shells 🌈

Modulefiles produce environment changes when evaluated β€” like defining an environment variable. The modulecmd.tcl program outputs the corresponding code for the selected "shell". Thereafter this code is evaluated by the module alias or function to update the current environment ✨

Depending on the "shell" kind, not all the environment changes that can be defined in modulefiles are supported. The original manual page lays this out in a table; here's the same info as a list so it's easier to read on your phone πŸ’…

The columns in that table are: Environment variables (setenv, unsetenv, pushenv, append-path, prepend-path, remove-path), Shell alias (set-alias, unset-alias), Shell functions (set-function, unset-function), Command completion (complete, uncomplete), chdir, and x-resource.

  • sh β€” environment variables βœ“, shell alias βœ“, shell functions βœ“, chdir βœ“, x-resource βœ“
  • bash β€” environment variables βœ“, shell alias βœ“, shell functions βœ“, command completion βœ“, chdir βœ“, x-resource βœ“
  • ksh β€” environment variables βœ“, shell alias βœ“, shell functions βœ“, chdir βœ“, x-resource βœ“
  • zsh β€” environment variables βœ“, shell alias βœ“, shell functions βœ“, chdir βœ“, x-resource βœ“
  • csh β€” environment variables βœ“, shell alias βœ“, chdir βœ“, x-resource βœ“
subtle but important:</p> notice bash is the one rocking the command completion column, and csh is missing out on shell functions entirely 😭 the table in the page just keeps going past what's shown here β€” the vibe check is: check the table for your shell before assuming a feature works fr fr πŸŽ€
  tcsh     ⦁               ⦁                                ⦁             ⦁       ⦁
  fish     ⦁               ⦁              ⦁                 ⦁             ⦁       ⦁
  cmd      ⦁               ⦁                                              ⦁
  python   ⦁                                                              ⦁       ⦁
  perl     ⦁                                                              ⦁       ⦁
  ruby     ⦁                                                              ⦁       ⦁
  tcl      ⦁                                                              ⦁       ⦁
  cmake    ⦁                                                                      ⦁
  r        ⦁                                                              ⦁       ⦁
  lisp     ⦁                                                              ⦁       ⦁

Every ⦁ in that grid is a yes bestie, that kind of environment change gets rendered β€” so line up the row of the language you're evaluating against the columns from the table up above and you can tell at a glance what you'll get. No guessing, no vibes-only, just read the grid. πŸ’…


So the tea on source-sh β˜•: it evaluates a shell script and then produces the modulefile commands corresponding to the environment changes that the script made. Like, it watches what your script actually did to the environment and translates that into modulefile-speak. Iconic behaviour, honestly.

source-sh is able to evaluate sh, bash, ksh, zsh, csh, tcsh and fish shell scripts. And it produces environment changes corresponding to the kinds listed in the table above. So based on the evaluated script, go peek at that table to know exactly which environment changes will be rendered for the shell you specified to the modulecmd.tcl program. Read the script, check the grid, know your fate. ✨


🌸 ENVIRONMENT 🌸

Genuinely just go read the ENVIRONMENT section in the module(1) man page, bestie. That's where the whole story lives, and I'm not about to steal its moment. 🫢


πŸ¦‹ SEE ALSO πŸ¦‹

Everything you might wanna slide into next:


πŸŽ€ NOTES πŸŽ€

Some lore for you, because credit matters and I'm obsessed with accuracy:

  • Tcl was developed by John Ousterhout at the University of California at Berkeley. Academic royalty, fr fr. πŸ‘‘
  • TclX was developed by Karl Lehenbauer and Mark Diekhans.

Respect the whole lineage, no cap β€” this thing has many parents and every single one of them ate:

1996-1999 John L. Furlani & Peter W. Osel, 1998-2017 R.K.Owen, 2002-2004 Mark Lakata, 2004-2017 Kent Mein, 2016-2022 Xavier Delaruelle


And that's a wrap on the whole page, bestie πŸŽ‰πŸ’– This little beauty is version 5.3.0, dated 2023-05-14, and it's the MODULEFILE(4) manual page β€” go forth and write the most immaculate modulefiles of your life βœ¨πŸ¦‹πŸŽ€

πŸ“¦ where this page comes from