Avoid hidden circular dependencies in spack.architecture (#25873)
* Refactor platform etc. to avoid circular dependencies All the base classes in spack.architecture have been moved to the corresponding specialized subpackages, e.g. Platform is now defined within spack.platforms. This resolves a circular dependency where spack.architecture was both: - Defining the base classes for spack.platforms, etc. - Collecting derived classes from spack.platforms, etc. Now it dopes only the latter. * Move a few platform related functions to "spack.platforms" * Removed spack.architecture.sys_type() * Fixup for docs * Rename Python modules according to review
This commit is contained in:
parent
060582a21d
commit
e9f1cfdaaf
23 changed files with 492 additions and 478 deletions
|
@ -211,7 +211,7 @@ Spec-related modules
|
||||||
yet.
|
yet.
|
||||||
|
|
||||||
:mod:`spack.architecture`
|
:mod:`spack.architecture`
|
||||||
:func:`architecture.sys_type <spack.architecture.sys_type>` is used
|
:func:`architecture.default_arch <spack.architecture.default_arch>` is used
|
||||||
to determine the host architecture while building.
|
to determine the host architecture while building.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
|
@ -2,28 +2,24 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
"""Aggregate the target processor, the operating system and the target
|
||||||
"""
|
platform into an architecture object.
|
||||||
This module contains all the elements that are required to create an
|
|
||||||
architecture object. These include, the target processor, the operating system,
|
|
||||||
and the architecture platform (i.e. cray, darwin, linux, etc) classes.
|
|
||||||
|
|
||||||
On a multiple architecture machine, the architecture spec field can be set to
|
On a multiple architecture machine, the architecture spec field can be set to
|
||||||
build a package against any target and operating system that is present on the
|
build a package against any target and operating system that is present on the
|
||||||
platform. On Cray platforms or any other architecture that has different front
|
platform. On Cray platforms or any other architecture that has different front
|
||||||
and back end environments, the operating system will determine the method of
|
and back end environments, the operating system will determine the method of
|
||||||
compiler
|
compiler detection.
|
||||||
detection.
|
|
||||||
|
|
||||||
There are two different types of compiler detection:
|
There are two different types of compiler detection:
|
||||||
|
|
||||||
1. Through the $PATH env variable (front-end detection)
|
1. Through the $PATH env variable (front-end detection)
|
||||||
2. Through the tcl module system. (back-end detection)
|
2. Through the module system. (back-end detection)
|
||||||
|
|
||||||
Depending on which operating system is specified, the compiler will be detected
|
Depending on which operating system is specified, the compiler will be detected
|
||||||
using one of those methods.
|
using one of those methods.
|
||||||
|
|
||||||
For platforms such as linux and darwin, the operating system is autodetected
|
For platforms such as linux and darwin, the operating system is autodetected.
|
||||||
and the target is set to be x86_64.
|
|
||||||
|
|
||||||
The command line syntax for specifying an architecture is as follows:
|
The command line syntax for specifying an architecture is as follows:
|
||||||
|
|
||||||
|
@ -33,10 +29,8 @@
|
||||||
the command line and Spack will concretize using the default. These defaults
|
the command line and Spack will concretize using the default. These defaults
|
||||||
are set in the 'platforms/' directory which contains the different subclasses
|
are set in the 'platforms/' directory which contains the different subclasses
|
||||||
for platforms. If the machine has multiple architectures, the user can
|
for platforms. If the machine has multiple architectures, the user can
|
||||||
also enter front-end, or fe or back-end or be. These settings will concretize
|
also enter frontend, or fe or backend or be. These settings will concretize
|
||||||
to their respective front-end and back-end targets and operating systems.
|
to their respective frontend and backend targets and operating systems.
|
||||||
Additional platforms can be added by creating a subclass of Platform
|
|
||||||
and adding it inside the platform directory.
|
|
||||||
|
|
||||||
Platforms are an abstract class that are extended by subclasses. If the user
|
Platforms are an abstract class that are extended by subclasses. If the user
|
||||||
wants to add a new type of platform (such as cray_xe), they can create a
|
wants to add a new type of platform (such as cray_xe), they can create a
|
||||||
|
@ -47,334 +41,30 @@
|
||||||
new platform is added and the user wants that to be detected first.
|
new platform is added and the user wants that to be detected first.
|
||||||
|
|
||||||
Targets are created inside the platform subclasses. Most architecture
|
Targets are created inside the platform subclasses. Most architecture
|
||||||
(like linux, and darwin) will have only one target (x86_64) but in the case of
|
(like linux, and darwin) will have only one target family (x86_64) but in the case of
|
||||||
Cray machines, there is both a frontend and backend processor. The user can
|
Cray machines, there is both a frontend and backend processor. The user can
|
||||||
specify which targets are present on front-end and back-end architecture
|
specify which targets are present on front-end and back-end architecture
|
||||||
|
|
||||||
Depending on the platform, operating systems are either auto-detected or are
|
Depending on the platform, operating systems are either autodetected or are
|
||||||
set. The user can set the front-end and back-end operating setting by the class
|
set. The user can set the frontend and backend operating setting by the class
|
||||||
attributes front_os and back_os. The operating system as described earlier,
|
attributes front_os and back_os. The operating system as described earlier,
|
||||||
will be responsible for compiler detection.
|
will be responsible for compiler detection.
|
||||||
"""
|
"""
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import archspec.cpu
|
import archspec.cpu
|
||||||
|
|
||||||
import llnl.util.lang as lang
|
import llnl.util.lang as lang
|
||||||
import llnl.util.tty as tty
|
|
||||||
|
|
||||||
import spack.compiler
|
import spack.compiler
|
||||||
import spack.compilers
|
import spack.compilers
|
||||||
import spack.config
|
import spack.config
|
||||||
import spack.error as serr
|
import spack.operating_systems
|
||||||
import spack.paths
|
import spack.platforms
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.util.classes
|
import spack.target
|
||||||
import spack.util.executable
|
import spack.util.spack_yaml as syaml
|
||||||
import spack.version
|
import spack.version
|
||||||
from spack.util.spack_yaml import syaml_dict
|
|
||||||
|
|
||||||
|
|
||||||
class NoPlatformError(serr.SpackError):
|
|
||||||
def __init__(self):
|
|
||||||
super(NoPlatformError, self).__init__(
|
|
||||||
"Could not determine a platform for this machine.")
|
|
||||||
|
|
||||||
|
|
||||||
def _ensure_other_is_target(method):
|
|
||||||
"""Decorator to be used in dunder methods taking a single argument to
|
|
||||||
ensure that the argument is an instance of ``Target`` too.
|
|
||||||
"""
|
|
||||||
@functools.wraps(method)
|
|
||||||
def _impl(self, other):
|
|
||||||
if isinstance(other, six.string_types):
|
|
||||||
other = Target(other)
|
|
||||||
|
|
||||||
if not isinstance(other, Target):
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
return method(self, other)
|
|
||||||
|
|
||||||
return _impl
|
|
||||||
|
|
||||||
|
|
||||||
class Target(object):
|
|
||||||
def __init__(self, name, module_name=None):
|
|
||||||
"""Target models microarchitectures and their compatibility.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name (str or Microarchitecture):micro-architecture of the
|
|
||||||
target
|
|
||||||
module_name (str): optional module name to get access to the
|
|
||||||
current target. This is typically used on machines
|
|
||||||
like Cray (e.g. craype-compiler)
|
|
||||||
"""
|
|
||||||
if not isinstance(name, archspec.cpu.Microarchitecture):
|
|
||||||
name = archspec.cpu.TARGETS.get(
|
|
||||||
name, archspec.cpu.generic_microarchitecture(name)
|
|
||||||
)
|
|
||||||
self.microarchitecture = name
|
|
||||||
self.module_name = module_name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return self.microarchitecture.name
|
|
||||||
|
|
||||||
@_ensure_other_is_target
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.microarchitecture == other.microarchitecture and \
|
|
||||||
self.module_name == other.module_name
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
# This method is necessary as long as we support Python 2. In Python 3
|
|
||||||
# __ne__ defaults to the implementation below
|
|
||||||
return not self == other
|
|
||||||
|
|
||||||
@_ensure_other_is_target
|
|
||||||
def __lt__(self, other):
|
|
||||||
# TODO: In the future it would be convenient to say
|
|
||||||
# TODO: `spec.architecture.target < other.architecture.target`
|
|
||||||
# TODO: and change the semantic of the comparison operators
|
|
||||||
|
|
||||||
# This is needed to sort deterministically specs in a list.
|
|
||||||
# It doesn't implement a total ordering semantic.
|
|
||||||
return self.microarchitecture.name < other.microarchitecture.name
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash((self.name, self.module_name))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_dict_or_value(dict_or_value):
|
|
||||||
# A string here represents a generic target (like x86_64 or ppc64) or
|
|
||||||
# a custom micro-architecture
|
|
||||||
if isinstance(dict_or_value, six.string_types):
|
|
||||||
return Target(dict_or_value)
|
|
||||||
|
|
||||||
# TODO: From a dict we actually retrieve much more information than
|
|
||||||
# TODO: just the name. We can use that information to reconstruct an
|
|
||||||
# TODO: "old" micro-architecture or check the current definition.
|
|
||||||
target_info = dict_or_value
|
|
||||||
return Target(target_info['name'])
|
|
||||||
|
|
||||||
def to_dict_or_value(self):
|
|
||||||
"""Returns a dict or a value representing the current target.
|
|
||||||
|
|
||||||
String values are used to keep backward compatibility with generic
|
|
||||||
targets, like e.g. x86_64 or ppc64. More specific micro-architectures
|
|
||||||
will return a dictionary which contains information on the name,
|
|
||||||
features, vendor, generation and parents of the current target.
|
|
||||||
"""
|
|
||||||
# Generic targets represent either an architecture
|
|
||||||
# family (like x86_64) or a custom micro-architecture
|
|
||||||
if self.microarchitecture.vendor == 'generic':
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
return syaml_dict(
|
|
||||||
self.microarchitecture.to_dict(return_list_of_items=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
cls_name = self.__class__.__name__
|
|
||||||
fmt = cls_name + '({0}, {1})'
|
|
||||||
return fmt.format(repr(self.microarchitecture),
|
|
||||||
repr(self.module_name))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.microarchitecture)
|
|
||||||
|
|
||||||
def __contains__(self, cpu_flag):
|
|
||||||
return cpu_flag in self.microarchitecture
|
|
||||||
|
|
||||||
def optimization_flags(self, compiler):
|
|
||||||
"""Returns the flags needed to optimize for this target using
|
|
||||||
the compiler passed as argument.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
compiler (spack.spec.CompilerSpec or spack.compiler.Compiler): object that
|
|
||||||
contains both the name and the version of the compiler we want to use
|
|
||||||
"""
|
|
||||||
# Mixed toolchains are not supported yet
|
|
||||||
if isinstance(compiler, spack.compiler.Compiler):
|
|
||||||
if spack.compilers.is_mixed_toolchain(compiler):
|
|
||||||
msg = ('microarchitecture specific optimizations are not '
|
|
||||||
'supported yet on mixed compiler toolchains [check'
|
|
||||||
' {0.name}@{0.version} for further details]')
|
|
||||||
warnings.warn(msg.format(compiler))
|
|
||||||
return ''
|
|
||||||
|
|
||||||
# Try to check if the current compiler comes with a version number or
|
|
||||||
# has an unexpected suffix. If so, treat it as a compiler with a
|
|
||||||
# custom spec.
|
|
||||||
compiler_version = compiler.version
|
|
||||||
version_number, suffix = archspec.cpu.version_components(
|
|
||||||
compiler.version
|
|
||||||
)
|
|
||||||
if not version_number or suffix not in ('', 'apple'):
|
|
||||||
# Try to deduce the underlying version of the compiler, regardless
|
|
||||||
# of its name in compilers.yaml. Depending on where this function
|
|
||||||
# is called we might get either a CompilerSpec or a fully fledged
|
|
||||||
# compiler object.
|
|
||||||
if isinstance(compiler, spack.spec.CompilerSpec):
|
|
||||||
compiler = spack.compilers.compilers_for_spec(compiler).pop()
|
|
||||||
try:
|
|
||||||
compiler_version = compiler.real_version
|
|
||||||
except spack.util.executable.ProcessError as e:
|
|
||||||
# log this and just return compiler.version instead
|
|
||||||
tty.debug(str(e))
|
|
||||||
|
|
||||||
return self.microarchitecture.optimization_flags(
|
|
||||||
compiler.name, str(compiler_version)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@lang.lazy_lexicographic_ordering
|
|
||||||
class Platform(object):
|
|
||||||
""" Abstract class that each type of Platform will subclass.
|
|
||||||
Will return a instance of it once it is returned.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Subclass sets number. Controls detection order
|
|
||||||
priority = None # type: int
|
|
||||||
|
|
||||||
#: binary formats used on this platform; used by relocation logic
|
|
||||||
binary_formats = ['elf']
|
|
||||||
|
|
||||||
front_end = None # type: str
|
|
||||||
back_end = None # type: str
|
|
||||||
default = None # type: str # The default back end target.
|
|
||||||
|
|
||||||
front_os = None # type: str
|
|
||||||
back_os = None # type: str
|
|
||||||
default_os = None # type: str
|
|
||||||
|
|
||||||
reserved_targets = ['default_target', 'frontend', 'fe', 'backend', 'be']
|
|
||||||
reserved_oss = ['default_os', 'frontend', 'fe', 'backend', 'be']
|
|
||||||
|
|
||||||
def __init__(self, name):
|
|
||||||
self.targets = {}
|
|
||||||
self.operating_sys = {}
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def add_target(self, name, target):
|
|
||||||
"""Used by the platform specific subclass to list available targets.
|
|
||||||
Raises an error if the platform specifies a name
|
|
||||||
that is reserved by spack as an alias.
|
|
||||||
"""
|
|
||||||
if name in Platform.reserved_targets:
|
|
||||||
raise ValueError(
|
|
||||||
"%s is a spack reserved alias "
|
|
||||||
"and cannot be the name of a target" % name)
|
|
||||||
self.targets[name] = target
|
|
||||||
|
|
||||||
def target(self, name):
|
|
||||||
"""This is a getter method for the target dictionary
|
|
||||||
that handles defaulting based on the values provided by default,
|
|
||||||
front-end, and back-end. This can be overwritten
|
|
||||||
by a subclass for which we want to provide further aliasing options.
|
|
||||||
"""
|
|
||||||
# TODO: Check if we can avoid using strings here
|
|
||||||
name = str(name)
|
|
||||||
if name == 'default_target':
|
|
||||||
name = self.default
|
|
||||||
elif name == 'frontend' or name == 'fe':
|
|
||||||
name = self.front_end
|
|
||||||
elif name == 'backend' or name == 'be':
|
|
||||||
name = self.back_end
|
|
||||||
|
|
||||||
return self.targets.get(name, None)
|
|
||||||
|
|
||||||
def add_operating_system(self, name, os_class):
|
|
||||||
""" Add the operating_system class object into the
|
|
||||||
platform.operating_sys dictionary
|
|
||||||
"""
|
|
||||||
if name in Platform.reserved_oss:
|
|
||||||
raise ValueError(
|
|
||||||
"%s is a spack reserved alias "
|
|
||||||
"and cannot be the name of an OS" % name)
|
|
||||||
self.operating_sys[name] = os_class
|
|
||||||
|
|
||||||
def operating_system(self, name):
|
|
||||||
if name == 'default_os':
|
|
||||||
name = self.default_os
|
|
||||||
if name == 'frontend' or name == "fe":
|
|
||||||
name = self.front_os
|
|
||||||
if name == 'backend' or name == 'be':
|
|
||||||
name = self.back_os
|
|
||||||
|
|
||||||
return self.operating_sys.get(name, None)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_platform_environment(cls, pkg, env):
|
|
||||||
""" Subclass can override this method if it requires any
|
|
||||||
platform-specific build environment modifications.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def detect(cls):
|
|
||||||
""" Subclass is responsible for implementing this method.
|
|
||||||
Returns True if the Platform class detects that
|
|
||||||
it is the current platform
|
|
||||||
and False if it's not.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return self.__str__()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def _cmp_iter(self):
|
|
||||||
yield self.name
|
|
||||||
yield self.default
|
|
||||||
yield self.front_end
|
|
||||||
yield self.back_end
|
|
||||||
yield self.default_os
|
|
||||||
yield self.front_os
|
|
||||||
yield self.back_os
|
|
||||||
|
|
||||||
def targets():
|
|
||||||
for t in sorted(self.targets.values()):
|
|
||||||
yield t._cmp_iter
|
|
||||||
yield targets
|
|
||||||
|
|
||||||
def oses():
|
|
||||||
for o in sorted(self.operating_sys.values()):
|
|
||||||
yield o._cmp_iter
|
|
||||||
yield oses
|
|
||||||
|
|
||||||
|
|
||||||
@lang.lazy_lexicographic_ordering
|
|
||||||
class OperatingSystem(object):
|
|
||||||
""" Operating System will be like a class similar to platform extended
|
|
||||||
by subclasses for the specifics. Operating System will contain the
|
|
||||||
compiler finding logic. Instead of calling two separate methods to
|
|
||||||
find compilers we call find_compilers method for each operating system
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, name, version):
|
|
||||||
self.name = name.replace('-', '_')
|
|
||||||
self.version = str(version).replace('-', '_')
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "%s%s" % (self.name, self.version)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return self.__str__()
|
|
||||||
|
|
||||||
def _cmp_iter(self):
|
|
||||||
yield self.name
|
|
||||||
yield self.version
|
|
||||||
|
|
||||||
def to_dict(self):
|
|
||||||
return syaml_dict([
|
|
||||||
('name', self.name),
|
|
||||||
('version', self.version)
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
@lang.lazy_lexicographic_ordering
|
@lang.lazy_lexicographic_ordering
|
||||||
|
@ -399,11 +89,13 @@ def __init__(self, plat=None, os=None, target=None):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def concrete(self):
|
def concrete(self):
|
||||||
return all((self.platform is not None,
|
return all(
|
||||||
isinstance(self.platform, Platform),
|
(self.platform is not None,
|
||||||
|
isinstance(self.platform, spack.platforms.Platform),
|
||||||
self.os is not None,
|
self.os is not None,
|
||||||
isinstance(self.os, OperatingSystem),
|
isinstance(self.os, spack.operating_systems.OperatingSystem),
|
||||||
self.target is not None, isinstance(self.target, Target)))
|
self.target is not None, isinstance(self.target, spack.target.Target))
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.platform or self.os or self.target:
|
if self.platform or self.os or self.target:
|
||||||
|
@ -428,28 +120,28 @@ def __nonzero__(self):
|
||||||
__bool__ = __nonzero__
|
__bool__ = __nonzero__
|
||||||
|
|
||||||
def _cmp_iter(self):
|
def _cmp_iter(self):
|
||||||
if isinstance(self.platform, Platform):
|
if isinstance(self.platform, spack.platforms.Platform):
|
||||||
yield self.platform.name
|
yield self.platform.name
|
||||||
else:
|
else:
|
||||||
yield self.platform
|
yield self.platform
|
||||||
|
|
||||||
if isinstance(self.os, OperatingSystem):
|
if isinstance(self.os, spack.operating_systems.OperatingSystem):
|
||||||
yield self.os.name
|
yield self.os.name
|
||||||
else:
|
else:
|
||||||
yield self.os
|
yield self.os
|
||||||
|
|
||||||
if isinstance(self.target, Target):
|
if isinstance(self.target, spack.target.Target):
|
||||||
yield self.target.microarchitecture
|
yield self.target.microarchitecture
|
||||||
else:
|
else:
|
||||||
yield self.target
|
yield self.target
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
str_or_none = lambda v: str(v) if v else None
|
str_or_none = lambda v: str(v) if v else None
|
||||||
d = syaml_dict([
|
d = syaml.syaml_dict([
|
||||||
('platform', str_or_none(self.platform)),
|
('platform', str_or_none(self.platform)),
|
||||||
('platform_os', str_or_none(self.os)),
|
('platform_os', str_or_none(self.os)),
|
||||||
('target', self.target.to_dict_or_value())])
|
('target', self.target.to_dict_or_value())])
|
||||||
return syaml_dict([('arch', d)])
|
return syaml.syaml_dict([('arch', d)])
|
||||||
|
|
||||||
def to_spec(self):
|
def to_spec(self):
|
||||||
"""Convert this Arch to an anonymous Spec with architecture defined."""
|
"""Convert this Arch to an anonymous Spec with architecture defined."""
|
||||||
|
@ -463,64 +155,25 @@ def from_dict(d):
|
||||||
return arch_for_spec(spec)
|
return arch_for_spec(spec)
|
||||||
|
|
||||||
|
|
||||||
@lang.memoized
|
|
||||||
def get_platform(platform_name):
|
|
||||||
"""Returns a platform object that corresponds to the given name."""
|
|
||||||
platform_list = all_platforms()
|
|
||||||
for p in platform_list:
|
|
||||||
if platform_name.replace("_", "").lower() == p.__name__.lower():
|
|
||||||
return p()
|
|
||||||
|
|
||||||
|
|
||||||
def verify_platform(platform_name):
|
|
||||||
""" Determines whether or not the platform with the given name is supported
|
|
||||||
in Spack. For more information, see the 'spack.platforms' submodule.
|
|
||||||
"""
|
|
||||||
platform_name = platform_name.replace("_", "").lower()
|
|
||||||
platform_names = [p.__name__.lower() for p in all_platforms()]
|
|
||||||
|
|
||||||
if platform_name not in platform_names:
|
|
||||||
tty.die("%s is not a supported platform; supported platforms are %s" %
|
|
||||||
(platform_name, platform_names))
|
|
||||||
|
|
||||||
|
|
||||||
def arch_for_spec(arch_spec):
|
def arch_for_spec(arch_spec):
|
||||||
"""Transforms the given architecture spec into an architecture object."""
|
"""Transforms the given architecture spec into an architecture object."""
|
||||||
arch_spec = spack.spec.ArchSpec(arch_spec)
|
arch_spec = spack.spec.ArchSpec(arch_spec)
|
||||||
assert arch_spec.concrete
|
assert arch_spec.concrete
|
||||||
|
|
||||||
arch_plat = get_platform(arch_spec.platform)
|
arch_plat = spack.platforms.by_name(arch_spec.platform)
|
||||||
if not (arch_plat.operating_system(arch_spec.os) and
|
if not (arch_plat.operating_system(arch_spec.os) and
|
||||||
arch_plat.target(arch_spec.target)):
|
arch_plat.target(arch_spec.target)):
|
||||||
raise ValueError(
|
sys_type = str(default_arch())
|
||||||
"Can't recreate arch for spec %s on current arch %s; "
|
msg = ("Can't recreate arch for spec {0} on current arch {1}; "
|
||||||
"spec architecture is too different" % (arch_spec, sys_type()))
|
"spec architecture is too different")
|
||||||
|
raise ValueError(msg.format(arch_spec, sys_type))
|
||||||
|
|
||||||
return Arch(arch_plat, arch_spec.os, arch_spec.target)
|
return Arch(arch_plat, arch_spec.os, arch_spec.target)
|
||||||
|
|
||||||
|
|
||||||
@lang.memoized
|
|
||||||
def _all_platforms():
|
|
||||||
mod_path = spack.paths.platform_path
|
|
||||||
return spack.util.classes.list_classes("spack.platforms", mod_path)
|
|
||||||
|
|
||||||
|
|
||||||
@lang.memoized
|
@lang.memoized
|
||||||
def _platform():
|
def _platform():
|
||||||
"""Detects the platform for this machine.
|
return spack.platforms.host()
|
||||||
|
|
||||||
Gather a list of all available subclasses of platforms.
|
|
||||||
Sorts the list according to their priority looking. Priority is
|
|
||||||
an arbitrarily set number. Detects platform either using uname or
|
|
||||||
a file path (/opt/cray...)
|
|
||||||
"""
|
|
||||||
# Try to create a Platform object using the config file FIRST
|
|
||||||
platform_list = _all_platforms()
|
|
||||||
platform_list.sort(key=lambda a: a.priority)
|
|
||||||
|
|
||||||
for platform_cls in platform_list:
|
|
||||||
if platform_cls.detect():
|
|
||||||
return platform_cls()
|
|
||||||
|
|
||||||
|
|
||||||
#: The "real" platform of the host running Spack. This should not be changed
|
#: The "real" platform of the host running Spack. This should not be changed
|
||||||
|
@ -531,44 +184,23 @@ def _platform():
|
||||||
#: context manager.
|
#: context manager.
|
||||||
platform = _platform
|
platform = _platform
|
||||||
|
|
||||||
#: The list of all platform classes. May be swapped by the use_platform
|
|
||||||
#: context manager.
|
|
||||||
all_platforms = _all_platforms
|
|
||||||
|
|
||||||
|
|
||||||
@lang.memoized
|
@lang.memoized
|
||||||
def default_arch():
|
def default_arch():
|
||||||
"""Default ``Arch`` object for this machine.
|
"""Default ``Arch`` object for this machine"""
|
||||||
|
|
||||||
See ``sys_type()``.
|
|
||||||
"""
|
|
||||||
return Arch(platform(), 'default_os', 'default_target')
|
return Arch(platform(), 'default_os', 'default_target')
|
||||||
|
|
||||||
|
|
||||||
def sys_type():
|
|
||||||
"""Print out the "default" platform-os-target tuple for this machine.
|
|
||||||
|
|
||||||
On machines with only one target OS/target, prints out the
|
|
||||||
platform-os-target for the frontend. For machines with a frontend
|
|
||||||
and a backend, prints the default backend.
|
|
||||||
|
|
||||||
TODO: replace with use of more explicit methods to get *all* the
|
|
||||||
backends, as client code should really be aware of cross-compiled
|
|
||||||
architectures.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return str(default_arch())
|
|
||||||
|
|
||||||
|
|
||||||
@lang.memoized
|
@lang.memoized
|
||||||
def compatible_sys_types():
|
def compatible_sys_types():
|
||||||
"""Returns a list of all the systypes compatible with the current host."""
|
"""Return a list of all the platform-os-target tuples compatible
|
||||||
compatible_archs = []
|
with the current host.
|
||||||
|
"""
|
||||||
current_host = archspec.cpu.host()
|
current_host = archspec.cpu.host()
|
||||||
compatible_targets = [current_host] + current_host.ancestors
|
compatible_targets = [current_host] + current_host.ancestors
|
||||||
for target in compatible_targets:
|
compatible_archs = [
|
||||||
arch = Arch(platform(), 'default_os', target)
|
str(Arch(platform(), 'default_os', target)) for target in compatible_targets
|
||||||
compatible_archs.append(str(arch))
|
]
|
||||||
return compatible_archs
|
return compatible_archs
|
||||||
|
|
||||||
|
|
||||||
|
@ -586,16 +218,15 @@ def __call__(self):
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def use_platform(new_platform):
|
def use_platform(new_platform):
|
||||||
global platform, all_platforms
|
global platform
|
||||||
|
|
||||||
msg = '"{0}" must be an instance of Platform'
|
msg = '"{0}" must be an instance of Platform'
|
||||||
assert isinstance(new_platform, Platform), msg.format(new_platform)
|
assert isinstance(new_platform, spack.platforms.Platform), msg.format(new_platform)
|
||||||
|
|
||||||
original_platform_fn, original_all_platforms_fn = platform, all_platforms
|
original_platform_fn = platform
|
||||||
|
|
||||||
try:
|
try:
|
||||||
platform = _PickleableCallable(new_platform)
|
platform = _PickleableCallable(new_platform)
|
||||||
all_platforms = _PickleableCallable([type(new_platform)])
|
|
||||||
|
|
||||||
# Clear configuration and compiler caches
|
# Clear configuration and compiler caches
|
||||||
spack.config.config.clear_caches()
|
spack.config.config.clear_caches()
|
||||||
|
@ -604,7 +235,7 @@ def use_platform(new_platform):
|
||||||
yield new_platform
|
yield new_platform
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
platform, all_platforms = original_platform_fn, original_all_platforms_fn
|
platform = original_platform_fn
|
||||||
|
|
||||||
# Clear configuration and compiler caches
|
# Clear configuration and compiler caches
|
||||||
spack.config.config.clear_caches()
|
spack.config.config.clear_caches()
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
import spack.hash_types as ht
|
import spack.hash_types as ht
|
||||||
import spack.hooks.sbang
|
import spack.hooks.sbang
|
||||||
import spack.mirror
|
import spack.mirror
|
||||||
|
import spack.platforms
|
||||||
import spack.relocate as relocate
|
import spack.relocate as relocate
|
||||||
import spack.util.file_cache as file_cache
|
import spack.util.file_cache as file_cache
|
||||||
import spack.util.gpg
|
import spack.util.gpg
|
||||||
|
@ -1156,7 +1157,7 @@ def make_package_relative(workdir, spec, allow_root):
|
||||||
orig_path_names.append(os.path.join(prefix, filename))
|
orig_path_names.append(os.path.join(prefix, filename))
|
||||||
cur_path_names.append(os.path.join(workdir, filename))
|
cur_path_names.append(os.path.join(workdir, filename))
|
||||||
|
|
||||||
platform = spack.architecture.get_platform(spec.platform)
|
platform = spack.platforms.by_name(spec.platform)
|
||||||
if 'macho' in platform.binary_formats:
|
if 'macho' in platform.binary_formats:
|
||||||
relocate.make_macho_binaries_relative(
|
relocate.make_macho_binaries_relative(
|
||||||
cur_path_names, orig_path_names, old_layout_root)
|
cur_path_names, orig_path_names, old_layout_root)
|
||||||
|
@ -1267,7 +1268,7 @@ def is_backup_file(file):
|
||||||
]
|
]
|
||||||
# If the buildcache was not created with relativized rpaths
|
# If the buildcache was not created with relativized rpaths
|
||||||
# do the relocation of path in binaries
|
# do the relocation of path in binaries
|
||||||
platform = spack.architecture.get_platform(spec.platform)
|
platform = spack.platforms.by_name(spec.platform)
|
||||||
if 'macho' in platform.binary_formats:
|
if 'macho' in platform.binary_formats:
|
||||||
relocate.relocate_macho_binaries(files_to_relocate,
|
relocate.relocate_macho_binaries(files_to_relocate,
|
||||||
old_layout_root,
|
old_layout_root,
|
||||||
|
|
|
@ -544,7 +544,7 @@ def arguments_to_detect_version_fn(operating_system, paths):
|
||||||
function by providing a method called with the same name.
|
function by providing a method called with the same name.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
operating_system (spack.architecture.OperatingSystem): the operating system
|
operating_system (spack.operating_systems.OperatingSystem): the operating system
|
||||||
on which we are looking for compilers
|
on which we are looking for compilers
|
||||||
paths: paths to search for compilers
|
paths: paths to search for compilers
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
import spack.error
|
import spack.error
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.spec
|
import spack.spec
|
||||||
|
import spack.target
|
||||||
import spack.tengine
|
import spack.tengine
|
||||||
import spack.variant as vt
|
import spack.variant as vt
|
||||||
from spack.config import config
|
from spack.config import config
|
||||||
|
@ -256,8 +257,7 @@ def concretize_architecture(self, spec):
|
||||||
# Get platform of nearest spec with a platform, including spec
|
# Get platform of nearest spec with a platform, including spec
|
||||||
# If spec has a platform, easy
|
# If spec has a platform, easy
|
||||||
if spec.architecture.platform:
|
if spec.architecture.platform:
|
||||||
new_plat = spack.architecture.get_platform(
|
new_plat = spack.platforms.by_name(spec.architecture.platform)
|
||||||
spec.architecture.platform)
|
|
||||||
else:
|
else:
|
||||||
# Else if anyone else has a platform, take the closest one
|
# Else if anyone else has a platform, take the closest one
|
||||||
# Search up, then down, along build/link deps first
|
# Search up, then down, along build/link deps first
|
||||||
|
@ -266,8 +266,7 @@ def concretize_architecture(self, spec):
|
||||||
spec, lambda x: x.architecture and x.architecture.platform
|
spec, lambda x: x.architecture and x.architecture.platform
|
||||||
)
|
)
|
||||||
if platform_spec:
|
if platform_spec:
|
||||||
new_plat = spack.architecture.get_platform(
|
new_plat = spack.platforms.by_name(platform_spec.architecture.platform)
|
||||||
platform_spec.architecture.platform)
|
|
||||||
else:
|
else:
|
||||||
# If no platform anywhere in this spec, grab the default
|
# If no platform anywhere in this spec, grab the default
|
||||||
new_plat = spack.architecture.platform()
|
new_plat = spack.architecture.platform()
|
||||||
|
@ -612,9 +611,7 @@ def _adjust_target(self, spec):
|
||||||
# Try to adjust the target only if it is the default
|
# Try to adjust the target only if it is the default
|
||||||
# target for this platform
|
# target for this platform
|
||||||
current_target = spec.architecture.target
|
current_target = spec.architecture.target
|
||||||
current_platform = spack.architecture.get_platform(
|
current_platform = spack.platforms.by_name(spec.architecture.platform)
|
||||||
spec.architecture.platform
|
|
||||||
)
|
|
||||||
|
|
||||||
default_target = current_platform.target('default_target')
|
default_target = current_platform.target('default_target')
|
||||||
if PackagePrefs.has_preferred_targets(spec.name):
|
if PackagePrefs.has_preferred_targets(spec.name):
|
||||||
|
@ -633,7 +630,7 @@ def _adjust_target(self, spec):
|
||||||
for ancestor in microarchitecture.ancestors:
|
for ancestor in microarchitecture.ancestors:
|
||||||
candidate = None
|
candidate = None
|
||||||
try:
|
try:
|
||||||
candidate = spack.architecture.Target(ancestor)
|
candidate = spack.target.Target(ancestor)
|
||||||
candidate.optimization_flags(spec.compiler)
|
candidate.optimization_flags(spec.compiler)
|
||||||
except archspec.cpu.UnsupportedMicroarchitecture:
|
except archspec.cpu.UnsupportedMicroarchitecture:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -666,7 +666,7 @@ def shell_set(var, value):
|
||||||
tty.die('shell must be sh or csh')
|
tty.die('shell must be sh or csh')
|
||||||
|
|
||||||
# print sys type
|
# print sys type
|
||||||
shell_set('_sp_sys_type', spack.architecture.sys_type())
|
shell_set('_sp_sys_type', str(spack.architecture.default_arch()))
|
||||||
shell_set('_sp_compatible_sys_types',
|
shell_set('_sp_compatible_sys_types',
|
||||||
':'.join(spack.architecture.compatible_sys_types()))
|
':'.join(spack.architecture.compatible_sys_types()))
|
||||||
# print roots for all module systems
|
# print roots for all module systems
|
||||||
|
|
|
@ -2,3 +2,19 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
from ._operating_system import OperatingSystem
|
||||||
|
from .cray_backend import CrayBackend
|
||||||
|
from .cray_frontend import CrayFrontend
|
||||||
|
from .linux_distro import LinuxDistro
|
||||||
|
from .mac_os import MacOs
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'OperatingSystem',
|
||||||
|
'LinuxDistro',
|
||||||
|
'MacOs',
|
||||||
|
'CrayFrontend',
|
||||||
|
'CrayBackend'
|
||||||
|
]
|
||||||
|
|
||||||
|
#: List of all the Operating Systems known to Spack
|
||||||
|
operating_systems = [LinuxDistro, MacOs, CrayFrontend, CrayBackend]
|
||||||
|
|
36
lib/spack/spack/operating_systems/_operating_system.py
Normal file
36
lib/spack/spack/operating_systems/_operating_system.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
|
||||||
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
import llnl.util.lang
|
||||||
|
|
||||||
|
import spack.util.spack_yaml as syaml
|
||||||
|
|
||||||
|
|
||||||
|
@llnl.util.lang.lazy_lexicographic_ordering
|
||||||
|
class OperatingSystem(object):
|
||||||
|
"""Base class for all the Operating Systems.
|
||||||
|
|
||||||
|
Each Operating System contain its own compiler finding logic, that is used
|
||||||
|
to detect compilers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, version):
|
||||||
|
self.name = name.replace('-', '_')
|
||||||
|
self.version = str(version).replace('-', '_')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s%s" % (self.name, self.version)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
def _cmp_iter(self):
|
||||||
|
yield self.name
|
||||||
|
yield self.version
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return syaml.syaml_dict([
|
||||||
|
('name', self.name),
|
||||||
|
('version', self.version)
|
||||||
|
])
|
|
@ -10,9 +10,10 @@
|
||||||
|
|
||||||
import spack.error
|
import spack.error
|
||||||
import spack.version
|
import spack.version
|
||||||
from spack.operating_systems.linux_distro import LinuxDistro
|
|
||||||
from spack.util.module_cmd import module
|
from spack.util.module_cmd import module
|
||||||
|
|
||||||
|
from .linux_distro import LinuxDistro
|
||||||
|
|
||||||
#: Possible locations of the Cray CLE release file,
|
#: Possible locations of the Cray CLE release file,
|
||||||
#: which we look at to get the CNL OS version.
|
#: which we look at to get the CNL OS version.
|
||||||
_cle_release_file = '/etc/opt/cray/release/cle-release'
|
_cle_release_file = '/etc/opt/cray/release/cle-release'
|
||||||
|
|
|
@ -11,10 +11,11 @@
|
||||||
import llnl.util.lang
|
import llnl.util.lang
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
from spack.operating_systems.linux_distro import LinuxDistro
|
|
||||||
from spack.util.environment import get_path
|
from spack.util.environment import get_path
|
||||||
from spack.util.module_cmd import module
|
from spack.util.module_cmd import module
|
||||||
|
|
||||||
|
from .linux_distro import LinuxDistro
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def unload_programming_environment():
|
def unload_programming_environment():
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from spack.architecture import OperatingSystem
|
from ._operating_system import OperatingSystem
|
||||||
|
|
||||||
|
|
||||||
class LinuxDistro(OperatingSystem):
|
class LinuxDistro(OperatingSystem):
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import platform as py_platform
|
import platform as py_platform
|
||||||
|
|
||||||
from spack.architecture import OperatingSystem
|
|
||||||
from spack.util.executable import Executable
|
from spack.util.executable import Executable
|
||||||
from spack.version import Version
|
from spack.version import Version
|
||||||
|
|
||||||
|
from ._operating_system import OperatingSystem
|
||||||
|
|
||||||
|
|
||||||
# FIXME: store versions inside OperatingSystem as a Version instead of string
|
# FIXME: store versions inside OperatingSystem as a Version instead of string
|
||||||
def macos_version():
|
def macos_version():
|
||||||
|
|
|
@ -2,14 +2,54 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
import llnl.util.lang
|
||||||
|
|
||||||
|
from ._platform import Platform
|
||||||
from .cray import Cray
|
from .cray import Cray
|
||||||
from .darwin import Darwin
|
from .darwin import Darwin
|
||||||
from .linux import Linux
|
from .linux import Linux
|
||||||
from .test import Test
|
from .test import Test
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
'Platform',
|
||||||
'Cray',
|
'Cray',
|
||||||
'Darwin',
|
'Darwin',
|
||||||
'Linux',
|
'Linux',
|
||||||
'Test'
|
'Test'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
#: List of all the platform classes known to Spack
|
||||||
|
platforms = [Cray, Darwin, Linux, Test]
|
||||||
|
|
||||||
|
|
||||||
|
def host():
|
||||||
|
"""Detect and return the platform for this machine or None if detection fails."""
|
||||||
|
for platform_cls in sorted(platforms, key=lambda plt: plt.priority):
|
||||||
|
if platform_cls.detect():
|
||||||
|
return platform_cls()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@llnl.util.lang.memoized
|
||||||
|
def cls_by_name(name):
|
||||||
|
"""Return a platform class that corresponds to the given name or None
|
||||||
|
if there is no match.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): name of the platform
|
||||||
|
"""
|
||||||
|
for platform_cls in sorted(platforms, key=lambda plt: plt.priority):
|
||||||
|
if name.replace("_", "").lower() == platform_cls.__name__.lower():
|
||||||
|
return platform_cls
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def by_name(name):
|
||||||
|
"""Return a platform object that corresponds to the given name or None
|
||||||
|
if there is no match.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): name of the platform
|
||||||
|
"""
|
||||||
|
platform_cls = cls_by_name(name)
|
||||||
|
return platform_cls() if platform_cls else None
|
||||||
|
|
126
lib/spack/spack/platforms/_platform.py
Normal file
126
lib/spack/spack/platforms/_platform.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
|
||||||
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
import llnl.util.lang
|
||||||
|
|
||||||
|
import spack.error
|
||||||
|
|
||||||
|
|
||||||
|
class NoPlatformError(spack.error.SpackError):
|
||||||
|
def __init__(self):
|
||||||
|
msg = "Could not determine a platform for this machine"
|
||||||
|
super(NoPlatformError, self).__init__(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@llnl.util.lang.lazy_lexicographic_ordering
|
||||||
|
class Platform(object):
|
||||||
|
"""Base class for each type of Platform"""
|
||||||
|
|
||||||
|
# Subclass sets number. Controls detection order
|
||||||
|
priority = None # type: int
|
||||||
|
|
||||||
|
#: binary formats used on this platform; used by relocation logic
|
||||||
|
binary_formats = ['elf']
|
||||||
|
|
||||||
|
front_end = None # type: str
|
||||||
|
back_end = None # type: str
|
||||||
|
default = None # type: str # The default back end target.
|
||||||
|
|
||||||
|
front_os = None # type: str
|
||||||
|
back_os = None # type: str
|
||||||
|
default_os = None # type: str
|
||||||
|
|
||||||
|
reserved_targets = ['default_target', 'frontend', 'fe', 'backend', 'be']
|
||||||
|
reserved_oss = ['default_os', 'frontend', 'fe', 'backend', 'be']
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.targets = {}
|
||||||
|
self.operating_sys = {}
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def add_target(self, name, target):
|
||||||
|
"""Used by the platform specific subclass to list available targets.
|
||||||
|
Raises an error if the platform specifies a name
|
||||||
|
that is reserved by spack as an alias.
|
||||||
|
"""
|
||||||
|
if name in Platform.reserved_targets:
|
||||||
|
msg = "{0} is a spack reserved alias and cannot be the name of a target"
|
||||||
|
raise ValueError(msg.format(name))
|
||||||
|
self.targets[name] = target
|
||||||
|
|
||||||
|
def target(self, name):
|
||||||
|
"""This is a getter method for the target dictionary
|
||||||
|
that handles defaulting based on the values provided by default,
|
||||||
|
front-end, and back-end. This can be overwritten
|
||||||
|
by a subclass for which we want to provide further aliasing options.
|
||||||
|
"""
|
||||||
|
# TODO: Check if we can avoid using strings here
|
||||||
|
name = str(name)
|
||||||
|
if name == 'default_target':
|
||||||
|
name = self.default
|
||||||
|
elif name == 'frontend' or name == 'fe':
|
||||||
|
name = self.front_end
|
||||||
|
elif name == 'backend' or name == 'be':
|
||||||
|
name = self.back_end
|
||||||
|
|
||||||
|
return self.targets.get(name, None)
|
||||||
|
|
||||||
|
def add_operating_system(self, name, os_class):
|
||||||
|
"""Add the operating_system class object into the
|
||||||
|
platform.operating_sys dictionary.
|
||||||
|
"""
|
||||||
|
if name in Platform.reserved_oss:
|
||||||
|
msg = "{0} is a spack reserved alias and cannot be the name of an OS"
|
||||||
|
raise ValueError(msg.format(name))
|
||||||
|
self.operating_sys[name] = os_class
|
||||||
|
|
||||||
|
def operating_system(self, name):
|
||||||
|
if name == 'default_os':
|
||||||
|
name = self.default_os
|
||||||
|
if name == 'frontend' or name == "fe":
|
||||||
|
name = self.front_os
|
||||||
|
if name == 'backend' or name == 'be':
|
||||||
|
name = self.back_os
|
||||||
|
|
||||||
|
return self.operating_sys.get(name, None)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_platform_environment(cls, pkg, env):
|
||||||
|
"""Subclass can override this method if it requires any
|
||||||
|
platform-specific build environment modifications.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def detect(cls):
|
||||||
|
"""Return True if the the host platform is detected to be the current
|
||||||
|
Platform class, False otherwise.
|
||||||
|
|
||||||
|
Derived classes are responsible for implementing this method.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def _cmp_iter(self):
|
||||||
|
yield self.name
|
||||||
|
yield self.default
|
||||||
|
yield self.front_end
|
||||||
|
yield self.back_end
|
||||||
|
yield self.default_os
|
||||||
|
yield self.front_os
|
||||||
|
yield self.back_os
|
||||||
|
|
||||||
|
def targets():
|
||||||
|
for t in sorted(self.targets.values()):
|
||||||
|
yield t._cmp_iter
|
||||||
|
yield targets
|
||||||
|
|
||||||
|
def oses():
|
||||||
|
for o in sorted(self.operating_sys.values()):
|
||||||
|
yield o._cmp_iter
|
||||||
|
yield oses
|
|
@ -11,13 +11,15 @@
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
from spack.architecture import NoPlatformError, Platform, Target
|
import spack.target
|
||||||
from spack.operating_systems.cray_backend import CrayBackend
|
from spack.operating_systems.cray_backend import CrayBackend
|
||||||
from spack.operating_systems.cray_frontend import CrayFrontend
|
from spack.operating_systems.cray_frontend import CrayFrontend
|
||||||
from spack.paths import build_env_path
|
from spack.paths import build_env_path
|
||||||
from spack.util.executable import Executable
|
from spack.util.executable import Executable
|
||||||
from spack.util.module_cmd import module
|
from spack.util.module_cmd import module
|
||||||
|
|
||||||
|
from ._platform import NoPlatformError, Platform
|
||||||
|
|
||||||
_craype_name_to_target_name = {
|
_craype_name_to_target_name = {
|
||||||
'x86-cascadelake': 'cascadelake',
|
'x86-cascadelake': 'cascadelake',
|
||||||
'x86-naples': 'zen',
|
'x86-naples': 'zen',
|
||||||
|
@ -51,7 +53,7 @@ def __init__(self):
|
||||||
# Make all craype targets available.
|
# Make all craype targets available.
|
||||||
for target in self._avail_targets():
|
for target in self._avail_targets():
|
||||||
name = _target_name_from_craype_target_name(target)
|
name = _target_name_from_craype_target_name(target)
|
||||||
self.add_target(name, Target(name, 'craype-%s' % target))
|
self.add_target(name, spack.target.Target(name, 'craype-%s' % target))
|
||||||
|
|
||||||
self.back_end = os.environ.get('SPACK_BACK_END',
|
self.back_end = os.environ.get('SPACK_BACK_END',
|
||||||
self._default_target_from_env())
|
self._default_target_from_env())
|
||||||
|
@ -63,12 +65,12 @@ def __init__(self):
|
||||||
# Setup frontend targets
|
# Setup frontend targets
|
||||||
for name in archspec.cpu.TARGETS:
|
for name in archspec.cpu.TARGETS:
|
||||||
if name not in self.targets:
|
if name not in self.targets:
|
||||||
self.add_target(name, Target(name))
|
self.add_target(name, spack.target.Target(name))
|
||||||
self.front_end = os.environ.get(
|
self.front_end = os.environ.get(
|
||||||
'SPACK_FRONT_END', archspec.cpu.host().name
|
'SPACK_FRONT_END', archspec.cpu.host().name
|
||||||
)
|
)
|
||||||
if self.front_end not in self.targets:
|
if self.front_end not in self.targets:
|
||||||
self.add_target(self.front_end, Target(self.front_end))
|
self.add_target(self.front_end, spack.target.Target(self.front_end))
|
||||||
|
|
||||||
front_distro = CrayFrontend()
|
front_distro = CrayFrontend()
|
||||||
back_distro = CrayBackend()
|
back_distro = CrayBackend()
|
||||||
|
|
|
@ -7,9 +7,11 @@
|
||||||
|
|
||||||
import archspec.cpu
|
import archspec.cpu
|
||||||
|
|
||||||
from spack.architecture import Platform, Target
|
import spack.target
|
||||||
from spack.operating_systems.mac_os import MacOs
|
from spack.operating_systems.mac_os import MacOs
|
||||||
|
|
||||||
|
from ._platform import Platform
|
||||||
|
|
||||||
|
|
||||||
class Darwin(Platform):
|
class Darwin(Platform):
|
||||||
priority = 89
|
priority = 89
|
||||||
|
@ -20,7 +22,7 @@ def __init__(self):
|
||||||
super(Darwin, self).__init__('darwin')
|
super(Darwin, self).__init__('darwin')
|
||||||
|
|
||||||
for name in archspec.cpu.TARGETS:
|
for name in archspec.cpu.TARGETS:
|
||||||
self.add_target(name, Target(name))
|
self.add_target(name, spack.target.Target(name))
|
||||||
|
|
||||||
self.default = archspec.cpu.host().name
|
self.default = archspec.cpu.host().name
|
||||||
self.front_end = self.default
|
self.front_end = self.default
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
|
|
||||||
import archspec.cpu
|
import archspec.cpu
|
||||||
|
|
||||||
from spack.architecture import Platform, Target
|
import spack.target
|
||||||
from spack.operating_systems.linux_distro import LinuxDistro
|
from spack.operating_systems.linux_distro import LinuxDistro
|
||||||
|
|
||||||
|
from ._platform import Platform
|
||||||
|
|
||||||
|
|
||||||
class Linux(Platform):
|
class Linux(Platform):
|
||||||
priority = 90
|
priority = 90
|
||||||
|
@ -17,7 +19,7 @@ def __init__(self):
|
||||||
super(Linux, self).__init__('linux')
|
super(Linux, self).__init__('linux')
|
||||||
|
|
||||||
for name in archspec.cpu.TARGETS:
|
for name in archspec.cpu.TARGETS:
|
||||||
self.add_target(name, Target(name))
|
self.add_target(name, spack.target.Target(name))
|
||||||
|
|
||||||
# Get specific default
|
# Get specific default
|
||||||
self.default = archspec.cpu.host().name
|
self.default = archspec.cpu.host().name
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
from spack.architecture import OperatingSystem, Platform, Target
|
import spack.operating_systems
|
||||||
|
import spack.target
|
||||||
|
|
||||||
|
from ._platform import Platform
|
||||||
|
|
||||||
|
|
||||||
class Test(Platform):
|
class Test(Platform):
|
||||||
|
@ -24,13 +26,13 @@ class Test(Platform):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Test, self).__init__('test')
|
super(Test, self).__init__('test')
|
||||||
self.add_target(self.default, Target(self.default))
|
self.add_target(self.default, spack.target.Target(self.default))
|
||||||
self.add_target(self.front_end, Target(self.front_end))
|
self.add_target(self.front_end, spack.target.Target(self.front_end))
|
||||||
|
|
||||||
self.add_operating_system(
|
self.add_operating_system(
|
||||||
self.default_os, OperatingSystem('debian', 6))
|
self.default_os, spack.operating_systems.OperatingSystem('debian', 6))
|
||||||
self.add_operating_system(
|
self.add_operating_system(
|
||||||
self.front_os, OperatingSystem('redhat', 6))
|
self.front_os, spack.operating_systems.OperatingSystem('redhat', 6))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def detect(cls):
|
def detect(cls):
|
||||||
|
|
|
@ -100,10 +100,12 @@
|
||||||
import spack.hash_types as ht
|
import spack.hash_types as ht
|
||||||
import spack.parse
|
import spack.parse
|
||||||
import spack.paths
|
import spack.paths
|
||||||
|
import spack.platforms
|
||||||
import spack.provider_index
|
import spack.provider_index
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.solver
|
import spack.solver
|
||||||
import spack.store
|
import spack.store
|
||||||
|
import spack.target
|
||||||
import spack.util.crypto
|
import spack.util.crypto
|
||||||
import spack.util.executable
|
import spack.util.executable
|
||||||
import spack.util.hash
|
import spack.util.hash
|
||||||
|
@ -291,7 +293,7 @@ def os(self, value):
|
||||||
# will assumed to be the host machine's platform.
|
# will assumed to be the host machine's platform.
|
||||||
value = str(value) if value is not None else None
|
value = str(value) if value is not None else None
|
||||||
|
|
||||||
if value in spack.architecture.Platform.reserved_oss:
|
if value in spack.platforms.Platform.reserved_oss:
|
||||||
curr_platform = str(spack.architecture.platform())
|
curr_platform = str(spack.architecture.platform())
|
||||||
self.platform = self.platform or curr_platform
|
self.platform = self.platform or curr_platform
|
||||||
|
|
||||||
|
@ -301,7 +303,7 @@ def os(self, value):
|
||||||
"arch platform (%s) isn't the current platform (%s)" %
|
"arch platform (%s) isn't the current platform (%s)" %
|
||||||
(value, self.platform, curr_platform))
|
(value, self.platform, curr_platform))
|
||||||
|
|
||||||
spec_platform = spack.architecture.get_platform(self.platform)
|
spec_platform = spack.platforms.by_name(self.platform)
|
||||||
value = str(spec_platform.operating_system(value))
|
value = str(spec_platform.operating_system(value))
|
||||||
|
|
||||||
self._os = value
|
self._os = value
|
||||||
|
@ -320,15 +322,15 @@ def target(self, value):
|
||||||
# will assumed to be the host machine's platform.
|
# will assumed to be the host machine's platform.
|
||||||
|
|
||||||
def target_or_none(t):
|
def target_or_none(t):
|
||||||
if isinstance(t, spack.architecture.Target):
|
if isinstance(t, spack.target.Target):
|
||||||
return t
|
return t
|
||||||
if t and t != 'None':
|
if t and t != 'None':
|
||||||
return spack.architecture.Target(t)
|
return spack.target.Target(t)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
value = target_or_none(value)
|
value = target_or_none(value)
|
||||||
|
|
||||||
if str(value) in spack.architecture.Platform.reserved_targets:
|
if str(value) in spack.platforms.Platform.reserved_targets:
|
||||||
curr_platform = str(spack.architecture.platform())
|
curr_platform = str(spack.architecture.platform())
|
||||||
self.platform = self.platform or curr_platform
|
self.platform = self.platform or curr_platform
|
||||||
|
|
||||||
|
@ -338,7 +340,7 @@ def target_or_none(t):
|
||||||
"the arch platform (%s) isn't the current platform (%s)" %
|
"the arch platform (%s) isn't the current platform (%s)" %
|
||||||
(value, self.platform, curr_platform))
|
(value, self.platform, curr_platform))
|
||||||
|
|
||||||
spec_platform = spack.architecture.get_platform(self.platform)
|
spec_platform = spack.platforms.by_name(self.platform)
|
||||||
value = spec_platform.target(value)
|
value = spec_platform.target(value)
|
||||||
|
|
||||||
self._target = value
|
self._target = value
|
||||||
|
@ -416,7 +418,7 @@ def target_intersection(self, other):
|
||||||
# s_target_range is a concrete target
|
# s_target_range is a concrete target
|
||||||
# get a microarchitecture reference for at least one side
|
# get a microarchitecture reference for at least one side
|
||||||
# of each comparison so we can use archspec comparators
|
# of each comparison so we can use archspec comparators
|
||||||
s_comp = spack.architecture.Target(s_min).microarchitecture
|
s_comp = spack.target.Target(s_min).microarchitecture
|
||||||
if not o_sep:
|
if not o_sep:
|
||||||
if s_min == o_min:
|
if s_min == o_min:
|
||||||
results.append(s_min)
|
results.append(s_min)
|
||||||
|
@ -425,22 +427,22 @@ def target_intersection(self, other):
|
||||||
results.append(s_min)
|
results.append(s_min)
|
||||||
elif not o_sep:
|
elif not o_sep:
|
||||||
# "cast" to microarchitecture
|
# "cast" to microarchitecture
|
||||||
o_comp = spack.architecture.Target(o_min).microarchitecture
|
o_comp = spack.target.Target(o_min).microarchitecture
|
||||||
if (not s_min or o_comp >= s_min) and (
|
if (not s_min or o_comp >= s_min) and (
|
||||||
not s_max or o_comp <= s_max):
|
not s_max or o_comp <= s_max):
|
||||||
results.append(o_min)
|
results.append(o_min)
|
||||||
else:
|
else:
|
||||||
# Take intersection of two ranges
|
# Take intersection of two ranges
|
||||||
# Lots of comparisons needed
|
# Lots of comparisons needed
|
||||||
_s_min = spack.architecture.Target(s_min).microarchitecture
|
_s_min = spack.target.Target(s_min).microarchitecture
|
||||||
_s_max = spack.architecture.Target(s_max).microarchitecture
|
_s_max = spack.target.Target(s_max).microarchitecture
|
||||||
_o_min = spack.architecture.Target(o_min).microarchitecture
|
_o_min = spack.target.Target(o_min).microarchitecture
|
||||||
_o_max = spack.architecture.Target(o_max).microarchitecture
|
_o_max = spack.target.Target(o_max).microarchitecture
|
||||||
|
|
||||||
n_min = s_min if _s_min >= _o_min else o_min
|
n_min = s_min if _s_min >= _o_min else o_min
|
||||||
n_max = s_max if _s_max <= _o_max else o_max
|
n_max = s_max if _s_max <= _o_max else o_max
|
||||||
_n_min = spack.architecture.Target(n_min).microarchitecture
|
_n_min = spack.target.Target(n_min).microarchitecture
|
||||||
_n_max = spack.architecture.Target(n_max).microarchitecture
|
_n_max = spack.target.Target(n_max).microarchitecture
|
||||||
if _n_min == _n_max:
|
if _n_min == _n_max:
|
||||||
results.append(n_min)
|
results.append(n_min)
|
||||||
elif not n_min or not n_max or _n_min < _n_max:
|
elif not n_min or not n_max or _n_min < _n_max:
|
||||||
|
@ -521,7 +523,7 @@ def from_dict(d):
|
||||||
d = d['arch']
|
d = d['arch']
|
||||||
|
|
||||||
operating_system = d.get('platform_os', None) or d['os']
|
operating_system = d.get('platform_os', None) or d['os']
|
||||||
target = spack.architecture.Target.from_dict_or_value(d['target'])
|
target = spack.target.Target.from_dict_or_value(d['target'])
|
||||||
|
|
||||||
return ArchSpec((d['platform'], operating_system, target))
|
return ArchSpec((d['platform'], operating_system, target))
|
||||||
|
|
||||||
|
|
162
lib/spack/spack/target.py
Normal file
162
lib/spack/spack/target.py
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
|
||||||
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
import functools
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
import archspec.cpu
|
||||||
|
|
||||||
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
|
import spack.compiler
|
||||||
|
import spack.compilers
|
||||||
|
import spack.spec
|
||||||
|
import spack.util.spack_yaml as syaml
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_other_is_target(method):
|
||||||
|
"""In a single argument method, ensure that the argument is an
|
||||||
|
instance of ``Target``.
|
||||||
|
"""
|
||||||
|
@functools.wraps(method)
|
||||||
|
def _impl(self, other):
|
||||||
|
if isinstance(other, six.string_types):
|
||||||
|
other = Target(other)
|
||||||
|
|
||||||
|
if not isinstance(other, Target):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return method(self, other)
|
||||||
|
|
||||||
|
return _impl
|
||||||
|
|
||||||
|
|
||||||
|
class Target(object):
|
||||||
|
def __init__(self, name, module_name=None):
|
||||||
|
"""Target models microarchitectures and their compatibility.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str or Microarchitecture): microarchitecture of the target
|
||||||
|
module_name (str): optional module name to get access to the
|
||||||
|
current target. This is typically used on machines
|
||||||
|
like Cray (e.g. craype-compiler)
|
||||||
|
"""
|
||||||
|
if not isinstance(name, archspec.cpu.Microarchitecture):
|
||||||
|
name = archspec.cpu.TARGETS.get(
|
||||||
|
name, archspec.cpu.generic_microarchitecture(name)
|
||||||
|
)
|
||||||
|
self.microarchitecture = name
|
||||||
|
self.module_name = module_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.microarchitecture.name
|
||||||
|
|
||||||
|
@_ensure_other_is_target
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (self.microarchitecture == other.microarchitecture and
|
||||||
|
self.module_name == other.module_name)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
# This method is necessary as long as we support Python 2. In Python 3
|
||||||
|
# __ne__ defaults to the implementation below
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
@_ensure_other_is_target
|
||||||
|
def __lt__(self, other):
|
||||||
|
# TODO: In the future it would be convenient to say
|
||||||
|
# TODO: `spec.architecture.target < other.architecture.target`
|
||||||
|
# TODO: and change the semantic of the comparison operators
|
||||||
|
|
||||||
|
# This is needed to sort deterministically specs in a list.
|
||||||
|
# It doesn't implement a total ordering semantic.
|
||||||
|
return self.microarchitecture.name < other.microarchitecture.name
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.name, self.module_name))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict_or_value(dict_or_value):
|
||||||
|
# A string here represents a generic target (like x86_64 or ppc64) or
|
||||||
|
# a custom micro-architecture
|
||||||
|
if isinstance(dict_or_value, six.string_types):
|
||||||
|
return Target(dict_or_value)
|
||||||
|
|
||||||
|
# TODO: From a dict we actually retrieve much more information than
|
||||||
|
# TODO: just the name. We can use that information to reconstruct an
|
||||||
|
# TODO: "old" micro-architecture or check the current definition.
|
||||||
|
target_info = dict_or_value
|
||||||
|
return Target(target_info['name'])
|
||||||
|
|
||||||
|
def to_dict_or_value(self):
|
||||||
|
"""Returns a dict or a value representing the current target.
|
||||||
|
|
||||||
|
String values are used to keep backward compatibility with generic
|
||||||
|
targets, like e.g. x86_64 or ppc64. More specific micro-architectures
|
||||||
|
will return a dictionary which contains information on the name,
|
||||||
|
features, vendor, generation and parents of the current target.
|
||||||
|
"""
|
||||||
|
# Generic targets represent either an architecture
|
||||||
|
# family (like x86_64) or a custom micro-architecture
|
||||||
|
if self.microarchitecture.vendor == 'generic':
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
return syaml.syaml_dict(
|
||||||
|
self.microarchitecture.to_dict(return_list_of_items=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
cls_name = self.__class__.__name__
|
||||||
|
fmt = cls_name + '({0}, {1})'
|
||||||
|
return fmt.format(repr(self.microarchitecture),
|
||||||
|
repr(self.module_name))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.microarchitecture)
|
||||||
|
|
||||||
|
def __contains__(self, cpu_flag):
|
||||||
|
return cpu_flag in self.microarchitecture
|
||||||
|
|
||||||
|
def optimization_flags(self, compiler):
|
||||||
|
"""Returns the flags needed to optimize for this target using
|
||||||
|
the compiler passed as argument.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
compiler (spack.spec.CompilerSpec or spack.compiler.Compiler): object that
|
||||||
|
contains both the name and the version of the compiler we want to use
|
||||||
|
"""
|
||||||
|
# Mixed toolchains are not supported yet
|
||||||
|
if isinstance(compiler, spack.compiler.Compiler):
|
||||||
|
if spack.compilers.is_mixed_toolchain(compiler):
|
||||||
|
msg = ('microarchitecture specific optimizations are not '
|
||||||
|
'supported yet on mixed compiler toolchains [check'
|
||||||
|
' {0.name}@{0.version} for further details]')
|
||||||
|
warnings.warn(msg.format(compiler))
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# Try to check if the current compiler comes with a version number or
|
||||||
|
# has an unexpected suffix. If so, treat it as a compiler with a
|
||||||
|
# custom spec.
|
||||||
|
compiler_version = compiler.version
|
||||||
|
version_number, suffix = archspec.cpu.version_components(
|
||||||
|
compiler.version
|
||||||
|
)
|
||||||
|
if not version_number or suffix not in ('', 'apple'):
|
||||||
|
# Try to deduce the underlying version of the compiler, regardless
|
||||||
|
# of its name in compilers.yaml. Depending on where this function
|
||||||
|
# is called we might get either a CompilerSpec or a fully fledged
|
||||||
|
# compiler object.
|
||||||
|
if isinstance(compiler, spack.spec.CompilerSpec):
|
||||||
|
compiler = spack.compilers.compilers_for_spec(compiler).pop()
|
||||||
|
try:
|
||||||
|
compiler_version = compiler.real_version
|
||||||
|
except spack.util.executable.ProcessError as e:
|
||||||
|
# log this and just return compiler.version instead
|
||||||
|
tty.debug(str(e))
|
||||||
|
|
||||||
|
return self.microarchitecture.optimization_flags(
|
||||||
|
compiler.name, str(compiler_version)
|
||||||
|
)
|
|
@ -9,8 +9,10 @@
|
||||||
|
|
||||||
import spack.architecture
|
import spack.architecture
|
||||||
import spack.concretize
|
import spack.concretize
|
||||||
|
import spack.operating_systems
|
||||||
import spack.platforms
|
import spack.platforms
|
||||||
import spack.spec
|
import spack.spec
|
||||||
|
import spack.target
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -66,9 +68,9 @@ def test_dict_round_trip(sample_arch):
|
||||||
assert sample_arch == sample_arch_copy
|
assert sample_arch == sample_arch_copy
|
||||||
for current_arch in (sample_arch, sample_arch_copy):
|
for current_arch in (sample_arch, sample_arch_copy):
|
||||||
assert isinstance(current_arch, spack.architecture.Arch)
|
assert isinstance(current_arch, spack.architecture.Arch)
|
||||||
assert isinstance(current_arch.platform, spack.architecture.Platform)
|
assert isinstance(current_arch.platform, spack.platforms.Platform)
|
||||||
assert isinstance(current_arch.os, spack.architecture.OperatingSystem)
|
assert isinstance(current_arch.os, spack.operating_systems.OperatingSystem)
|
||||||
assert isinstance(current_arch.target, spack.architecture.Target)
|
assert isinstance(current_arch.target, spack.target.Target)
|
||||||
|
|
||||||
|
|
||||||
def test_platform(current_host_platform):
|
def test_platform(current_host_platform):
|
||||||
|
@ -111,7 +113,7 @@ def test_user_input_combination(config, target_str, os_str):
|
||||||
|
|
||||||
|
|
||||||
def test_operating_system_conversion_to_dict():
|
def test_operating_system_conversion_to_dict():
|
||||||
operating_system = spack.architecture.OperatingSystem('os', '1.0')
|
operating_system = spack.operating_systems.OperatingSystem('os', '1.0')
|
||||||
assert operating_system.to_dict() == {
|
assert operating_system.to_dict() == {
|
||||||
'name': 'os', 'version': '1.0'
|
'name': 'os', 'version': '1.0'
|
||||||
}
|
}
|
||||||
|
@ -129,7 +131,7 @@ def test_operating_system_conversion_to_dict():
|
||||||
('avx512', 'icelake'),
|
('avx512', 'icelake'),
|
||||||
])
|
])
|
||||||
def test_target_container_semantic(cpu_flag, target_name):
|
def test_target_container_semantic(cpu_flag, target_name):
|
||||||
target = spack.architecture.Target(target_name)
|
target = spack.target.Target(target_name)
|
||||||
assert cpu_flag in target
|
assert cpu_flag in target
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,7 +161,7 @@ def test_arch_spec_container_semantic(item, architecture_str):
|
||||||
def test_optimization_flags(
|
def test_optimization_flags(
|
||||||
compiler_spec, target_name, expected_flags, config
|
compiler_spec, target_name, expected_flags, config
|
||||||
):
|
):
|
||||||
target = spack.architecture.Target(target_name)
|
target = spack.target.Target(target_name)
|
||||||
compiler = spack.compilers.compilers_for_spec(compiler_spec).pop()
|
compiler = spack.compilers.compilers_for_spec(compiler_spec).pop()
|
||||||
opt_flags = target.optimization_flags(compiler)
|
opt_flags = target.optimization_flags(compiler)
|
||||||
assert opt_flags == expected_flags
|
assert opt_flags == expected_flags
|
||||||
|
@ -182,7 +184,7 @@ def test_optimization_flags(
|
||||||
def test_optimization_flags_with_custom_versions(
|
def test_optimization_flags_with_custom_versions(
|
||||||
compiler, real_version, target_str, expected_flags, monkeypatch, config
|
compiler, real_version, target_str, expected_flags, monkeypatch, config
|
||||||
):
|
):
|
||||||
target = spack.architecture.Target(target_str)
|
target = spack.target.Target(target_str)
|
||||||
if real_version:
|
if real_version:
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
spack.compiler.Compiler, 'get_real_version',
|
spack.compiler.Compiler, 'get_real_version',
|
||||||
|
|
|
@ -98,9 +98,6 @@ def current_host(request, monkeypatch):
|
||||||
cpu, _, is_preference = request.param.partition('-')
|
cpu, _, is_preference = request.param.partition('-')
|
||||||
target = archspec.cpu.TARGETS[cpu]
|
target = archspec.cpu.TARGETS[cpu]
|
||||||
|
|
||||||
# this function is memoized, so clear its state for testing
|
|
||||||
spack.architecture.get_platform.cache.clear()
|
|
||||||
|
|
||||||
monkeypatch.setattr(spack.platforms.Test, 'default', cpu)
|
monkeypatch.setattr(spack.platforms.Test, 'default', cpu)
|
||||||
monkeypatch.setattr(spack.platforms.Test, 'front_end', cpu)
|
monkeypatch.setattr(spack.platforms.Test, 'front_end', cpu)
|
||||||
if not is_preference:
|
if not is_preference:
|
||||||
|
@ -110,9 +107,6 @@ def current_host(request, monkeypatch):
|
||||||
with spack.config.override('packages:all', {'target': [cpu]}):
|
with spack.config.override('packages:all', {'target': [cpu]}):
|
||||||
yield target
|
yield target
|
||||||
|
|
||||||
# clear any test values fetched
|
|
||||||
spack.architecture.get_platform.cache.clear()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def repo_with_changing_recipe(tmpdir_factory, mutable_mock_repo):
|
def repo_with_changing_recipe(tmpdir_factory, mutable_mock_repo):
|
||||||
|
|
|
@ -2,11 +2,8 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import spack.architecture
|
|
||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,8 +108,8 @@ def configure_args(self):
|
||||||
# Versions < 2.1.1 have a bug in the test code that *sometimes*
|
# Versions < 2.1.1 have a bug in the test code that *sometimes*
|
||||||
# causes problems on strict alignment architectures such as
|
# causes problems on strict alignment architectures such as
|
||||||
# aarch64. Work-around is to just not build the test code.
|
# aarch64. Work-around is to just not build the test code.
|
||||||
if 'aarch64' in spack.architecture.sys_type() and \
|
if (self.spec.satisfies('target=aarch64:') and
|
||||||
self.spec.version < Version('2.1.1'):
|
self.spec.version < Version('2.1.1')):
|
||||||
config_args.append('--without-tests-examples')
|
config_args.append('--without-tests-examples')
|
||||||
|
|
||||||
# Versions >= 3.0 also use hwloc
|
# Versions >= 3.0 also use hwloc
|
||||||
|
|
Loading…
Reference in a new issue