How does Lmod convert TCL modulefile into Lua

Lmod uses a TCL program called tcl2lua.tcl to read TCL modulefiles and convert them to lua. The whole TCL modulefile evaluated by the TCL interpreter. This is NOT a source to source translation.

The purpose of tcl2lua.tcl is to evaluate the regular TCL command but replace “module functions”, such as prepend-path or setenv, and converted to Lua functions. For example, suppose you have the following simple TCL modulefile for git:

#%Module
set appDir          $env(APP_DIR)
set version         2.0.3

prepend-path        PATH "$appDir/git/$version/bin"

Assuming that the environment variable APP_DIR is /apps then the entire output of the tcl2lua.tcl program would be:

prepend_path("PATH", "/apps/git/2.0.3/bin")

Note that all the normal TCL code has been evaluated and the TCL prepend-path command has been converted to a lua prepend_path function call.

Normally this works fine. However, because Lmod does evaluate the actions of a TCL module file as a two-step process, it can cause problems. In particular, suppose you have two TCL modulefiles:

Centos:

#%Module
setenv SYSTEM_NAME Centos

And B:

#%Module
module load Centos

if { $env(SYSTEM_NAME) == "Centos" } {
   # do something
}

When Lmod tries to translate the B modulefile into lua it fails:

load("Centos")
LmodError([[/opt/mfiles/B: (???): can't read "env(SYSTEM_NAME)": no such variable]])

This is because unlike the TCL/C Module system, the module load Centos command is converted to a function call, but it won’t load the module in time for the test to be evaluated properly.

The only solution is convert the B modulefile into a Lua modulefile (B.lua):

load("Centos")
if (os.getenv("SYSTEM_NAME") == "Centos") then
  -- Do something
end

The Centos modulefile does not have to be translated in order for this to work, just the B modulefile.

As a side note, you are free to put Lua modules in the same tree that the TCL/C Module system uses. It will ignore files that the first line is not #%Module and Lmod will pick B.lua over B.