diff options
-rw-r--r-- | lib/spack/spack/operating_systems/cray_frontend.py | 43 | ||||
-rw-r--r-- | lib/spack/spack/test/compilers/detection.py | 44 |
2 files changed, 85 insertions, 2 deletions
diff --git a/lib/spack/spack/operating_systems/cray_frontend.py b/lib/spack/spack/operating_systems/cray_frontend.py index 15f5b23baf..a11875ae75 100644 --- a/lib/spack/spack/operating_systems/cray_frontend.py +++ b/lib/spack/spack/operating_systems/cray_frontend.py @@ -5,8 +5,11 @@ import contextlib import os +import re import llnl.util.filesystem as fs +import llnl.util.lang +import llnl.util.tty as tty from spack.operating_systems.linux_distro import LinuxDistro from spack.util.environment import get_path @@ -60,6 +63,42 @@ class CrayFrontend(LinuxDistro): This prevents from detecting Cray compiler wrappers and avoids possible false detections. """ + import spack.compilers + with unload_programming_environment(): - search_paths = fs.search_paths_for_executables(*get_path('PATH')) - return search_paths + search_paths = get_path('PATH') + + extract_path_re = re.compile(r'prepend-path[\s]*PATH[\s]*([/\w\.:-]*)') + + for compiler_cls in spack.compilers.all_compiler_types(): + # Check if the compiler class is supported on Cray + prg_env = getattr(compiler_cls, 'PrgEnv', None) + compiler_module = getattr(compiler_cls, 'PrgEnv_compiler', None) + if not (prg_env and compiler_module): + continue + + # It is supported, check which versions are available + output = module('avail', compiler_cls.PrgEnv_compiler) + version_regex = r'({0})/([\d\.]+[\d]-?[\w]*)'.format( + compiler_cls.PrgEnv_compiler + ) + matches = re.findall(version_regex, output) + versions = tuple(version for _, version in matches) + + # Now inspect the modules and add to paths + msg = "[CRAY FE] Detected FE compiler [name={0}, versions={1}]" + tty.debug(msg.format(compiler_module, versions)) + for v in versions: + try: + current_module = compiler_module + '/' + v + out = module('show', current_module) + match = extract_path_re.search(out) + search_paths += match.group(1).split(':') + except Exception as e: + msg = ("[CRAY FE] An unexpected error occurred while " + "detecting FE compiler [compiler={0}, " + " version={1}, error={2}]") + tty.debug(msg.format(compiler_cls.name, v, str(e))) + + search_paths = list(llnl.util.lang.dedupe(search_paths)) + return fs.search_paths_for_executables(*search_paths) diff --git a/lib/spack/spack/test/compilers/detection.py b/lib/spack/spack/test/compilers/detection.py index b38cf89b5d..f36e15804d 100644 --- a/lib/spack/spack/test/compilers/detection.py +++ b/lib/spack/spack/test/compilers/detection.py @@ -4,6 +4,9 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) """Test detection of compiler version""" import pytest +import os + +import llnl.util.filesystem as fs import spack.compilers.arm import spack.compilers.cce @@ -16,6 +19,9 @@ import spack.compilers.pgi import spack.compilers.xl import spack.compilers.xl_r +from spack.operating_systems.cray_frontend import CrayFrontend +import spack.util.module_cmd + @pytest.mark.parametrize('version_str,expected_version', [ ('Arm C/C++/Fortran Compiler version 19.0 (build number 73) (based on LLVM 7.0.2)\n' # NOQA @@ -189,3 +195,41 @@ def test_xl_version_detection(version_str, expected_version): version = spack.compilers.xl_r.XlR.extract_version_from_output(version_str) assert version == expected_version + + +@pytest.mark.parametrize('compiler,version', [ + ('gcc', '8.1.0'), + ('gcc', '1.0.0-foo'), + ('pgi', '19.1'), + ('pgi', '19.1a'), + ('intel', '9.0.0'), + ('intel', '0.0.0-foobar') +]) +def test_cray_frontend_compiler_detection( + compiler, version, tmpdir, monkeypatch, working_env +): + """Test that the Cray frontend properly finds compilers form modules""" + # setup the fake compiler directory + compiler_dir = tmpdir.join(compiler) + compiler_exe = compiler_dir.join('cc').ensure() + fs.set_executable(str(compiler_exe)) + + # mock modules + def _module(cmd, *args): + module_name = '%s/%s' % (compiler, version) + module_contents = 'prepend-path PATH %s' % compiler_dir + if cmd == 'avail': + return module_name if compiler in args[0] else '' + if cmd == 'show': + return module_contents if module_name in args else '' + monkeypatch.setattr(spack.operating_systems.cray_frontend, 'module', + _module) + + # remove PATH variable + os.environ.pop('PATH', None) + + # get a CrayFrontend object + cray_fe_os = CrayFrontend() + + paths = cray_fe_os.compiler_search_paths + assert paths == [str(compiler_dir)] |