Skip to content

Commit 926b8fa

Browse files
authored
Merge pull request #1813 from climbfuji/feature/shorter_modulepaths
This PR shortens the module paths for the modules generated by spack module [tcl|lmod] refresh and spack stack setup-meta-modules. It does so by implementing a compiler- and MPI-name translation and shortening the path where the modules are generated. This is done in multiple places: configs/common/modules_lmod.yaml (configs/common/modules_tcl.yaml) spack-ext/lib/jcsda-emc/spack-stack/stack/meta_modules.py While this solution comes with a certain amount of code duplication, I consider it as the best option because any other solution would have required changes to the spack code itself. Also, we rarely make changes to these names or add new compilers and MPI providers, thus the maintenance effort is low. While working on this, I realized that the ecmwf-atlas --> atlas translation never worked as intended, because it was missing the MPI module dependency. I checked and the spack-generated modules were named ecmwf-atlas before this PR was made (at least for tcl modules). I therefore removed this mapping, since the module name ecmwf-atlas apparently worked fine until now.
2 parents b5de645 + f47b076 commit 926b8fa

File tree

9 files changed

+92
-43
lines changed

9 files changed

+92
-43
lines changed

.github/workflows/ubuntu-ci-x86_64-gnu.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ jobs:
234234
235235
export ENVNAME=ue-gcc-11.4.0
236236
export ENVDIR=$PWD/envs/${ENVNAME}
237-
ls -l ${ENVDIR}/install/modulefiles/Core
237+
ls -l ${ENVDIR}/modules/Core
238238
239-
module use ${ENVDIR}/install/modulefiles/Core
239+
module use ${ENVDIR}/modules/Core
240240
module load stack-gcc/11.4.0
241241
module load stack-openmpi/5.0.8
242242
module available

.github/workflows/ubuntu-ci-x86_64-oneapi-ifx.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ jobs:
242242
243243
export ENVNAME=ue-oneifx-2024.2.0
244244
export ENVDIR=$PWD/envs/${ENVNAME}
245-
ls -l ${ENVDIR}/install/modulefiles/Core
245+
ls -l ${ENVDIR}/modules/Core
246246
247-
module use ${ENVDIR}/install/modulefiles/Core
247+
module use ${ENVDIR}/modules/Core
248248
module load stack-intel-oneapi-compilers/2024.2.0
249249
module load stack-intel-oneapi-mpi/2021.13
250250
module available

.github/workflows/ubuntu-ci-x86_64-oneapi.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ jobs:
242242
243243
export ENVNAME=ue-oneapi-2024.2.0
244244
export ENVDIR=$PWD/envs/${ENVNAME}
245-
ls -l ${ENVDIR}/install/modulefiles/Core
245+
ls -l ${ENVDIR}/modules/Core
246246
247-
module use ${ENVDIR}/install/modulefiles/Core
247+
module use ${ENVDIR}/modules/Core
248248
module load stack-intel-oneapi-compilers/2024.2.0
249249
module load stack-intel-oneapi-mpi/2021.13
250250
module available

configs/common/modules_lmod.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
modules:
44
default:
55
roots:
6-
lmod: $env/install/modulefiles
6+
lmod: $env/modules
77
lmod:
88
# Core compiler is a dummy that is not used to build the stack, do not change.
99
# Hopefully nobody is trying to build software with gcc-4.6 in 2023 ...
1010
core_compilers::
1111
1212
projections:
13-
ecmwf-atlas: 'atlas/{version}'
1413
nlohmann-json: 'json/{version}'
1514
nlohmann-json-schema-validator: 'json-schema-validator/{version}'
1615
libjpeg-turbo: 'libjpeg/{version}'

configs/common/modules_tcl.yaml

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,32 @@
33
modules:
44
default:
55
roots:
6-
tcl: $env/install/modulefiles
6+
tcl: $env/modules
77
tcl:
88
projections:
9-
all: '{compiler.name}/{compiler.version}/{name}/{version}'
9+
# Note: These translations of compiler and MPI library names must match the ALIASES
10+
# dictionary in spack-ext/lib/jcsda-emc/spack-stack/stack/meta_modules.py
11+
# Defaults
12+
'^intel-oneapi-compilers-classic^intel-oneapi-mpi': 'impi/{^mpi.version}/intel/{compiler.version}/{name}/{version}'
13+
'^intel-oneapi-compilers-classic^mpi': '{^mpi.name}/{^mpi.version}/intel/{compiler.version}/{name}/{version}'
14+
'^intel-oneapi-compilers-classic': 'intel/{compiler.version}/{name}/{version}'
15+
'^intel-oneapi-compilers^intel-oneapi-mpi': 'impi/{^mpi.version}/oneapi/{compiler.version}/{name}/{version}'
16+
'^intel-oneapi-compilers^mpi': '{^mpi.name}/{^mpi.version}/oneapi/{compiler.version}/{name}/{version}'
17+
'^intel-oneapi-compilers': 'oneapi/{compiler.version}/{name}/{version}'
18+
^intel-oneapi-mpi: 'impi/{^mpi.version}/{compiler.name}/{compiler.version}/{name}/{version}'
1019
^mpi: '{^mpi.name}/{^mpi.version}/{compiler.name}/{compiler.version}/{name}/{version}'
11-
ecmwf-atlas: '{compiler.name}/{compiler.version}/atlas/{version}'
20+
all: '{compiler.name}/{compiler.version}/{name}/{version}'
21+
# The special cases - Intel classic compilers
22+
'nlohmann-json ^intel-oneapi-compilers-classic': 'intel/{compiler.version}/json/{version}'
23+
'nlohmann-json-schema-validator ^intel-oneapi-compilers-classic': 'intel/{compiler.version}/json-schema-validator/{version}'
24+
'libjpeg-turbo ^intel-oneapi-compilers-classic': 'intel/{compiler.version}/libjpeg/{version}'
25+
'prod-util ^intel-oneapi-compilers-classic': 'intel/{compiler.version}/prod_util/{version}'
26+
# The special cases - Intel LLVM compilers
27+
'nlohmann-json ^intel-oneapi-compilers': 'oneapi/{compiler.version}/json/{version}'
28+
'nlohmann-json-schema-validator ^intel-oneapi-compilers': 'oneapi/{compiler.version}/json-schema-validator/{version}'
29+
'libjpeg-turbo ^intel-oneapi-compilers': 'oneapi/{compiler.version}/libjpeg/{version}'
30+
'prod-util ^intel-oneapi-compilers': 'oneapi/{compiler.version}/prod_util/{version}'
31+
# The special cases - other compilers
1232
nlohmann-json: '{compiler.name}/{compiler.version}/json/{version}'
1333
nlohmann-json-schema-validator: '{compiler.name}/{compiler.version}/json-schema-validator/{version}'
1434
libjpeg-turbo: '{compiler.name}/{compiler.version}/libjpeg/{version}'

repos/builtin

spack-ext/lib/jcsda-emc/spack-stack/stack/meta_modules.py

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,22 @@
5252
"MPIROOT": "",
5353
}
5454

55-
56-
# DH* TODO: IMPORT THIS FROM SPACK, THEY MAINTAIN THE SAME DICTIONARY
57-
COMPILER_TRANSLATION_TABLE = {
55+
# Aliases to shorten module paths for tcl modules. These aliases must match
56+
# the compiler and MPI name translations in configs/common/modules_tcl.yaml
57+
ALIASES = {
58+
"none" : "none",
59+
# Compilers
5860
"gcc" : "gcc",
59-
"clang" : "llvm",
60-
"intel" : "intel-oneapi-compilers-classic",
61-
"oneapi" : "intel-oneapi-compilers",
61+
"intel-oneapi-compilers-classic" : "intel",
62+
"intel-oneapi-compilers" : "oneapi",
63+
"llvm" : "llvm",
64+
# MPI
65+
"cray-mpich" : "cray-mpich",
66+
# Do we still need intel-mpi, and if yes, use the same impi?
67+
"intel-oneapi-mpi" : "impi",
68+
"mpich" : "mpich",
69+
"mpt" : "mpt",
70+
"openmpi" : "openmpi",
6271
}
6372

6473

@@ -220,7 +229,7 @@ def get_preferred_compiler():
220229
return preferred_compiler
221230

222231

223-
def remove_compiler_prefices_from_tcl_modulefiles(modulepath, compiler_list, mpi_provider):
232+
def remove_compiler_prefices_from_tcl_modulefiles(modulepath, compiler_list, mpi_provider, module_choice):
224233
"""Remove compiler and mpi prefices from tcl modulefiles in modulepath"""
225234
logging.info(f" ... ... removing compiler/mpi prefices from tcl modulefiles in {modulepath}")
226235
module_replace_patterns = ["is-loaded", "module load", "depends-on"]
@@ -237,20 +246,30 @@ def remove_compiler_prefices_from_tcl_modulefiles(modulepath, compiler_list, mpi
237246
for compiler in compiler_list:
238247
# First, compiler-dependent modules
239248
(compiler_name, compiler_version) = compiler.split("@")
249+
# Module paths are short names for tcl modules
250+
if module_choice == "lmod":
251+
compiler_alias = compiler_name
252+
else:
253+
compiler_alias = ALIASES[compiler_name]
240254
cmd = "sed -i {4} 's#{0} {1}/{2}/#{0} #g' {3}".format(
241-
pattern, compiler_name, compiler_version, filepath, sed_syntax_fix
255+
pattern, compiler_alias, compiler_version, filepath, sed_syntax_fix
242256
)
243257
status = os.system(cmd)
244258
if not status == 0:
245259
raise Exception(f"Error while calling '{cmd}'")
246260
# If mpi_provider is not None, also do compiler+mpi-dependent modules
247261
if not mpi_provider:
248262
continue
263+
# Module paths are short names for tcl modules
264+
if module_choice == "lmod":
265+
mpi_alias = mpi_provider.name
266+
else:
267+
mpi_alias = ALIASES[mpi_provider.name]
249268
cmd = "sed -i {6} 's#{0} {1}/{2}/{3}/{4}/#{0} #g' {5}".format(
250269
pattern,
251-
mpi_provider.name,
270+
mpi_alias,
252271
mpi_provider.version,
253-
compiler_name,
272+
compiler_alias,
254273
compiler_version,
255274
filepath,
256275
sed_syntax_fix,
@@ -381,13 +400,20 @@ def custom_sort_key(entry):
381400
remove_compiler_prefices_from_tcl_modulefiles(
382401
modulepath_save,
383402
compiler_list,
384-
mpi_provider = None
403+
mpi_provider = None,
404+
module_choice = module_choice
385405
)
386406

387407
for compiler in compilers:
388408
logging.info(f" ... configuring compiler {compiler.name}@{compiler.version}")
389409

390-
modulepath_save = os.path.join(module_dir, compiler.name, str(compiler.version))
410+
# Module paths are short names for tcl modules
411+
if module_choice == "lmod":
412+
compiler_alias = compiler.name
413+
else:
414+
compiler_alias = ALIASES[compiler.name]
415+
416+
modulepath_save = os.path.join(module_dir, compiler_alias, str(compiler.version))
391417
if not os.path.isdir(modulepath_save):
392418
os.makedirs(modulepath_save)
393419
logging.info(" ... ... appending {} to MODULEPATHS_SAVE".format(modulepath_save))
@@ -398,7 +424,8 @@ def custom_sort_key(entry):
398424
remove_compiler_prefices_from_tcl_modulefiles(
399425
modulepath_save,
400426
compiler_list,
401-
mpi_provider = None
427+
mpi_provider = None,
428+
module_choice = module_choice
402429
)
403430

404431
# The remainder of the loop is only needed for the preferred compiler
@@ -496,15 +523,20 @@ def custom_sort_key(entry):
496523
# For tcl, append modulepath for external specs and for specs without
497524
# compiler dependencies; remove the compiler/mpi prefices from the moduless
498525
if module_choice == "tcl":
499-
modulepath_save = os.path.join(module_dir, mpi_provider.name, str(mpi_provider.version), "none", "none")
526+
527+
# Module paths are short names for tcl modules
528+
mpi_alias = ALIASES[mpi_provider.name]
529+
530+
modulepath_save = os.path.join(module_dir, mpi_alias, str(mpi_provider.version), "none", "none")
500531
if not os.path.isdir(modulepath_save):
501532
os.makedirs(modulepath_save)
502533
logging.info(" ... appending {} to MODULEPATHS_SAVE".format(modulepath_save))
503534
MODULEPATHS_SAVE.append(modulepath_save)
504535
remove_compiler_prefices_from_tcl_modulefiles(
505536
modulepath_save,
506537
compiler_list,
507-
mpi_provider = mpi_provider
538+
mpi_provider = mpi_provider,
539+
module_choice = module_choice
508540
)
509541

510542
for compiler in compilers:
@@ -514,9 +546,15 @@ def custom_sort_key(entry):
514546
)
515547
)
516548

549+
# Module paths are short names for tcl modules
550+
if module_choice == "lmod":
551+
mpi_alias = compiler.name
552+
else:
553+
compiler_alias = ALIASES[compiler.name]
554+
517555
# Spack mpi+compiler module hierarchy
518556
modulepath_save = os.path.join(
519-
module_dir, mpi_provider.name, str(mpi_provider.version), compiler.name, str(compiler.version)
557+
module_dir, mpi_alias, str(mpi_provider.version), compiler_alias, str(compiler.version)
520558
)
521559
if not os.path.isdir(modulepath_save):
522560
os.makedirs(modulepath_save)
@@ -528,7 +566,8 @@ def custom_sort_key(entry):
528566
remove_compiler_prefices_from_tcl_modulefiles(
529567
modulepath_save,
530568
compiler_list,
531-
mpi_provider = mpi_provider
569+
mpi_provider = mpi_provider,
570+
module_choice = module_choice
532571
)
533572

534573
# The remainder of the loop is only needed for the preferred compiler
@@ -537,7 +576,7 @@ def custom_sort_key(entry):
537576

538577
# Path and name for mpi module file
539578
mpi_module_dir = os.path.join(
540-
module_dir, compiler.name, str(compiler.version), "stack-" + mpi_provider.name
579+
module_dir, compiler_alias, str(compiler.version), "stack-" + mpi_provider.name
541580
)
542581
mpi_module_file = os.path.join(
543582
mpi_module_dir, str(mpi_provider.version).split("-")[0] + MODULE_FILE_EXTENSION[module_choice]

spack-ext/lib/jcsda-emc/spack-stack/tests/test_setup_meta_modules.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_setup_meta_modules():
3535

3636
env_name = "modtest1"
3737
env_dir = os.path.join(env_root_dir, env_name)
38-
module_dir = os.path.join(env_dir, "install", "modulefiles")
38+
module_dir = os.path.join(env_dir, "modules")
3939
if os.path.exists(env_dir):
4040
shutil.rmtree(env_dir)
4141

util/modules_config_check.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,12 @@
2020
yaml_raw = f.read().replace("lmod:", "LMOD_OR_TCL:").replace("tcl:", "LMOD_OR_TCL:")
2121
modules[lmod_or_tcl] = syaml.load_config(yaml_raw)
2222

23-
# Check subset of projection to ensure keys match
24-
lmod_projections = modules["lmod"]["modules"]["default"]["LMOD_OR_TCL"]["projections"].keys()
25-
tcl_projections = modules["tcl"]["modules"]["default"]["LMOD_OR_TCL"]["projections"].keys()
26-
assert set(lmod_projections) == set(tcl_projections)-{"all", "^mpi"}
27-
28-
for lmod_or_tcl in ("lmod", "tcl"):
29-
for key in modules[lmod_or_tcl]["modules"]["default"]["LMOD_OR_TCL"]["projections"].keys():
30-
modules[lmod_or_tcl]["modules"]["default"]["LMOD_OR_TCL"]["projections"][key] = "DUMMYVALUE"
31-
3223
# Removing sections we don't want to compare; note this will
33-
# affect line numbers in the diff output
24+
# affect line numbers in the diff output
3425
del(modules["lmod"]["modules"]["default"]["LMOD_OR_TCL"]["core_compilers"])
3526
del(modules["lmod"]["modules"]["default"]["LMOD_OR_TCL"]["hierarchy"])
36-
del(modules["tcl"]["modules"]["default"]["LMOD_OR_TCL"]["projections"]["all"])
37-
del(modules["tcl"]["modules"]["default"]["LMOD_OR_TCL"]["projections"]["^mpi"])
27+
del(modules["lmod"]["modules"]["default"]["LMOD_OR_TCL"]["projections"])
28+
del(modules["tcl"]["modules"]["default"]["LMOD_OR_TCL"]["projections"])
3829

3930
# If sections mismatch, print a diff of the whole configuration
4031
dump_lmod = syaml.dump_config(modules["lmod"]).split("\n")

0 commit comments

Comments
 (0)