summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2014-05-07 20:01:12 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2014-06-22 12:33:49 -0700
commit45baf73c349465cce9c82db48777f2b8a853caa5 (patch)
treede5e47b6d21dd1bc883cdcee7fd29035c6f35d46
parentc6956bc8e7b9d1261b71d09adaad570bdf7d9bd6 (diff)
downloadspack-45baf73c349465cce9c82db48777f2b8a853caa5.tar.gz
spack-45baf73c349465cce9c82db48777f2b8a853caa5.tar.bz2
spack-45baf73c349465cce9c82db48777f2b8a853caa5.tar.xz
spack-45baf73c349465cce9c82db48777f2b8a853caa5.zip
Implemented compiler concretization policy.
-rw-r--r--lib/spack/spack/cmd/compilers.py2
-rw-r--r--lib/spack/spack/compilers/__init__.py29
-rw-r--r--lib/spack/spack/concretize.py34
-rw-r--r--lib/spack/spack/spec.py53
-rw-r--r--lib/spack/spack/test/concretize.py14
5 files changed, 91 insertions, 41 deletions
diff --git a/lib/spack/spack/cmd/compilers.py b/lib/spack/spack/cmd/compilers.py
index 5658263c26..8267ecbd6b 100644
--- a/lib/spack/spack/cmd/compilers.py
+++ b/lib/spack/spack/cmd/compilers.py
@@ -34,7 +34,7 @@ description = "List available compilers"
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)
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index 4bfb855d94..2b97cd1036 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -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 supported(compiler_spec):
- """Test if a particular compiler is supported."""
- if isinstance(compiler_spec, spack.spec.Compiler):
- return compiler_spec.name in supported_compilers()
+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)]
- elif isinstance(compiler_spec, basestring):
- return compiler_spec in supported_compilers()
- else:
- raise TypeError("compiler_spec must be string or spack.spec.Compiler")
+def supported(compiler_spec):
+ """Test if a particular compiler is supported."""
+ if not isinstance(compiler_spec, spack.spec.Compiler):
+ compiler_spec = spack.spec.Compiler(compiler_spec)
+ return compiler_spec.name in supported_compilers()
@memoized
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index fc360d59ba..8679d3e13e 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -89,15 +89,11 @@ class DefaultConcretizer(object):
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 @@ class DefaultConcretizer(object):
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):
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index bb8965ccc8..d0b08cca00 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -196,12 +196,20 @@ class Compiler(object):
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 @@ class Spec(object):
"""
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 @@ class Spec(object):
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 @@ class Spec(object):
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 @@ class Spec(object):
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 @@ class Spec(object):
# 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 @@ class DuplicateCompilerError(SpecError):
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):
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 62e2732749..2a989f6766 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -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 @@ class ConcretizeTest(MockPackagesTest):
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'))