summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorscheibelp <scheibel1@llnl.gov>2017-03-16 21:08:13 -0700
committerbecker33 <becker33@llnl.gov>2017-03-16 21:08:13 -0700
commit0b27a7e13d5138ebf9b2d7510b1c16179e3b803c (patch)
treebf44388b698a5d99a54a31aebfb3b854fc667ae0 /lib
parent5936ad2ca78566fd13ad11081a75e333697b2065 (diff)
downloadspack-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__.py11
-rw-r--r--lib/spack/spack/concretize.py77
-rw-r--r--lib/spack/spack/test/concretize.py10
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')