diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/architecture.py | 216 |
1 files changed, 105 insertions, 111 deletions
diff --git a/lib/spack/spack/architecture.py b/lib/spack/spack/architecture.py index 88cebc0943..e74e72d6cd 100644 --- a/lib/spack/spack/architecture.py +++ b/lib/spack/spack/architecture.py @@ -29,8 +29,9 @@ and the architecture platform (i.e. cray, darwin, linux, bgq, etc) classes. 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 -platform. On Cray platforms or any other architecture that has different front and -back end environments, the operating system will determine the method of compiler +platform. On Cray platforms or any other architecture that has different front +and back end environments, the operating system will determine the method of +compiler detection. There are two different types of compiler detection: @@ -40,44 +41,42 @@ There are two different types of compiler detection: Depending on which operating system is specified, the compiler will be detected using one of those methods. -For platforms such as linux and darwin, the operating system is autodetected and -the target is set to be x86_64. +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: target=<Target name> os=<OperatingSystem name> If the user wishes to use the defaults, either target or os can be left out of -the command line and Spack will concretize using the default. These defaults are -set in the 'platforms/' directory which contains the different subclasses for -platforms. If the machine has multiple architectures, the user can +the command line and Spack will concretize using the default. These defaults +are set in the 'platforms/' directory which contains the different subclasses +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 to their respective front-end and back-end 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 -wants to add a new type of platform (such as cray_xe), they can create a subclass -and set all the class attributes such as priority, front_target ,back_target, -front_os, back_os. Platforms also contain a priority class attribute. A lower -number signifies higher priority. These numbers are arbitrarily set and can be -changed though often there isn't much need unless a new platform is added and -the user wants that to be detected first. - -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 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 +wants to add a new type of platform (such as cray_xe), they can create a +subclass and set all the class attributes such as priority, front_target, +back_target, front_os, back_os. Platforms also contain a priority class +attribute. A lower number signifies higher priority. These numbers are +arbitrarily set and can be changed though often there isn't much need unless a +new platform is added and the user wants that to be detected first. + +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 +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 Depending on the platform, operating systems are either auto-detected or are set. The user can set the front-end and back-end operating setting by the class -attributes front_os and back_os. The operating system as described earlier, will -be responsible for compiler detection. +attributes front_os and back_os. The operating system as described earlier, +will be responsible for compiler detection. """ import os -from collections import namedtuple import imp -import platform as py_platform import inspect from llnl.util.lang import memoized, list_modules, key_ordering @@ -91,6 +90,7 @@ from spack.util.environment import get_path from spack.util.multiproc import parmap import spack.error as serr + class InvalidSysTypeError(serr.SpackError): def __init__(self, sys_type): super(InvalidSysTypeError, self).__init__( @@ -128,12 +128,6 @@ class Target(object): def __str__(self): return self.name - def to_dict(self): - d = {} - d['name'] = self.name - d['module_name'] = self.module_name - - return d @key_ordering class Platform(object): @@ -142,7 +136,7 @@ class Platform(object): is returned """ - priority = None # Subclass needs to set this number. This controls order in which platform is detected. + priority = None # Subclass sets number. Controls detection order front_end = None back_end = None default = None # The default back end target. On cray ivybridge @@ -156,19 +150,6 @@ class Platform(object): self.operating_sys = {} self.name = name - def to_dict(self): - n = {} - n['targets'] = dict((name, target.to_dict()) for (name, target) in self.targets.items()) - n['operating_systems'] = dict((name, os.to_dict()) for (name, os) in self.operating_sys.items()) - n['priority'] = self.priority - n['default_front_end_target'] = self.front_end - n['default_back_end_target'] = self.back_end - n['default_target'] = self.default - n['default_front_end_os'] = self.front_os - n['default_back_end_os'] = self.back_os - n['default_os'] = self.default_os - return {self.name: n} - 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 @@ -215,7 +196,6 @@ class Platform(object): return self.operating_sys.get(name, None) - @classmethod def detect(self): """ Subclass is responsible for implementing this method. @@ -232,8 +212,10 @@ class Platform(object): return self.name def _cmp_key(self): - t_keys = ''.join(str(t._cmp_key()) for t in sorted(self.targets.values())) - o_keys = ''.join(str(o._cmp_key()) for o in sorted(self.operating_sys.values())) + t_keys = ''.join(str(t._cmp_key()) for t in + sorted(self.targets.values())) + o_keys = ''.join(str(o._cmp_key()) for o in + sorted(self.operating_sys.values())) return (self.name, self.default, self.front_end, @@ -244,6 +226,7 @@ class Platform(object): t_keys, o_keys) + @key_ordering class OperatingSystem(object): """ Operating System will be like a class similar to platform extended @@ -265,7 +248,6 @@ class OperatingSystem(object): def _cmp_key(self): return (self.name, self.version) - def find_compilers(self, *paths): """ Return a list of compilers found in the suppied paths. @@ -293,11 +275,13 @@ class OperatingSystem(object): # compiler. We can spawn a bunch of parallel searches to reduce # the overhead of spelunking all these directories. types = spack.compilers.all_compiler_types() - compiler_lists = parmap(lambda cmp_cls: self.find_compiler(cmp_cls, *filtered_path), types) + compiler_lists = parmap(lambda cmp_cls: + self.find_compiler(cmp_cls, *filtered_path), + types) # ensure all the version calls we made are cached in the parent # process, as well. This speeds up Spack a lot. - clist = reduce(lambda x,y: x+y, compiler_lists) + clist = reduce(lambda x, y: x+y, compiler_lists) return clist def find_compiler(self, cmp_cls, *path): @@ -338,7 +322,7 @@ class OperatingSystem(object): # prefer the one with more compilers. prev_paths = [prev.cc, prev.cxx, prev.f77, prev.fc] - newcount = len([p for p in paths if p is not None]) + newcount = len([p for p in paths if p is not None]) prevcount = len([p for p in prev_paths if p is not None]) # Don't add if it's not an improvement over prev compiler. @@ -349,14 +333,7 @@ class OperatingSystem(object): return list(compilers.values()) - def to_dict(self): - d = {} - d['name'] = self.name - d['version'] = self.version - return d - -#NOTE: Key error caused because Architecture has no comparison method @key_ordering class Arch(object): "Architecture is now a class to help with setting attributes" @@ -376,10 +353,11 @@ class Arch(object): @property def concrete(self): - return all( (self.platform is not None, isinstance(self.platform, Platform), - self.platform_os is not None, isinstance(self.platform_os, OperatingSystem), - self.target is not None, isinstance(self.target, Target) ) ) - + return all((self.platform is not None, + isinstance(self.platform, Platform), + self.platform_os is not None, + isinstance(self.platform_os, OperatingSystem), + self.target is not None, isinstance(self.target, Target))) def __str__(self): if self.platform or self.platform_os or self.target: @@ -388,71 +366,75 @@ class Arch(object): else: os_name = str(self.platform_os) - return (str(self.platform) +"-"+ + return (str(self.platform) + "-" + os_name + "-" + str(self.target)) else: return '' def _cmp_key(self): - platform = self.platform.name if isinstance(self.platform, Platform) else self.platform - os = self.platform_os.name if isinstance(self.platform_os, OperatingSystem) else self.platform_os - target = self.target.name if isinstance(self.target, Target) else self.target - return (platform, os, target) + if isinstance(self.platform, Platform): + platform = self.platform.name + else: + platform = self.platform + if isinstance(self.platform_os, OperatingSystem): + platform_os = self.platform_os.name + else: + platform_os = self.platform_os + if isinstance(self.target, Target): + target = self.target.name + else: + target = self.target + print (platform, platform_os, target) + return (platform, platform_os, target) def to_dict(self): d = {} - platform = self.platform - platform_os = self.platform_os - target = self.target - - d['platform'] = self.platform.to_dict() if self.platform else None - d['platform_os'] = self.platform_os.to_dict() if self.platform_os else None - d['target'] = self.target.to_dict() if self.target else None + d['platform'] = str(self.platform) if self.platform else None + d['platform_os'] = str(self.platform_os) if self.platform_os else None + d['target'] = str(self.target) if self.target else None return d -def _target_from_dict(target_dict): +def _target_from_dict(target_name, platform=None): """ Creates new instance of target and assigns all the attributes of that target from the dictionary """ - target = Target.__new__(Target) - target.name = target_dict['name'] - target.module_name = target_dict['module_name'] - if 'platform_name' in target_dict: - target.platform_name = target_dict['platform_name'] - return target - -def _operating_system_from_dict(os_dict): + if not platform: + platform = sys_type() + return platform.target(target_name) + + +def _operating_system_from_dict(os_name, platform=None): """ uses platform's operating system method to grab the constructed operating systems that are valid on the platform. """ -# NOTE: Might need a better way to create operating system objects - operating_system = OperatingSystem.__new__(OperatingSystem) - operating_system.name = os_dict['name'] - operating_system.version = os_dict['version'] - return operating_system + if not platform: + platform = sys_type() + if isinstance(os_name, spack.util.spack_yaml.syaml_dict): + name = os_name['name'] + version = os_name['version'] + return platform.operating_system(name+version) + else: + return platform.operating_system(os_name) + -def _platform_from_dict(platform_dict): +def _platform_from_dict(platform_name): """ Constructs a platform from a dictionary. """ - platform = Platform.__new__(Platform) - name, p_dict = platform_dict.items()[0] - platform.name = name - platform.targets = {} - for name, t_dict in p_dict['targets'].items(): - platform.add_target(name, _target_from_dict(t_dict)) - platform.operating_sys = {} - for name, o_dict in p_dict['operating_systems'].items(): - platform.add_operating_system(name, _operating_system_from_dict(o_dict)) - platform.priority = p_dict['priority'] - platform.front_end = p_dict['default_front_end_target'] - platform.back_end = p_dict['default_back_end_target'] - platform.default = p_dict['default_target'] - platform.front_os = p_dict['default_front_end_os'] - platform.back_os = p_dict['default_back_end_os'] - platform.default_os = p_dict['default_os'] - - return platform + platform_path = spack.platform_path + mod_string = "spack.platforms" + + for p in list_modules(platform_path): + if platform_name == p: + mod_name = mod_string + platform_name + path = join_path(platform_path, platform_name) + ".py" + mod = imp.load_source(mod_name, path) + platform_class = mod_to_class(platform_name) + cls = getattr(mod, platform_class) + platform = cls() + return platform + return None + def arch_from_dict(d): """ Uses _platform_from_dict, _operating_system_from_dict, _target_from_dict @@ -472,19 +454,30 @@ def arch_from_dict(d): else: if d is None: return None - platform_dict = d['platform'] - os_dict = d['platform_os'] - target_dict = d['target'] + platform_name = d['platform'] + os_name = d['platform_os'] + target_name = d['target'] - arch.platform = _platform_from_dict(platform_dict) if platform_dict else None - arch.target = _target_from_dict(target_dict) if os_dict else None - arch.platform_os = _operating_system_from_dict(os_dict) if os_dict else None + if platform_name: + arch.platform = _platform_from_dict(platform_name) + else: + arch.platform = None + if target_name: + arch.target = _target_from_dict(target_name, arch.platform) + else: + arch.target = None + if os_name: + arch.platform_os = _operating_system_from_dict(os_name, + arch.platform) + else: + arch.platform_os = None arch.os_string = None arch.target_string = None return arch + @memoized def all_platforms(): classes = [] @@ -505,6 +498,7 @@ def all_platforms(): return classes + @memoized def sys_type(): """ Gather a list of all available subclasses of platforms. |