Spack can guess lmod core compilers, if none is already present

closes #8916

Currently Spack ends with an error if asked to write lmod modules files
and the 'core_compilers' entry is not found in `modules.yaml`. After
this PR an attempt will be made to guess that entry and the site
configuration file will be updated accordingly.

This is similar to what Spack already does to guess compilers on first
run.
This commit is contained in:
Massimiliano Culpo 2018-08-14 11:59:11 +02:00 committed by Todd Gamblin
parent 2fdfa46735
commit 8ecf5ae2ee
2 changed files with 64 additions and 5 deletions

View File

@ -65,6 +65,42 @@ def make_context(spec):
return LmodContext(conf)
def guess_core_compilers(store=False):
"""Guesses the list of core compilers installed in the system.
Args:
store (bool): if True writes the core compilers to the
modules.yaml configuration file
Returns:
List of core compilers, if found, or None
"""
core_compilers = []
for compiler_config in spack.compilers.all_compilers_config():
try:
compiler = compiler_config['compiler']
# A compiler is considered to be a core compiler if any of the
# C, C++ or Fortran compilers reside in a system directory
is_system_compiler = any(
os.path.dirname(x) in spack.util.environment.system_dirs
for x in compiler['paths'].values() if x is not None
)
if is_system_compiler:
core_compilers.append(str(compiler['spec']))
except (KeyError, TypeError, AttributeError):
continue
if store and core_compilers:
# If we asked to store core compilers, update the entry
# at 'site' scope (i.e. within the directory hierarchy
# of Spack itself)
modules_cfg = spack.config.get('modules', scope='site')
modules_cfg.setdefault('lmod', {})['core_compilers'] = core_compilers
spack.config.set('modules', modules_cfg, scope='site')
return core_compilers or None
class LmodConfiguration(BaseConfiguration):
"""Configuration class for lmod module files."""
@ -77,12 +113,12 @@ def core_compilers(self):
specified in the configuration file or the sequence
is empty
"""
value = configuration.get('core_compilers')
if value is None:
msg = "'core_compilers' key not found in configuration file"
raise CoreCompilersNotFoundError(msg)
value = configuration.get(
'core_compilers'
) or guess_core_compilers(store=True)
if not value:
msg = "'core_compilers' list cannot be empty"
msg = 'the key "core_compilers" must be set in modules.yaml'
raise CoreCompilersNotFoundError(msg)
return value

View File

@ -258,3 +258,26 @@ def test_external_configure_args(
writer, spec = factory('externaltool')
assert 'unknown' in writer.context.configure_options
def test_guess_core_compilers(
self, factory, module_configuration, monkeypatch
):
"""Check that we can guess core compilers."""
# In this case we miss the entry completely
module_configuration('missing_core_compilers')
# Our mock paths must be detected as system paths
monkeypatch.setattr(
spack.util.environment, 'system_dirs', ['/path/to']
)
# We don't want to really write into user configuration
# when running tests
def no_op_set(*args, **kwargs):
pass
monkeypatch.setattr(spack.config, 'set', no_op_set)
# Assert we have core compilers now
writer, _ = factory(mpileaks_spec_string)
assert writer.conf.core_compilers