diff options
-rw-r--r-- | lib/spack/spack/modules/lmod.py | 46 | ||||
-rw-r--r-- | lib/spack/spack/test/modules/lmod.py | 23 |
2 files changed, 64 insertions, 5 deletions
diff --git a/lib/spack/spack/modules/lmod.py b/lib/spack/spack/modules/lmod.py index aa41b27daa..a057f2bf3a 100644 --- a/lib/spack/spack/modules/lmod.py +++ b/lib/spack/spack/modules/lmod.py @@ -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 @@ class LmodConfiguration(BaseConfiguration): 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 diff --git a/lib/spack/spack/test/modules/lmod.py b/lib/spack/spack/test/modules/lmod.py index 2b3949621d..b262ab7b5b 100644 --- a/lib/spack/spack/test/modules/lmod.py +++ b/lib/spack/spack/test/modules/lmod.py @@ -258,3 +258,26 @@ class TestLmod(object): 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 |