Initial ability to swap compilers.
Fixes SPACK-16 and forces compiler script to build using compiler wrappers. - works with gcc and clang on laptop.
This commit is contained in:
parent
ed6454fe78
commit
f784757113
19 changed files with 235 additions and 122 deletions
|
@ -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)
|
||||
|
|
37
lib/spack/env/cc
vendored
37
lib/spack/env/cc
vendored
|
@ -21,23 +21,22 @@ 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_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))
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
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_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 @@ def __call__(self, *args, **kwargs):
|
|||
|
||||
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.
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -35,6 +35,11 @@ def setup_parser(subparser):
|
|||
subparser.add_argument(
|
||||
'-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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -41,49 +41,69 @@
|
|||
_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))
|
||||
|
||||
|
||||
@_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 = find(compiler_spec)
|
||||
|
||||
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))
|
||||
|
||||
return compilers
|
||||
|
||||
|
||||
@_auto_compiler_spec
|
||||
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.
|
||||
"""
|
||||
matches = [c for c in available_compilers() if c.satisfies(compiler_spec)]
|
||||
|
||||
# TODO: do something when there are zero matches.
|
||||
assert(len(matches) >= 1)
|
||||
|
||||
compiler = matches[0]
|
||||
file_path = join_path(spack.compiler_version_path, "%s.py" % compiler)
|
||||
|
||||
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)
|
||||
assert(compiler_spec.concrete)
|
||||
compilers = compilers_for_spec(compiler_spec)
|
||||
assert(len(compilers) == 1)
|
||||
return compilers[0]
|
||||
|
||||
|
||||
def class_for_compiler_name(compiler_name):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -33,9 +33,10 @@
|
|||
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 @@ def concretize_compiler(self, spec):
|
|||
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 @@ def choose_provider(self, spec, providers):
|
|||
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.")
|
||||
|
|
|
@ -626,6 +626,7 @@ def do_install(self, **kwargs):
|
|||
"""
|
||||
# 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,8 +672,9 @@ def do_install(self, **kwargs):
|
|||
"Install failed for %s. Nothing was installed!"
|
||||
% self.name)
|
||||
|
||||
if not keep_stage:
|
||||
# On successful install, remove the stage.
|
||||
# Leave if there is an error
|
||||
# Leave it if there is an error
|
||||
self.stage.destroy()
|
||||
|
||||
tty.msg("Successfully installed %s" % self.name)
|
||||
|
@ -725,16 +727,16 @@ def do_uninstall(self, **kwargs):
|
|||
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):
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
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 @@ def constrain(self, other):
|
|||
|
||||
@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 @@ def __str__(self):
|
|||
out += "@%s" % vlist
|
||||
return out
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
|
||||
@key_ordering
|
||||
class Variant(object):
|
||||
|
@ -821,12 +825,13 @@ def validate_names(self):
|
|||
|
||||
# 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 @@ def constrain(self, other, **kwargs):
|
|||
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 @@ def _autospec(self, spec_like):
|
|||
|
||||
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
|
||||
|
|
|
@ -37,16 +37,13 @@ def check_satisfies(self, spec, anon_spec):
|
|||
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)
|
||||
# if left satisfies right, then we should be able to consrain
|
||||
# right by left. Reverse is not always true.
|
||||
right.copy().constrain(left)
|
||||
except SpecError, e:
|
||||
self.fail("Got a SpecError in constrain! " + e.message)
|
||||
|
||||
|
||||
def check_unsatisfiable(self, spec, anon_spec):
|
||||
|
@ -56,25 +53,21 @@ def check_unsatisfiable(self, spec, anon_spec):
|
|||
self.assertFalse(left.satisfies(right))
|
||||
self.assertFalse(left.satisfies(anon_spec))
|
||||
|
||||
self.assertFalse(right.satisfies(left))
|
||||
|
||||
self.assertRaises(UnsatisfiableSpecError, left.constrain, right)
|
||||
self.assertRaises(UnsatisfiableSpecError, left.constrain, anon_spec)
|
||||
self.assertRaises(UnsatisfiableSpecError, right.constrain, left)
|
||||
self.assertRaises(UnsatisfiableSpecError, right.copy().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 @@ def test_invalid_constraint(self):
|
|||
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')
|
||||
|
|
|
@ -311,7 +311,7 @@ def test_intersection(self):
|
|||
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 @@ def test_satisfaction(self):
|
|||
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 @@ def test_satisfaction(self):
|
|||
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')
|
||||
|
|
|
@ -43,7 +43,7 @@ def add_default_arg(self, arg):
|
|||
|
||||
@property
|
||||
def command(self):
|
||||
return self.exe[0]
|
||||
return ' '.join(self.exe)
|
||||
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
|
|
|
@ -39,6 +39,8 @@ class Libdwarf(Package):
|
|||
|
||||
depends_on("libelf")
|
||||
|
||||
parallel = False
|
||||
|
||||
|
||||
def clean(self):
|
||||
for dir in dwarf_dirs:
|
||||
|
|
Loading…
Reference in a new issue