Feature: Allow lmod configuration to set core specs (#16517)

Packages built with lmod core_compiler are placed in `Core`.

Other packages may belong in `Core`. For example, python may be built with a proprietary compiler for performance, but belong on the `Core` directory.

With this PR, lmod config can include a `core_specs` list. Any package that satisfies a spec in that list is placed in `Core`, regardless of its compiler or dependencies.
This commit is contained in:
Greg Becker 2020-05-14 11:27:37 -07:00 committed by GitHub
parent 20b3e41831
commit 445cae5c81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 3 deletions

View file

@ -538,6 +538,8 @@ most likely via the ``+blas`` variant specification.
lmod: lmod:
core_compilers: core_compilers:
- 'gcc@4.8' - 'gcc@4.8'
core_specs:
- 'python'
hierarchy: hierarchy:
- 'mpi' - 'mpi'
- 'lapack' - 'lapack'
@ -547,6 +549,15 @@ most likely via the ``+blas`` variant specification.
implementations of ``mpi`` and ``lapack``, and let LMod switch safely from one to the implementations of ``mpi`` and ``lapack``, and let LMod switch safely from one to the
other. other.
All packages built with a compiler in ``core_compilers`` and all
packages that satisfy a spec in ``core_specs`` will be put in the
``Core`` hierarchy of the lua modules.
.. warning::
Consistency of Core packages
The user is responsible for maintining consistency among core packages, as ``core_specs``
bypasses the hierarchy that allows LMod to safely switch between coherent software stacks.
.. warning:: .. warning::
Deep hierarchies and ``lmod spider`` Deep hierarchies and ``lmod spider``
For hierarchies that are deeper than three layers ``lmod spider`` may have some issues. For hierarchies that are deeper than three layers ``lmod spider`` may have some issues.

View file

@ -110,6 +110,11 @@ def core_compilers(self):
raise CoreCompilersNotFoundError(msg) raise CoreCompilersNotFoundError(msg)
return value return value
@property
def core_specs(self):
"""Returns the list of "Core" specs"""
return configuration().get('core_specs', [])
@property @property
def hierarchy_tokens(self): def hierarchy_tokens(self):
"""Returns the list of tokens that are part of the modulefile """Returns the list of tokens that are part of the modulefile
@ -140,6 +145,11 @@ def requires(self):
to the actual provider. 'compiler' is always present among the to the actual provider. 'compiler' is always present among the
requirements. requirements.
""" """
# If it's a core_spec, lie and say it requires a core compiler
if any(self.spec.satisfies(core_spec)
for core_spec in self.core_specs):
return {'compiler': self.core_compilers[0]}
# Keep track of the requirements that this package has in terms # Keep track of the requirements that this package has in terms
# of virtual packages that participate in the hierarchical structure # of virtual packages that participate in the hierarchical structure
requirements = {'compiler': self.spec.compiler} requirements = {'compiler': self.spec.compiler}

View file

@ -16,7 +16,7 @@
#: #:
#: THIS NEEDS TO BE UPDATED FOR EVERY NEW KEYWORD THAT #: THIS NEEDS TO BE UPDATED FOR EVERY NEW KEYWORD THAT
#: IS ADDED IMMEDIATELY BELOW THE MODULE TYPE ATTRIBUTE #: IS ADDED IMMEDIATELY BELOW THE MODULE TYPE ATTRIBUTE
spec_regex = r'(?!hierarchy|verbose|hash_length|whitelist|' \ spec_regex = r'(?!hierarchy|core_specs|verbose|hash_length|whitelist|' \
r'blacklist|naming_scheme|core_compilers|all)(^\w[\w-]*)' r'blacklist|naming_scheme|core_compilers|all)(^\w[\w-]*)'
#: Matches an anonymous spec, i.e. a spec without a root name #: Matches an anonymous spec, i.e. a spec without a root name
@ -145,7 +145,8 @@
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'core_compilers': array_of_strings, 'core_compilers': array_of_strings,
'hierarchy': array_of_strings 'hierarchy': array_of_strings,
'core_specs': array_of_strings,
}, },
} # Specific lmod extensions } # Specific lmod extensions
] ]

View file

@ -6,6 +6,9 @@ lmod:
core_compilers: core_compilers:
- 'clang@3.3' - 'clang@3.3'
core_specs:
- 'mpich@3.0.1'
hierarchy: hierarchy:
- lapack - lapack
- blas - blas

View file

@ -27,6 +27,7 @@ def compiler(request):
@pytest.fixture(params=[ @pytest.fixture(params=[
('mpich@3.0.4', ('mpi',)), ('mpich@3.0.4', ('mpi',)),
('mpich@3.0.1', []),
('openblas@0.2.15', ('blas',)), ('openblas@0.2.15', ('blas',)),
('openblas-with-lapack@0.2.15', ('blas', 'lapack')) ('openblas-with-lapack@0.2.15', ('blas', 'lapack'))
]) ])
@ -54,7 +55,8 @@ def test_file_layout(
# Check that the compiler part of the path has no hash and that it # Check that the compiler part of the path has no hash and that it
# is transformed to r"Core" if the compiler is listed among core # is transformed to r"Core" if the compiler is listed among core
# compilers # compilers
if compiler == 'clang@3.3': # Check that specs listed as core_specs are transformed to "Core"
if compiler == 'clang@3.3' or spec_string == 'mpich@3.0.1':
assert 'Core' in layout.available_path_parts assert 'Core' in layout.available_path_parts
else: else:
assert compiler.replace('@', '/') in layout.available_path_parts assert compiler.replace('@', '/') in layout.available_path_parts