summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2014-05-19 16:07:42 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2014-06-22 12:49:34 -0700
commitf78475711343a98b1f0e756d6c39df87802c25c8 (patch)
tree5da8229e1c885af863b6b29fa7bcebbdf3119c55
parented6454fe78c8de2efb08d3c85e41fddd6fe704fb (diff)
downloadspack-f78475711343a98b1f0e756d6c39df87802c25c8.tar.gz
spack-f78475711343a98b1f0e756d6c39df87802c25c8.tar.bz2
spack-f78475711343a98b1f0e756d6c39df87802c25c8.tar.xz
spack-f78475711343a98b1f0e756d6c39df87802c25c8.zip
Initial ability to swap compilers.
Fixes SPACK-16 and forces compiler script to build using compiler wrappers. - works with gcc and clang on laptop.
-rwxr-xr-xbin/spack3
-rwxr-xr-xlib/spack/env/cc47
-rw-r--r--lib/spack/spack/build_environment.py29
-rw-r--r--lib/spack/spack/cmd/compilers.py2
-rw-r--r--lib/spack/spack/cmd/find.py2
-rw-r--r--lib/spack/spack/cmd/install.py6
-rw-r--r--lib/spack/spack/cmd/uninstall.py19
-rw-r--r--lib/spack/spack/compiler.py10
-rw-r--r--lib/spack/spack/compilers/__init__.py64
-rw-r--r--lib/spack/spack/compilers/clang.py6
-rw-r--r--lib/spack/spack/compilers/gcc.py6
-rw-r--r--lib/spack/spack/compilers/intel.py6
-rw-r--r--lib/spack/spack/concretize.py24
-rw-r--r--lib/spack/spack/package.py14
-rw-r--r--lib/spack/spack/spec.py41
-rw-r--r--lib/spack/spack/test/spec_semantics.py36
-rw-r--r--lib/spack/spack/test/versions.py30
-rw-r--r--lib/spack/spack/util/executable.py2
-rw-r--r--var/spack/packages/libdwarf/package.py2
19 files changed, 231 insertions, 118 deletions
diff --git a/bin/spack b/bin/spack
index fb9f045f35..fef793a6ce 100755
--- a/bin/spack
+++ b/bin/spack
@@ -41,7 +41,7 @@ sys.path.insert(0, SPACK_LIB_PATH)
# If there is no working directory, use the spack prefix.
try:
- os.getcwd()
+ working_dir = os.getcwd()
except OSError:
os.chdir(SPACK_PREFIX)
@@ -79,6 +79,7 @@ args = parser.parse_args()
# Set up environment based on args.
spack.verbose = args.verbose
spack.debug = args.debug
+spack.spack_working_dir = working_dir
if args.mock:
from spack.packages import PackageDB
spack.db = PackageDB(spack.mock_packages_path)
diff --git a/lib/spack/env/cc b/lib/spack/env/cc
index e5dbf21beb..09abf3a31d 100755
--- a/lib/spack/env/cc
+++ b/lib/spack/env/cc
@@ -10,7 +10,7 @@ import argparse
from contextlib import closing
# Import spack parameters through the build environment.
-spack_lib = os.environ.get("SPACK_LIB")
+spack_lib = os.environ.get("SPACK_LIB")
if not spack_lib:
print "Spack compiler must be run from spack!"
sys.exit(1)
@@ -20,24 +20,23 @@ sys.path.append(spack_lib)
from spack.compilation import *
import llnl.util.tty as tty
-spack_prefix = get_env_var("SPACK_PREFIX")
-spack_build_root = get_env_var("SPACK_BUILD_ROOT")
-spack_debug = get_env_flag("SPACK_DEBUG")
-spack_deps = get_path("SPACK_DEPENDENCIES")
-spack_env_path = get_path("SPACK_ENV_PATH")
+spack_prefix = get_env_var("SPACK_PREFIX")
+spack_debug = get_env_flag("SPACK_DEBUG")
+spack_deps = get_path("SPACK_DEPENDENCIES")
+spack_env_path = get_path("SPACK_ENV_PATH")
+spack_debug_log_dir = get_env_var("SPACK_DEBUG_LOG_DIR")
+spack_spec = get_env_var("SPACK_SPEC")
+
+spack_cc = get_env_var("SPACK_CC")
+spack_cxx = get_env_var("SPACK_CXX")
+spack_f77 = get_env_var("SPACK_F77")
+spack_fc = get_env_var("SPACK_FC")
# Figure out what type of operation we're doing
command = os.path.basename(sys.argv[0])
cpp, cc, ccld, ld, version_check = range(5)
-########################################################################
-# TODO: this can to be removed once JIRA issue SPACK-16 is resolved
-#
-if command == 'CC':
- command = 'c++'
-########################################################################
-
if command == 'cpp':
mode = cpp
elif command == 'ld':
@@ -49,7 +48,23 @@ elif '-c' in sys.argv:
else:
mode = ccld
-if '-V' in sys.argv or '-v' in sys.argv or '--version' in sys.argv:
+
+if command in ('cc', 'gcc', 'c89', 'c99', 'clang'):
+ command = spack_cc
+elif command in ('c++', 'CC', 'g++', 'clang++'):
+ command = spack_cxx
+elif command in ('f77'):
+ command = spack_f77
+elif command in ('fc'):
+ command = spack_fc
+elif command in ('ld', 'cpp'):
+ pass # leave it the same. TODO: what's the right thing?
+else:
+ raise Exception("Unknown compiler: %s" % command)
+
+
+version_args = ['-V', '-v', '--version', '-dumpversion']
+if any(arg in sys.argv for arg in version_args):
mode = version_check
# Parse out the includes, libs, etc. so we can adjust them if need be.
@@ -104,8 +119,8 @@ os.environ["PATH"] = ":".join(path)
full_command = [command] + arguments
if spack_debug:
- input_log = os.path.join(spack_build_root, 'spack_cc_in.log')
- output_log = os.path.join(spack_build_root, 'spack_cc_out.log')
+ input_log = os.path.join(spack_debug_log_dir, 'spack-cc-%s.in.log' % spack_spec)
+ output_log = os.path.join(spack_debug_log_dir, 'spack-cc-%s.out.log' % spack_spec)
with closing(open(input_log, 'a')) as log:
args = [os.path.basename(sys.argv[0])] + sys.argv[1:]
log.write("%s\n" % " ".join(arg.replace(' ', r'\ ') for arg in args))
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 8d3d0909db..36dae74e84 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -34,7 +34,7 @@ import platform
from llnl.util.filesystem import *
import spack
-from spack.compilers import compiler_for_spec
+import spack.compilers as compilers
from spack.util.executable import Executable, which
from spack.util.environment import *
@@ -52,7 +52,9 @@ SPACK_LIB = 'SPACK_LIB'
SPACK_ENV_PATH = 'SPACK_ENV_PATH'
SPACK_DEPENDENCIES = 'SPACK_DEPENDENCIES'
SPACK_PREFIX = 'SPACK_PREFIX'
-SPACK_BUILD_ROOT = 'SPACK_BUILD_ROOT'
+SPACK_DEBUG = 'SPACK_DEBUG'
+SPACK_SPEC = 'SPACK_SPEC'
+SPACK_DEBUG_LOG_DIR = 'SPACK_DEBUG_LOG_DIR'
class MakeExecutable(Executable):
@@ -82,7 +84,19 @@ class MakeExecutable(Executable):
def set_compiler_environment_variables(pkg):
assert(pkg.spec.concrete)
- compiler = compiler_for_spec(pkg.spec.compiler)
+ compiler = compilers.compiler_for_spec(pkg.spec.compiler)
+
+ # Set compiler variables used by CMake and autotools
+ os.environ['CC'] = 'cc'
+ os.environ['CXX'] = 'c++'
+ os.environ['F77'] = 'f77'
+ os.environ['FC'] = 'fc'
+
+ # Set SPACK compiler variables so that our wrapper knows what to call
+ os.environ['SPACK_CC'] = compiler.cc.command
+ os.environ['SPACK_CXX'] = compiler.cxx.command
+ os.environ['SPACK_F77'] = compiler.f77.command
+ os.environ['SPACK_FC'] = compiler.fc.command
def set_build_environment_variables(pkg):
@@ -108,9 +122,6 @@ def set_build_environment_variables(pkg):
# Install prefix
os.environ[SPACK_PREFIX] = pkg.prefix
- # Build root for logging.
- os.environ[SPACK_BUILD_ROOT] = pkg.stage.expanded_archive_path
-
# Remove these vars from the environment during build becaus they
# can affect how some packages find libraries. We want to make
# sure that builds never pull in unintended external dependencies.
@@ -120,6 +131,12 @@ def set_build_environment_variables(pkg):
bin_dirs = ['%s/bin' % prefix for prefix in dep_prefixes]
path_put_first('PATH', [bin for bin in bin_dirs if os.path.isdir(bin)])
+ # Working directory for the spack command itself, for debug logs.
+ if spack.debug:
+ os.environ[SPACK_DEBUG] = "TRUE"
+ os.environ[SPACK_SPEC] = str(pkg.spec)
+ os.environ[SPACK_DEBUG_LOG_DIR] = spack.spack_working_dir
+
def set_module_variables_for_package(pkg):
"""Populate the module scope of install() with some useful functions.
diff --git a/lib/spack/spack/cmd/compilers.py b/lib/spack/spack/cmd/compilers.py
index 8267ecbd6b..c34118f033 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.available_compilers(), 'name')
+ index = index_by(spack.compilers.all_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/cmd/find.py b/lib/spack/spack/cmd/find.py
index eaa3632043..08cfb5af96 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -62,7 +62,7 @@ def find(parser, args):
# Make a dict with specs keyed by architecture and compiler.
specs = [s for s in spack.db.installed_package_specs()
- if not query_specs or any(spec.satisfies(q) for q in query_specs)]
+ if not query_specs or any(s.satisfies(q) for q in query_specs)]
index = index_by(specs, 'architecture', 'compiler')
# Traverse the index and print out each package
diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py
index ea11cb89a9..4570d6c40f 100644
--- a/lib/spack/spack/cmd/install.py
+++ b/lib/spack/spack/cmd/install.py
@@ -36,7 +36,10 @@ def setup_parser(subparser):
help="Do not try to install dependencies of requested packages.")
subparser.add_argument(
'--keep-prefix', action='store_true', dest='keep_prefix',
- help="Don't clean up staging area when install completes.")
+ help="Don't remove the install prefix if installation fails.")
+ subparser.add_argument(
+ '--keep-stage', action='store_true', dest='keep_stage',
+ help="Don't remove the build stage if installation succeeds.")
subparser.add_argument(
'-n', '--no-checksum', action='store_true', dest='no_checksum',
help="Do not check packages against checksum")
@@ -55,4 +58,5 @@ def install(parser, args):
for spec in specs:
package = spack.db.get(spec)
package.do_install(keep_prefix=args.keep_prefix,
+ keep_stage=args.keep_stage,
ignore_deps=args.ignore_deps)
diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py
index df208b3a6a..044a9b2960 100644
--- a/lib/spack/spack/cmd/uninstall.py
+++ b/lib/spack/spack/cmd/uninstall.py
@@ -36,6 +36,11 @@ def setup_parser(subparser):
'-f', '--force', action='store_true', dest='force',
help="Remove regardless of whether other packages depend on this one.")
subparser.add_argument(
+ '-a', '--all', action='store_true', dest='all',
+ help="USE CAREFULLY. Remove ALL installed packages that match each supplied spec. " +
+ "i.e., if you say uninstall libelf, ALL versions of libelf are uninstalled. " +
+ "This is both useful and dangerous, like rm -r.")
+ subparser.add_argument(
'packages', nargs=argparse.REMAINDER, help="specs of packages to uninstall")
@@ -50,15 +55,17 @@ def uninstall(parser, args):
pkgs = []
for spec in specs:
matching_specs = spack.db.get_installed(spec)
- if len(matching_specs) > 1:
- tty.die("%s matches multiple packages. Which one did you mean?"
- % spec, *matching_specs)
+ if not args.all and len(matching_specs) > 1:
+ tty.die("%s matches multiple packages." % spec,
+ "You can either:",
+ " a) Use spack uninstall -a to uninstall ALL matching specs, or",
+ " b) use a more specific spec.",
+ "Matching packages:", *(" " + str(s) for s in matching_specs))
- elif len(matching_specs) == 0:
+ if len(matching_specs) == 0:
tty.die("%s does not match any installed packages." % spec)
- installed_spec = matching_specs[0]
- pkgs.append(spack.db.get(installed_spec))
+ pkgs.extend(spack.db.get(s) for s in matching_specs)
# Sort packages to be uninstalled by the number of installed dependents
# This ensures we do things in the right order
diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py
index 27effa20c4..3d097b6180 100644
--- a/lib/spack/spack/compiler.py
+++ b/lib/spack/spack/compiler.py
@@ -16,7 +16,7 @@ def _verify_executables(*paths):
class Compiler(object):
"""This class encapsulates a Spack "compiler", which includes C,
- C++, Fortran, and F90 compilers. Subclasses should implement
+ C++, and Fortran compilers. Subclasses should implement
support for specific compilers, their possible names, arguments,
and how to identify the particular type of compiler."""
@@ -30,20 +30,20 @@ class Compiler(object):
f77_names = []
# Subclasses use possible names of Fortran 90 compiler
- f90_names = []
+ fc_names = []
# Names of generic arguments used by this compiler
arg_version = '-dumpversion'
arg_rpath = '-Wl,-rpath,%s'
- def __init__(self, cc, cxx, f77, f90):
- _verify_executables(cc, cxx, f77, f90)
+ def __init__(self, cc, cxx, f77, fc):
+ _verify_executables(cc, cxx, f77, fc)
self.cc = Executable(cc)
self.cxx = Executable(cxx)
self.f77 = Executable(f77)
- self.f90 = Executable(f90)
+ self.fc = Executable(fc)
@property
@memoized
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index 095e26edb5..a36ea618bc 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -41,49 +41,69 @@ _imported_compilers_module = 'spack.compiler.versions'
_imported_versions_module = 'spack.compilers'
+def _auto_compiler_spec(function):
+ def converter(cspec_like):
+ if not isinstance(cspec_like, spack.spec.CompilerSpec):
+ cspec_like = spack.spec.CompilerSpec(cspec_like)
+ return function(cspec_like)
+ return converter
+
+
@memoized
def supported_compilers():
- """Return a list of names of compilers supported by Spack.
+ """Return a set 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))
+ return sorted(name for name in list_modules(spack.compilers_path))
+@_auto_compiler_spec
def supported(compiler_spec):
"""Test if a particular compiler is supported."""
- if not isinstance(compiler_spec, spack.spec.CompilerSpec):
- compiler_spec = spack.spec.CompilerSpec(compiler_spec)
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
- CompilerSpec.
+@memoized
+def all_compilers():
+ """Return a set of specs for all the compiler versions currently
+ available to build with. These are instances of CompilerSpec.
"""
- return [spack.spec.CompilerSpec(c)
- for c in list_modules(spack.compiler_version_path)]
+ return set(spack.spec.CompilerSpec(c)
+ for c in list_modules(spack.compiler_version_path))
-def compiler_for_spec(compiler_spec):
- """This gets an instance of an actual spack.compiler.Compiler object
- from a compiler spec. The spec needs to be concrete for this to
- work; it will raise an error if passed an abstract compiler.
+@_auto_compiler_spec
+def find(compiler_spec):
+ """Return specs of available compilers that match the supplied
+ compiler spec. Return an list if nothing found."""
+ return [c for c in all_compilers() if c.satisfies(compiler_spec)]
+
+
+@_auto_compiler_spec
+def compilers_for_spec(compiler_spec):
+ """This gets all compilers that satisfy the supplied CompilerSpec.
+ Returns an empty list if none are found.
"""
- matches = [c for c in available_compilers() if c.satisfies(compiler_spec)]
+ matches = find(compiler_spec)
- # TODO: do something when there are zero matches.
- assert(len(matches) >= 1)
+ compilers = []
+ for cspec in matches:
+ path = join_path(spack.compiler_version_path, "%s.py" % cspec)
+ mod = imp.load_source(_imported_versions_module, path)
+ cls = class_for_compiler_name(cspec.name)
+ compilers.append(cls(mod.cc, mod.cxx, mod.f77, mod.fc))
- compiler = matches[0]
- file_path = join_path(spack.compiler_version_path, "%s.py" % compiler)
+ return compilers
- mod = imp.load_source(_imported_versions_module, file_path)
- compiler_class = class_for_compiler_name(compiler.name)
- return compiler_class(mod.cc, mod.cxx, mod.f77, mod.f90)
+@_auto_compiler_spec
+def compiler_for_spec(compiler_spec):
+ assert(compiler_spec.concrete)
+ compilers = compilers_for_spec(compiler_spec)
+ assert(len(compilers) == 1)
+ return compilers[0]
def class_for_compiler_name(compiler_name):
diff --git a/lib/spack/spack/compilers/clang.py b/lib/spack/spack/compilers/clang.py
index 9ed7b57846..1616fcaf08 100644
--- a/lib/spack/spack/compilers/clang.py
+++ b/lib/spack/spack/compilers/clang.py
@@ -35,7 +35,7 @@ class Clang(Compiler):
f77_names = []
# Subclasses use possible names of Fortran 90 compiler
- f90_names = []
+ fc_names = []
- def __init__(self, cc, cxx, f77, f90):
- super(Gcc, self).__init__(cc, cxx, f77, f90)
+ def __init__(self, cc, cxx, f77, fc):
+ super(Clang, self).__init__(cc, cxx, f77, fc)
diff --git a/lib/spack/spack/compilers/gcc.py b/lib/spack/spack/compilers/gcc.py
index 638051008f..f73cb08c63 100644
--- a/lib/spack/spack/compilers/gcc.py
+++ b/lib/spack/spack/compilers/gcc.py
@@ -35,7 +35,7 @@ class Gcc(Compiler):
f77_names = ['gfortran']
# Subclasses use possible names of Fortran 90 compiler
- f90_names = ['gfortran']
+ fc_names = ['gfortran']
- def __init__(self, cc, cxx, f77, f90):
- super(Gcc, self).__init__(cc, cxx, f77, f90)
+ def __init__(self, cc, cxx, f77, fc):
+ super(Gcc, self).__init__(cc, cxx, f77, fc)
diff --git a/lib/spack/spack/compilers/intel.py b/lib/spack/spack/compilers/intel.py
index ebbab57ed1..fe2aabd864 100644
--- a/lib/spack/spack/compilers/intel.py
+++ b/lib/spack/spack/compilers/intel.py
@@ -35,7 +35,7 @@ class Intel(Compiler):
f77_names = ['ifort']
# Subclasses use possible names of Fortran 90 compiler
- f90_names = ['ifort']
+ fc_names = ['ifort']
- def __init__(self, cc, cxx, f77, f90):
- super(Gcc, self).__init__(cc, cxx, f77, f90)
+ def __init__(self, cc, cxx, f77, fc):
+ super(Intel, self).__init__(cc, cxx, f77, fc)
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index 28efcaea64..312b9ce1b1 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -33,9 +33,10 @@ or user preferences.
TODO: make this customizable and allow users to configure
concretization policies.
"""
-import spack.architecture
-import spack.compilers
import spack.spec
+import spack.compilers
+import spack.architecture
+import spack.error
from spack.version import *
@@ -117,9 +118,13 @@ class DefaultConcretizer(object):
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()
+ # Take the newest compiler that saisfies the spec
+ matches = sorted(spack.compilers.find(nearest))
+ if not matches:
+ raise UnavailableCompilerVersionError(nearest)
+
+ # copy concrete version into nearest spec
+ nearest.versions = matches[-1].versions.copy()
assert(nearest.concrete)
spec.compiler = nearest.copy()
@@ -140,3 +145,12 @@ class DefaultConcretizer(object):
first_key = sorted(index.keys())[0]
latest_version = sorted(index[first_key])[-1]
return latest_version
+
+
+class UnavailableCompilerVersionError(spack.error.SpackError):
+ """Raised when there is no available compiler that satisfies a
+ compiler spec."""
+ def __init__(self, compiler_spec):
+ super(UnavailableCompilerVersionError, self).__init__(
+ "No available compiler version matches '%s'" % compiler_spec,
+ "Run 'spack compilers' to see available compiler Options.")
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index b40448df37..069c66f4a7 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -626,6 +626,7 @@ class Package(object):
"""
# whether to keep the prefix on failure. Default is to destroy it.
keep_prefix = kwargs.get('keep_prefix', False)
+ keep_stage = kwargs.get('keep_stage', False)
ignore_deps = kwargs.get('ignore_deps', False)
if not self.spec.concrete:
@@ -671,9 +672,10 @@ class Package(object):
"Install failed for %s. Nothing was installed!"
% self.name)
- # On successful install, remove the stage.
- # Leave if there is an error
- self.stage.destroy()
+ if not keep_stage:
+ # On successful install, remove the stage.
+ # Leave it if there is an error
+ self.stage.destroy()
tty.msg("Successfully installed %s" % self.name)
print_pkg(self.prefix)
@@ -725,16 +727,16 @@ class Package(object):
force = kwargs.get('force', False)
if not self.installed:
- raise InstallError(self.name + " is not installed.")
+ raise InstallError(self.spec + " is not installed.")
if not force:
deps = self.installed_dependents
if deps: raise InstallError(
"Cannot uninstall %s. The following installed packages depend on it: %s"
- % (self.name, deps))
+ % (self.spec, deps))
self.remove_prefix()
- tty.msg("Successfully uninstalled %s." % self.name)
+ tty.msg("Successfully uninstalled %s." % self.spec)
def do_clean(self):
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 35a17621b6..5848ac2000 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -102,7 +102,7 @@ from llnl.util.tty.color import *
import spack
import spack.parse
import spack.error
-from spack.compilers import supported as supported_compiler
+import spack.compilers as compilers
from spack.version import *
from spack.util.string import *
@@ -231,8 +231,9 @@ class CompilerSpec(object):
@property
def concrete(self):
- """A CompilerSpec is concrete if its versions are concrete."""
- return self.versions.concrete
+ """A CompilerSpec is concrete if its versions are concrete and there
+ is an available compiler with the right version."""
+ return self.versions.concrete and self in compilers.all_compilers()
@property
@@ -260,6 +261,9 @@ class CompilerSpec(object):
out += "@%s" % vlist
return out
+ def __repr__(self):
+ return str(self)
+
@key_ordering
class Variant(object):
@@ -821,12 +825,13 @@ class Spec(object):
# validate compiler in addition to the package name.
if spec.compiler:
- if not supported_compiler(spec.compiler):
+ if not compilers.supported(spec.compiler):
raise UnsupportedCompilerError(spec.compiler.name)
def constrain(self, other, **kwargs):
other = self._autospec(other)
+ constrain_deps = kwargs.get('deps', True)
if not self.name == other.name:
raise UnsatisfiableSpecNameError(self.name, other.name)
@@ -854,7 +859,7 @@ class Spec(object):
self.variants.update(other.variants)
self.architecture = self.architecture or other.architecture
- if kwargs.get('deps', True):
+ if constrain_deps:
self._constrain_dependencies(other)
@@ -911,28 +916,28 @@ class Spec(object):
def satisfies(self, other, **kwargs):
other = self._autospec(other)
+ satisfy_deps = kwargs.get('deps', True)
# First thing we care about is whether the name matches
if self.name != other.name:
return False
- # This function simplifies null checking below
- def check(attribute, op):
- s = getattr(self, attribute)
- o = getattr(other, attribute)
- return not s or not o or op(s,o)
-
- # All these attrs have satisfies criteria of their own
- for attr in ('versions', 'variants', 'compiler'):
- if not check(attr, lambda s, o: s.satisfies(o)):
+ # All these attrs have satisfies criteria of their own,
+ # but can be None to indicate no constraints.
+ for s, o in ((self.versions, other.versions),
+ (self.variants, other.variants),
+ (self.compiler, other.compiler)):
+ if s and o and not s.satisfies(o):
return False
- # Architecture is just a string
- # TODO: inviestigate making an Architecture class for symmetry
- if not check('architecture', lambda s,o: s == o):
+ # Architecture satisfaction is currently just string equality.
+ # Can be None for unconstrained, though.
+ if (self.architecture and other.architecture and
+ self.architecture != other.architecture):
return False
- if kwargs.get('deps', True):
+ # If we need to descend into dependencies, do it, otherwise we're done.
+ if satisfy_deps:
return self.satisfies_dependencies(other)
else:
return True
diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py
index dbd04f9449..5fb09e68af 100644
--- a/lib/spack/spack/test/spec_semantics.py
+++ b/lib/spack/spack/test/spec_semantics.py
@@ -37,16 +37,13 @@ class SpecSematicsTest(MockPackagesTest):
left = Spec(spec)
right = parse_anonymous_spec(anon_spec, left.name)
+ # Satisfies is one-directional.
self.assertTrue(left.satisfies(right))
self.assertTrue(left.satisfies(anon_spec))
- self.assertTrue(right.satisfies(left))
- try:
- left.copy().constrain(right)
- left.copy().constrain(anon_spec)
- right.copy().constrain(left)
- except SpecError, e:
- self.fail("Got a SpecError in constrain! " + e.message)
+ # if left satisfies right, then we should be able to consrain
+ # right by left. Reverse is not always true.
+ right.copy().constrain(left)
def check_unsatisfiable(self, spec, anon_spec):
@@ -56,25 +53,21 @@ class SpecSematicsTest(MockPackagesTest):
self.assertFalse(left.satisfies(right))
self.assertFalse(left.satisfies(anon_spec))
- self.assertFalse(right.satisfies(left))
+ self.assertRaises(UnsatisfiableSpecError, right.copy().constrain, left)
- self.assertRaises(UnsatisfiableSpecError, left.constrain, right)
- self.assertRaises(UnsatisfiableSpecError, left.constrain, anon_spec)
- self.assertRaises(UnsatisfiableSpecError, right.constrain, left)
-
- def check_constrain(self, expected, constrained, constraint):
+ def check_constrain(self, expected, spec, constraint):
exp = Spec(expected)
- constrained = Spec(constrained)
+ spec = Spec(spec)
constraint = Spec(constraint)
- constrained.constrain(constraint)
- self.assertEqual(exp, constrained)
+ spec.constrain(constraint)
+ self.assertEqual(exp, spec)
- def check_invalid_constraint(self, constrained, constraint):
- constrained = Spec(constrained)
+ def check_invalid_constraint(self, spec, constraint):
+ spec = Spec(spec)
constraint = Spec(constraint)
- self.assertRaises(UnsatisfiableSpecError, constrained.constrain, constraint)
+ self.assertRaises(UnsatisfiableSpecError, spec.constrain, constraint)
# ================================================================================
@@ -177,3 +170,8 @@ class SpecSematicsTest(MockPackagesTest):
self.check_invalid_constraint('libelf+debug~foo', 'libelf+debug+foo')
self.check_invalid_constraint('libelf=bgqos_0', 'libelf=x86_54')
+
+
+ def test_compiler_satisfies(self):
+ self.check_satisfies('foo %gcc@4.7.3', '%gcc@4.7')
+ self.check_unsatisfiable('foo %gcc@4.7', '%gcc@4.7.3')
diff --git a/lib/spack/spack/test/versions.py b/lib/spack/spack/test/versions.py
index e272274a4f..454ab36b8a 100644
--- a/lib/spack/spack/test/versions.py
+++ b/lib/spack/spack/test/versions.py
@@ -311,7 +311,7 @@ class VersionsTest(unittest.TestCase):
self.check_intersection(['0:1'], [':'], ['0:1'])
- def test_satisfaction(self):
+ def test_basic_version_satisfaction(self):
self.assert_satisfies('4.7.3', '4.7.3')
self.assert_satisfies('4.7.3', '4.7')
@@ -326,6 +326,22 @@ class VersionsTest(unittest.TestCase):
self.assert_does_not_satisfy('4.8', '4.9')
self.assert_does_not_satisfy('4', '4.9')
+ def test_basic_version_satisfaction_in_lists(self):
+ self.assert_satisfies(['4.7.3'], ['4.7.3'])
+
+ self.assert_satisfies(['4.7.3'], ['4.7'])
+ self.assert_satisfies(['4.7.3b2'], ['4.7'])
+ self.assert_satisfies(['4.7b6'], ['4.7'])
+
+ self.assert_satisfies(['4.7.3'], ['4'])
+ self.assert_satisfies(['4.7.3b2'], ['4'])
+ self.assert_satisfies(['4.7b6'], ['4'])
+
+ self.assert_does_not_satisfy(['4.8.0'], ['4.9'])
+ self.assert_does_not_satisfy(['4.8'], ['4.9'])
+ self.assert_does_not_satisfy(['4'], ['4.9'])
+
+ def test_version_range_satisfaction(self):
self.assert_satisfies('4.7b6', '4.3:4.7')
self.assert_satisfies('4.3.0', '4.3:4.7')
self.assert_satisfies('4.3.2', '4.3:4.7')
@@ -336,6 +352,18 @@ class VersionsTest(unittest.TestCase):
self.assert_satisfies('4.7b6', '4.3:4.7')
self.assert_does_not_satisfy('4.8.0', '4.3:4.7')
+ def test_version_range_satisfaction_in_lists(self):
+ self.assert_satisfies(['4.7b6'], ['4.3:4.7'])
+ self.assert_satisfies(['4.3.0'], ['4.3:4.7'])
+ self.assert_satisfies(['4.3.2'], ['4.3:4.7'])
+
+ self.assert_does_not_satisfy(['4.8.0'], ['4.3:4.7'])
+ self.assert_does_not_satisfy(['4.3'], ['4.4:4.7'])
+
+ self.assert_satisfies(['4.7b6'], ['4.3:4.7'])
+ self.assert_does_not_satisfy(['4.8.0'], ['4.3:4.7'])
+
+ def test_satisfaction_with_lists(self):
self.assert_satisfies('4.7', '4.3, 4.6, 4.7')
self.assert_satisfies('4.7.3', '4.3, 4.6, 4.7')
self.assert_satisfies('4.6.5', '4.3, 4.6, 4.7')
diff --git a/lib/spack/spack/util/executable.py b/lib/spack/spack/util/executable.py
index 845d1470e7..6dea46a5c8 100644
--- a/lib/spack/spack/util/executable.py
+++ b/lib/spack/spack/util/executable.py
@@ -43,7 +43,7 @@ class Executable(object):
@property
def command(self):
- return self.exe[0]
+ return ' '.join(self.exe)
def __call__(self, *args, **kwargs):
diff --git a/var/spack/packages/libdwarf/package.py b/var/spack/packages/libdwarf/package.py
index 657e84705a..000187736c 100644
--- a/var/spack/packages/libdwarf/package.py
+++ b/var/spack/packages/libdwarf/package.py
@@ -39,6 +39,8 @@ class Libdwarf(Package):
depends_on("libelf")
+ parallel = False
+
def clean(self):
for dir in dwarf_dirs: