diff options
author | scheibelp <scheibel1@llnl.gov> | 2017-03-16 21:08:13 -0700 |
---|---|---|
committer | becker33 <becker33@llnl.gov> | 2017-03-16 21:08:13 -0700 |
commit | 0b27a7e13d5138ebf9b2d7510b1c16179e3b803c (patch) | |
tree | bf44388b698a5d99a54a31aebfb3b854fc667ae0 /lib | |
parent | 5936ad2ca78566fd13ad11081a75e333697b2065 (diff) | |
download | spack-0b27a7e13d5138ebf9b2d7510b1c16179e3b803c.tar.gz spack-0b27a7e13d5138ebf9b2d7510b1c16179e3b803c.tar.bz2 spack-0b27a7e13d5138ebf9b2d7510b1c16179e3b803c.tar.xz spack-0b27a7e13d5138ebf9b2d7510b1c16179e3b803c.zip |
Detect when OS updates affect compiler selection (#3410)
Fixes #1476
Concretization uses compilers defined in config files and if those
are not available defaults to searching typical paths where the
detected operating system would have a compiler. If there is an OS
update, the detected OS can change; in this case all compilers
defined in the config files would no longer match (because they would
be associated with the previous OS version). The error message in
this case was too vague. This commit adds logic for detecting when it
is likely that the OS has been updated (in particular when that
affects compiler concretization) and improves the information provided
to the user in the error message.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/compilers/__init__.py | 11 | ||||
-rw-r--r-- | lib/spack/spack/concretize.py | 77 | ||||
-rw-r--r-- | lib/spack/spack/test/concretize.py | 10 |
3 files changed, 77 insertions, 21 deletions
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py index 771c8c0559..cb3aab9b97 100644 --- a/lib/spack/spack/compilers/__init__.py +++ b/lib/spack/spack/compilers/__init__.py @@ -230,10 +230,15 @@ def compilers_for_spec(compiler_spec, arch_spec=None, scope=None, matches = set(find(compiler_spec, scope, init_config)) compilers = [] for cspec in matches: - compilers.extend(get_compilers(cspec, config, arch_spec)) + compilers.extend(get_compilers(config, cspec, arch_spec)) return compilers +def compilers_for_arch(arch_spec, scope=None): + config = all_compilers_config(scope) + return list(get_compilers(config, arch_spec=arch_spec)) + + def compiler_from_config_entry(items): cspec = spack.spec.CompilerSpec(items['spec']) os = items.get('operating_system', None) @@ -266,12 +271,12 @@ def compiler_from_config_entry(items): environment, extra_rpaths, **compiler_flags) -def get_compilers(cspec, config, arch_spec=None): +def get_compilers(config, cspec=None, arch_spec=None): compilers = [] for items in config: items = items['compiler'] - if items['spec'] != str(cspec): + if cspec and items['spec'] != str(cspec): continue # If an arch spec is given, confirm that this compiler diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 3d38f22cb6..126db8b780 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -315,11 +315,16 @@ class DefaultConcretizer(object): def _proper_compiler_style(cspec, aspec): return spack.compilers.compilers_for_spec(cspec, arch_spec=aspec) - all_compilers = spack.compilers.all_compiler_specs() + all_compiler_specs = spack.compilers.all_compiler_specs() + if not all_compiler_specs: + raise spack.compilers.NoCompilersError() if (spec.compiler and spec.compiler.concrete and - spec.compiler in all_compilers): + spec.compiler in all_compiler_specs): + if not _proper_compiler_style(spec.compiler, spec.architecture): + _compiler_concretization_failure( + spec.compiler, spec.architecture) return False # Find the another spec that has a compiler, or the root if none do @@ -332,22 +337,23 @@ class DefaultConcretizer(object): assert(other_spec) # Check if the compiler is already fully specified - if other_compiler in all_compilers: + if other_compiler in all_compiler_specs: spec.compiler = other_compiler.copy() + if not _proper_compiler_style(spec.compiler, spec.architecture): + _compiler_concretization_failure( + spec.compiler, spec.architecture) return True # Filter the compilers into a sorted list based on the compiler_order # from spackconfig - compiler_list = all_compilers if not other_compiler else \ + compiler_list = all_compiler_specs if not other_compiler else \ spack.compilers.find(other_compiler) + if not compiler_list: + # No compiler with a satisfactory spec was found + raise UnavailableCompilerVersionError(other_compiler) cmp_compilers = partial( pkgsort().compiler_compare, other_spec.name) matches = sorted(compiler_list, cmp=cmp_compilers) - if not matches: - arch = spec.architecture - raise UnavailableCompilerVersionError(other_compiler, - arch.platform_os, - arch.target) # copy concrete version into other_compiler try: @@ -355,10 +361,9 @@ class DefaultConcretizer(object): c for c in matches if _proper_compiler_style(c, spec.architecture)).copy() except StopIteration: - raise UnavailableCompilerVersionError( - spec.compiler, spec.architecture.platform_os, - spec.architecture.target - ) + # No compiler with a satisfactory spec has a suitable arch + _compiler_concretization_failure( + other_compiler, spec.architecture) assert(spec.compiler.concrete) return True # things changed. @@ -443,17 +448,53 @@ def find_spec(spec, condition): return None # Nothing matched the condition. +def _compiler_concretization_failure(compiler_spec, arch): + # Distinguish between the case that there are compilers for + # the arch but not with the given compiler spec and the case that + # there are no compilers for the arch at all + if not spack.compilers.compilers_for_arch(arch): + available_os_targets = set( + (c.operating_system, c.target) for c in + spack.compilers.all_compilers()) + raise NoCompilersForArchError(arch, available_os_targets) + else: + raise UnavailableCompilerVersionError(compiler_spec, arch) + + +class NoCompilersForArchError(spack.error.SpackError): + def __init__(self, arch, available_os_targets): + err_msg = ("No compilers found" + " for operating system %s and target %s." + "\nIf previous installations have succeeded, the" + " operating system may have been updated." % + (arch.platform_os, arch.target)) + + available_os_target_strs = list() + for os, t in available_os_targets: + os_target_str = "%s-%s" % (os, t) if t else os + available_os_target_strs.append(os_target_str) + err_msg += ( + "\nCompilers are defined for the following" + " operating systems and targets:\n\t" + + "\n\t".join(available_os_target_strs)) + + super(NoCompilersForArchError, self).__init__( + err_msg, "Run 'spack compiler find' to add compilers.") + + class UnavailableCompilerVersionError(spack.error.SpackError): """Raised when there is no available compiler that satisfies a compiler spec.""" - def __init__(self, compiler_spec, operating_system, target): + def __init__(self, compiler_spec, arch=None): + err_msg = "No compilers with spec %s found" % compiler_spec + if arch: + err_msg += (" for operating system %s and target %s." % + (compiler_spec, arch.platform_os, arch.target)) + super(UnavailableCompilerVersionError, self).__init__( - "No available compiler version matches '%s' on operating_system " - "'%s' for target '%s'" - % (compiler_spec, operating_system, target), - "Run 'spack compilers' to see available compiler Options.") + err_msg, "Run 'spack compiler find' to add compilers.") class NoValidVersionError(spack.error.SpackError): diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 0cb3a34a48..f4021a89ee 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -221,6 +221,16 @@ class TestConcretize(object): with pytest.raises(spack.spec.MultipleProviderError): s.concretize() + def test_no_matching_compiler_specs(self): + s = Spec('a %gcc@0.0.0') + with pytest.raises(spack.concretize.UnavailableCompilerVersionError): + s.concretize() + + def test_no_compilers_for_arch(self): + s = Spec('a arch=linux-rhel0-x86_64') + with pytest.raises(spack.concretize.NoCompilersForArchError): + s.concretize() + def test_virtual_is_fully_expanded_for_callpath(self): # force dependence on fake "zmpi" by asking for MPI 10.0 spec = Spec('callpath ^mpi@10.0') |