From 8ecf5ae2eebf85e580e0a23ccd2bebed094c507f Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 14 Aug 2018 11:59:11 +0200 Subject: 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. --- lib/spack/spack/modules/lmod.py | 46 ++++++++++++++++++++++++++++++++---- 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 -- cgit v1.2.3-70-g09d2