Implemented compiler concretization policy.
This commit is contained in:
parent
c6956bc8e7
commit
45baf73c34
@ -34,7 +34,7 @@
|
||||
def compilers(parser, args):
|
||||
tty.msg("Available compilers")
|
||||
|
||||
index = index_by(spack.compilers.supported_compilers(), 'name')
|
||||
index = index_by(spack.compilers.available_compilers(), 'name')
|
||||
for name, compilers in index.items():
|
||||
tty.hline(name, char='-', color=spack.spec.compiler_color)
|
||||
colify(compilers, indent=4)
|
||||
|
@ -27,27 +27,34 @@
|
||||
#
|
||||
from llnl.util.lang import memoized, list_modules
|
||||
|
||||
import spack
|
||||
import spack.spec
|
||||
from spack.util.executable import which
|
||||
|
||||
|
||||
|
||||
@memoized
|
||||
def supported_compilers():
|
||||
"""Return a list of compiler types supported by Spack."""
|
||||
"""Return a list of names of compilers supported by Spack.
|
||||
|
||||
See available_compilers() to get a list of all the available
|
||||
versions of supported compilers.
|
||||
"""
|
||||
return sorted(c for c in list_modules(spack.compilers_path))
|
||||
|
||||
|
||||
def available_compilers():
|
||||
"""Return a list of specs for all the compiler versions currently
|
||||
available to build with. These are instances of
|
||||
spack.spec.Compiler.
|
||||
"""
|
||||
return [spack.spec.Compiler(c)
|
||||
for c in list_modules(spack.compiler_version_path)]
|
||||
|
||||
|
||||
def supported(compiler_spec):
|
||||
"""Test if a particular compiler is supported."""
|
||||
if isinstance(compiler_spec, spack.spec.Compiler):
|
||||
return compiler_spec.name in supported_compilers()
|
||||
|
||||
elif isinstance(compiler_spec, basestring):
|
||||
return compiler_spec in supported_compilers()
|
||||
|
||||
else:
|
||||
raise TypeError("compiler_spec must be string or spack.spec.Compiler")
|
||||
if not isinstance(compiler_spec, spack.spec.Compiler):
|
||||
compiler_spec = spack.spec.Compiler(compiler_spec)
|
||||
return compiler_spec.name in supported_compilers()
|
||||
|
||||
|
||||
@memoized
|
||||
|
@ -89,15 +89,11 @@ def concretize_architecture(self, spec):
|
||||
|
||||
|
||||
def concretize_compiler(self, spec):
|
||||
"""Currently just sets the compiler to gcc or throws an exception
|
||||
if the compiler is set to something else.
|
||||
|
||||
TODO: implement below description.
|
||||
|
||||
If the spec already has a compiler, we're done. If not, then
|
||||
take the compiler used for the nearest ancestor with a concrete
|
||||
compiler, or use the system default if there is no ancestor
|
||||
with a compiler.
|
||||
"""If the spec already has a compiler, we're done. If not, then take
|
||||
the compiler used for the nearest ancestor with a compiler
|
||||
spec and use that. If the ancestor's compiler is not
|
||||
concrete, then give it a valid version. If there is no
|
||||
ancestor with a compiler, use the system default compiler.
|
||||
|
||||
Intuition: Use the system default if no package that depends on
|
||||
this one has a strict compiler requirement. Otherwise, try to
|
||||
@ -105,10 +101,22 @@ def concretize_compiler(self, spec):
|
||||
link to this one, to maximize compatibility.
|
||||
"""
|
||||
if spec.compiler and spec.compiler.concrete:
|
||||
if spec.compiler != spack.compilers.default_compiler():
|
||||
raise spack.spec.UnknownCompilerError(str(spec.compiler))
|
||||
else:
|
||||
spec.compiler = spack.compilers.default_compiler()
|
||||
return
|
||||
|
||||
try:
|
||||
nearest = next(p for p in spec.preorder_traversal(direction='parents')
|
||||
if p.compiler is not None).compiler
|
||||
|
||||
if not nearest.concrete:
|
||||
matches = [c for c in spack.compilers.available_compilers()
|
||||
if c.name == nearest.name]
|
||||
nearest.versions = sorted(matches)[-1].versions.copy()
|
||||
assert(nearest.concrete)
|
||||
|
||||
spec.compiler = nearest.copy()
|
||||
|
||||
except StopIteration:
|
||||
spec.compiler = spack.compilers.default_compiler().copy()
|
||||
|
||||
|
||||
def choose_provider(self, spec, providers):
|
||||
|
@ -196,12 +196,20 @@ def _add_version(self, version):
|
||||
self.versions.add(version)
|
||||
|
||||
|
||||
def _autospec(self, compiler_spec_like):
|
||||
if not isinstance(compiler_spec_like, Compiler):
|
||||
return Compiler(compiler_spec_like)
|
||||
return compiler_spec_like
|
||||
|
||||
|
||||
def satisfies(self, other):
|
||||
other = self._autospec(other)
|
||||
return (self.name == other.name and
|
||||
self.versions.overlaps(other.versions))
|
||||
|
||||
|
||||
def constrain(self, other):
|
||||
other = self._autospec(other)
|
||||
if not self.satisfies(other):
|
||||
raise UnsatisfiableCompilerSpecError(self, other)
|
||||
|
||||
@ -374,14 +382,14 @@ def root(self):
|
||||
"""
|
||||
if not self.dependents:
|
||||
return self
|
||||
else:
|
||||
# If the spec has multiple dependents, ensure that they all
|
||||
# lead to the same place. Spack shouldn't deal with any DAGs
|
||||
# with multiple roots, so something's wrong if we find one.
|
||||
depiter = iter(self.dependents.values())
|
||||
first_root = next(depiter).root
|
||||
assert(all(first_root is d.root for d in depiter))
|
||||
return first_root
|
||||
|
||||
# If the spec has multiple dependents, ensure that they all
|
||||
# lead to the same place. Spack shouldn't deal with any DAGs
|
||||
# with multiple roots, so something's wrong if we find one.
|
||||
depiter = iter(self.dependents.values())
|
||||
first_root = next(depiter).root
|
||||
assert(all(first_root is d.root for d in depiter))
|
||||
return first_root
|
||||
|
||||
|
||||
@property
|
||||
@ -441,17 +449,28 @@ def preorder_traversal(self, visited=None, d=0, **kwargs):
|
||||
|
||||
root [=True]
|
||||
If false, this won't yield the root node, just its descendents.
|
||||
|
||||
direction [=children|parents]
|
||||
If 'children', does a traversal of this spec's children. If
|
||||
'parents', traverses upwards in the DAG towards the root.
|
||||
|
||||
"""
|
||||
depth = kwargs.get('depth', False)
|
||||
key_fun = kwargs.get('key', id)
|
||||
yield_root = kwargs.get('root', True)
|
||||
cover = kwargs.get('cover', 'nodes')
|
||||
direction = kwargs.get('direction', 'children')
|
||||
|
||||
cover_values = ('nodes', 'edges', 'paths')
|
||||
if cover not in cover_values:
|
||||
raise ValueError("Invalid value for cover: %s. Choices are %s"
|
||||
% (cover, ",".join(cover_values)))
|
||||
|
||||
direction_values = ('children', 'parents')
|
||||
if direction not in direction_values:
|
||||
raise ValueError("Invalid value for direction: %s. Choices are %s"
|
||||
% (direction, ",".join(direction_values)))
|
||||
|
||||
if visited is None:
|
||||
visited = set()
|
||||
|
||||
@ -465,9 +484,13 @@ def preorder_traversal(self, visited=None, d=0, **kwargs):
|
||||
else:
|
||||
if yield_root or d > 0: yield result
|
||||
|
||||
successors = self.dependencies
|
||||
if direction == 'parents':
|
||||
successors = self.dependents
|
||||
|
||||
visited.add(key)
|
||||
for name in sorted(self.dependencies):
|
||||
child = self.dependencies[name]
|
||||
for name in sorted(successors):
|
||||
child = successors[name]
|
||||
for elt in child.preorder_traversal(visited, d+1, **kwargs):
|
||||
yield elt
|
||||
|
||||
@ -776,7 +799,7 @@ def normalized(self):
|
||||
def validate_names(self):
|
||||
"""This checks that names of packages and compilers in this spec are real.
|
||||
If they're not, it will raise either UnknownPackageError or
|
||||
UnknownCompilerError.
|
||||
UnsupportedCompilerError.
|
||||
"""
|
||||
for spec in self.preorder_traversal():
|
||||
# Don't get a package for a virtual name.
|
||||
@ -786,7 +809,7 @@ def validate_names(self):
|
||||
# validate compiler in addition to the package name.
|
||||
if spec.compiler:
|
||||
if not spack.compilers.supported(spec.compiler):
|
||||
raise UnknownCompilerError(spec.compiler)
|
||||
raise UnsupportedCompilerError(spec.compiler.name)
|
||||
|
||||
|
||||
def constrain(self, other, **kwargs):
|
||||
@ -1385,11 +1408,11 @@ def __init__(self, message):
|
||||
super(DuplicateCompilerError, self).__init__(message)
|
||||
|
||||
|
||||
class UnknownCompilerError(SpecError):
|
||||
class UnsupportedCompilerError(SpecError):
|
||||
"""Raised when the user asks for a compiler spack doesn't know about."""
|
||||
def __init__(self, compiler_name):
|
||||
super(UnknownCompilerError, self).__init__(
|
||||
"Unknown compiler: %s" % compiler_name)
|
||||
super(UnsupportedCompilerError, self).__init__(
|
||||
"The '%s' compiler is not yet supported." % compiler_name)
|
||||
|
||||
|
||||
class DuplicateArchitectureError(SpecError):
|
||||
|
@ -25,7 +25,7 @@
|
||||
import unittest
|
||||
|
||||
import spack
|
||||
from spack.spec import Spec
|
||||
from spack.spec import Spec, Compiler
|
||||
from spack.test.mock_packages_test import *
|
||||
|
||||
class ConcretizeTest(MockPackagesTest):
|
||||
@ -163,3 +163,15 @@ def test_my_dep_depends_on_provider_of_my_virtual_dep(self):
|
||||
spec = Spec('indirect_mpich')
|
||||
spec.normalize()
|
||||
spec.concretize()
|
||||
|
||||
|
||||
def test_compiler_inheritance(self):
|
||||
spec = Spec('mpileaks')
|
||||
spec.normalize()
|
||||
|
||||
spec['dyninst'].compiler = Compiler('clang')
|
||||
spec.concretize()
|
||||
|
||||
# TODO: not exactly the syntax I would like.
|
||||
self.assertTrue(spec['libdwarf'].compiler.satisfies('clang'))
|
||||
self.assertTrue(spec['libelf'].compiler.satisfies('clang'))
|
||||
|
Loading…
Reference in New Issue
Block a user