diff options
author | Todd Gamblin <tgamblin@llnl.gov> | 2022-07-30 15:19:18 -0700 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2022-07-31 13:29:20 -0700 |
commit | f52f6e99dbf1131886a80112b8c79dfc414afb7c (patch) | |
tree | 05cb7d64b2395922f2f24683da49f472075be12c /lib/spack/spack/build_systems/intel.py | |
parent | 549ba1ed32372c67fc57271cde3797d58b7dec6e (diff) | |
download | spack-f52f6e99dbf1131886a80112b8c79dfc414afb7c.tar.gz spack-f52f6e99dbf1131886a80112b8c79dfc414afb7c.tar.bz2 spack-f52f6e99dbf1131886a80112b8c79dfc414afb7c.tar.xz spack-f52f6e99dbf1131886a80112b8c79dfc414afb7c.zip |
black: reformat entire repository with black
Diffstat (limited to 'lib/spack/spack/build_systems/intel.py')
-rw-r--r-- | lib/spack/spack/build_systems/intel.py | 837 |
1 files changed, 424 insertions, 413 deletions
diff --git a/lib/spack/spack/build_systems/intel.py b/lib/spack/spack/build_systems/intel.py index a249afff90..133b5030de 100644 --- a/lib/spack/spack/build_systems/intel.py +++ b/lib/spack/spack/build_systems/intel.py @@ -38,25 +38,24 @@ from spack.version import Version, ver def debug_print(msg, *args): - '''Prints a message (usu. a variable) and the callers' names for a couple + """Prints a message (usu. a variable) and the callers' names for a couple of stack frames. - ''' + """ # https://docs.python.org/2/library/inspect.html#the-interpreter-stack stack = inspect.stack() _func_name = 3 - tty.debug("%s.%s:\t%s" % (stack[2][_func_name], stack[1][_func_name], msg), - *args) + tty.debug("%s.%s:\t%s" % (stack[2][_func_name], stack[1][_func_name], msg), *args) def raise_lib_error(*args): - '''Bails out with an error message. Shows args after the first as one per + """Bails out with an error message. Shows args after the first as one per line, tab-indented, useful for long paths to line up and stand out. - ''' + """ raise InstallError("\n\t".join(str(i) for i in args)) def _expand_fields(s): - '''[Experimental] Expand arch-related fields in a string, typically a + """[Experimental] Expand arch-related fields in a string, typically a filename. Supported fields and their typical expansions are:: @@ -66,24 +65,24 @@ def _expand_fields(s): {libarch} intel64, empty on Mac {bits} 64 - ''' + """ # Python-native string formatting requires arg list counts to match the # replacement field count; optional fields are far easier with regexes. - _bits = '64' - _arch = 'intel64' # TBD: ia32 + _bits = "64" + _arch = "intel64" # TBD: ia32 - if 'linux' in sys.platform: # NB: linux2 vs. linux - s = re.sub('{platform}', 'linux', s) - s = re.sub('{libarch}', _arch, s) - elif 'darwin' in sys.platform: - s = re.sub('{platform}', 'mac', s) - s = re.sub('{libarch}', '', s) # no arch dirs are used (as of 2018) + if "linux" in sys.platform: # NB: linux2 vs. linux + s = re.sub("{platform}", "linux", s) + s = re.sub("{libarch}", _arch, s) + elif "darwin" in sys.platform: + s = re.sub("{platform}", "mac", s) + s = re.sub("{libarch}", "", s) # no arch dirs are used (as of 2018) # elif 'win' in sys.platform: # TBD # s = re.sub('{platform}', 'windows', s) - s = re.sub('{arch}', _arch, s) - s = re.sub('{bits}', _bits, s) + s = re.sub("{arch}", _arch, s) + s = re.sub("{bits}", _bits, s) return s @@ -99,12 +98,13 @@ class IntelPackage(PackageBase): only thing necessary will be to override setup_run_environment to set the appropriate environment variables. """ + #: Phases of an Intel package - phases = ['configure', 'install'] + phases = ["configure", "install"] #: This attribute is used in UI queries that need to know the build #: system base class - build_system_class = 'IntelPackage' + build_system_class = "IntelPackage" #: A dict that maps Spack version specs to release years, needed to infer #: the installation directory layout for pre-2016 versions in the family of @@ -117,54 +117,65 @@ class IntelPackage(PackageBase): # that satisfies self.spec will be used. version_years = { # intel-daal is versioned 2016 and later, no divining is needed - 'intel-ipp@9.0:9': 2016, - 'intel-mkl@11.3.0:11.3': 2016, - 'intel-mpi@5.1:5': 2016, + "intel-ipp@9.0:9": 2016, + "intel-mkl@11.3.0:11.3": 2016, + "intel-mpi@5.1:5": 2016, } # Below is the list of possible values for setting auto dispatch functions # for the Intel compilers. Using these allows for the building of fat # binaries that will detect the CPU SIMD capabilities at run time and # activate the appropriate extensions. - auto_dispatch_options = ('COMMON-AVX512', 'MIC-AVX512', 'CORE-AVX512', - 'CORE-AVX2', 'CORE-AVX-I', 'AVX', 'SSE4.2', - 'SSE4.1', 'SSSE3', 'SSE3', 'SSE2') + auto_dispatch_options = ( + "COMMON-AVX512", + "MIC-AVX512", + "CORE-AVX512", + "CORE-AVX2", + "CORE-AVX-I", + "AVX", + "SSE4.2", + "SSE4.1", + "SSSE3", + "SSE3", + "SSE2", + ) @property def license_required(self): # The Intel libraries are provided without requiring a license as of # version 2017.2. Trying to specify one anyway will fail. See: # https://software.intel.com/en-us/articles/free-ipsxe-tools-and-libraries - return self._has_compilers or self.version < ver('2017.2') + return self._has_compilers or self.version < ver("2017.2") #: Comment symbol used in the license.lic file - license_comment = '#' + license_comment = "#" #: Environment variables that Intel searches for a license file - license_vars = ['INTEL_LICENSE_FILE'] + license_vars = ["INTEL_LICENSE_FILE"] #: URL providing information on how to acquire a license key - license_url = 'https://software.intel.com/en-us/articles/intel-license-manager-faq' + license_url = "https://software.intel.com/en-us/articles/intel-license-manager-faq" #: Location where Intel searches for a license file @property def license_files(self): - dirs = ['Licenses'] + dirs = ["Licenses"] if self._has_compilers: - dirs.append(self.component_bin_dir('compiler')) + dirs.append(self.component_bin_dir("compiler")) for variant, component_suite_dir in { - '+advisor': 'advisor', - '+inspector': 'inspector', - '+itac': 'itac', - '+vtune': 'vtune_profiler', + "+advisor": "advisor", + "+inspector": "inspector", + "+itac": "itac", + "+vtune": "vtune_profiler", }.items(): if variant in self.spec: - dirs.append(self.normalize_path( - 'licenses', component_suite_dir, relative=True)) + dirs.append( + self.normalize_path("licenses", component_suite_dir, relative=True) + ) - files = [os.path.join(d, 'license.lic') for d in dirs] + files = [os.path.join(d, "license.lic") for d in dirs] return files #: Components to install (list of name patterns from pset/mediaconfig.xml) @@ -173,7 +184,7 @@ class IntelPackage(PackageBase): def pset_components(self): # Do not detail single-purpose client packages. if not self._has_compilers: - return ['ALL'] + return ["ALL"] # tty.warn('DEBUG: installing ALL components') # return ['ALL'] @@ -183,34 +194,35 @@ class IntelPackage(PackageBase): # Later releases have overlapping minor parts that differ by "edition". # NB: The spack package 'intel' is a subset of # 'intel-parallel-studio@composer' without the lib variants. - c = ' intel-icc intel-ifort' \ - ' intel-ccomp intel-fcomp intel-comp-' \ - ' intel-compilerproc intel-compilerprof intel-compilerpro-' \ - ' intel-psxe intel-openmp' + c = ( + " intel-icc intel-ifort" + " intel-ccomp intel-fcomp intel-comp-" + " intel-compilerproc intel-compilerprof intel-compilerpro-" + " intel-psxe intel-openmp" + ) additions_for = { - 'cluster': ' intel-icsxe', - 'professional': ' intel-ips-', - 'composer': ' intel-compxe', + "cluster": " intel-icsxe", + "professional": " intel-ips-", + "composer": " intel-compxe", } if self._edition in additions_for: c += additions_for[self._edition] for variant, components_to_add in { - '+daal': ' intel-daal', # Data Analytics Acceleration Lib - '+gdb': ' intel-gdb', # Integrated Performance Primitives - '+ipp': ' intel-ipp intel-crypto-ipp', - '+mkl': ' intel-mkl', # Math Kernel Library - '+mpi': ' intel-mpi intel-imb', # MPI runtime, SDK, benchm. - '+tbb': ' intel-tbb', # Threading Building Blocks - '+advisor': ' intel-advisor', - '+clck': ' intel_clck', # Cluster Checker - '+inspector': ' intel-inspector', - '+itac': ' intel-itac intel-ta intel-tc' - ' intel-trace-analyzer intel-trace-collector', - # Trace Analyzer and Collector - '+vtune': ' intel-vtune' - # VTune, ..-profiler since 2020, ..-amplifier before + "+daal": " intel-daal", # Data Analytics Acceleration Lib + "+gdb": " intel-gdb", # Integrated Performance Primitives + "+ipp": " intel-ipp intel-crypto-ipp", + "+mkl": " intel-mkl", # Math Kernel Library + "+mpi": " intel-mpi intel-imb", # MPI runtime, SDK, benchm. + "+tbb": " intel-tbb", # Threading Building Blocks + "+advisor": " intel-advisor", + "+clck": " intel_clck", # Cluster Checker + "+inspector": " intel-inspector", + "+itac": " intel-itac intel-ta intel-tc" " intel-trace-analyzer intel-trace-collector", + # Trace Analyzer and Collector + "+vtune": " intel-vtune" + # VTune, ..-profiler since 2020, ..-amplifier before }.items(): if variant in self.spec: c += components_to_add @@ -223,11 +235,11 @@ class IntelPackage(PackageBase): # --------------------------------------------------------------------- @property def _filtered_components(self): - '''Expands the list of desired component patterns to the exact names + """Expands the list of desired component patterns to the exact names present in the given download. - ''' + """ c = self.pset_components - if 'ALL' in c or 'DEFAULTS' in c: # No filter needed + if "ALL" in c or "DEFAULTS" in c: # No filter needed return c # mediaconfig.xml is known to contain duplicate components. @@ -243,8 +255,8 @@ class IntelPackage(PackageBase): # # https://software.intel.com/en-us/articles/configuration-file-format # - xmltree = ElementTree.parse('pset/mediaconfig.xml') - for entry in xmltree.getroot().findall('.//Abbr'): # XPath expression + xmltree = ElementTree.parse("pset/mediaconfig.xml") + for entry in xmltree.getroot().findall(".//Abbr"): # XPath expression name_present = entry.text for name_requested in requested: if name_present.startswith(name_requested): @@ -254,36 +266,36 @@ class IntelPackage(PackageBase): @property def intel64_int_suffix(self): - '''Provide the suffix for Intel library names to match a client + """Provide the suffix for Intel library names to match a client application's desired int size, conveyed by the active spec variant. The possible suffixes and their meanings are: ``ilp64`` all of int, long, and pointer are 64 bit, `` lp64`` only long and pointer are 64 bit; int will be 32bit. - ''' - if '+ilp64' in self.spec: - return 'ilp64' + """ + if "+ilp64" in self.spec: + return "ilp64" else: - return 'lp64' + return "lp64" @property def _has_compilers(self): - return self.name in ['intel', 'intel-parallel-studio'] + return self.name in ["intel", "intel-parallel-studio"] @property def _edition(self): - if self.name == 'intel-parallel-studio': - return self.version[0] # clearer than .up_to(1), I think. - elif self.name == 'intel': - return 'composer' + if self.name == "intel-parallel-studio": + return self.version[0] # clearer than .up_to(1), I think. + elif self.name == "intel": + return "composer" else: - return '' + return "" @property def version_yearlike(self): - '''Return the version in a unified style, suitable for Version class + """Return the version in a unified style, suitable for Version class conditionals. - ''' + """ # Input data for this routine: self.version # Returns: YYYY.Nupdate[.Buildseq] # @@ -309,18 +321,18 @@ class IntelPackage(PackageBase): # (*) YYYY is taken from @property "version_years" (a dict of specs) # try: - if self.name == 'intel': + if self.name == "intel": # Has a "Minor" version element, but it is always set as 0. To # be useful for comparisons, drop it and get YYYY.Nupdate. - v_tail = self.version[2:] # coerced just fine via __getitem__ + v_tail = self.version[2:] # coerced just fine via __getitem__ else: v_tail = self.version[1:] except IndexError: # Hmm - this happens on "spack install intel-mkl@11". # I thought concretization picks an actual version?? - return self.version # give up + return self.version # give up - if self.name == 'intel-parallel-studio': + if self.name == "intel-parallel-studio": return v_tail v_year = self.version[0] @@ -332,7 +344,7 @@ class IntelPackage(PackageBase): v_year = year break - return ver('%s.%s' % (v_year, v_tail)) + return ver("%s.%s" % (v_year, v_tail)) # --------------------------------------------------------------------- # Directory handling common to all Intel components @@ -345,8 +357,8 @@ class IntelPackage(PackageBase): # Not using class IntelPackage: # intel-gpu-tools/ intel-mkl-dnn/ intel-tbb/ # - def normalize_suite_dir(self, suite_dir_name, version_globs=['*.*.*']): - '''Returns the version-specific and absolute path to the directory of + def normalize_suite_dir(self, suite_dir_name, version_globs=["*.*.*"]): + """Returns the version-specific and absolute path to the directory of an Intel product or a suite of product components. Parameters: @@ -373,7 +385,7 @@ class IntelPackage(PackageBase): first) expected to qualify suite_dir_name to its fully version-specific install directory (as opposed to a compatibility directory or symlink). - ''' + """ # See ./README-intel.rst for background and analysis of dir layouts. d = self.prefix @@ -381,7 +393,7 @@ class IntelPackage(PackageBase): # Distinguish between product installations that were done external to # Spack (integrated via packages.yaml) and Spack-internal ones. The # resulting prefixes may differ in directory depth and specificity. - unversioned_dirname = '' + unversioned_dirname = "" if suite_dir_name and suite_dir_name in d: # If e.g. MKL was installed outside of Spack, it is likely just one # product or product component among possibly many other Intel @@ -391,8 +403,7 @@ class IntelPackage(PackageBase): # version-specific directory. This is what we want and need, and # nothing more specific than that, i.e., if needed, convert, e.g.: # .../compilers_and_libraries*/* -> .../compilers_and_libraries* - d = re.sub('(%s%s.*?)%s.*' % - (os.sep, re.escape(suite_dir_name), os.sep), r'\1', d) + d = re.sub("(%s%s.*?)%s.*" % (os.sep, re.escape(suite_dir_name), os.sep), r"\1", d) # The Intel installer scripts try hard to place compatibility links # named like this in the install dir to convey upgrade benefits to @@ -448,15 +459,14 @@ class IntelPackage(PackageBase): if unversioned_dirname: for g in version_globs: try_glob = unversioned_dirname + g - debug_print('trying %s' % try_glob) + debug_print("trying %s" % try_glob) matching_dirs = sorted(glob.glob(try_glob)) # NB: Python glob() returns results in arbitrary order - ugh! # NB2: sorted() is a shortcut that is NOT number-aware. if matching_dirs: - debug_print('found %d:' % len(matching_dirs), - matching_dirs) + debug_print("found %d:" % len(matching_dirs), matching_dirs) # Take the highest and thus presumably newest match, which # better be the sole one anyway. d = matching_dirs[-1] @@ -469,9 +479,8 @@ class IntelPackage(PackageBase): debug_print(d) return Prefix(d) - def normalize_path(self, component_path, component_suite_dir=None, - relative=False): - '''Returns the absolute or relative path to a component or file under a + def normalize_path(self, component_path, component_suite_dir=None, relative=False): + """Returns the absolute or relative path to a component or file under a component suite directory. Intel's product names, scope, and directory layout changed over the @@ -498,7 +507,7 @@ class IntelPackage(PackageBase): relative (bool): When True, return path relative to self.prefix, otherwise, return an absolute path (the default). - ''' + """ # Design note: Choosing the default for `component_suite_dir` was a bit # tricky since there better be a sensible means to specify direct # parentage under self.prefix (even though you normally shouldn't need @@ -518,60 +527,59 @@ class IntelPackage(PackageBase): # are not natively versioned by year. cs = component_suite_dir - if cs is None and component_path.startswith('ism'): - cs = 'parallel_studio_xe' + if cs is None and component_path.startswith("ism"): + cs = "parallel_studio_xe" v = self.version_yearlike # Glob variants to complete component_suite_dir. # Helper var for older MPI versions - those are reparented, with each # version in their own version-named dir. - standalone_glob = '[1-9]*.*.*' + standalone_glob = "[1-9]*.*.*" # Most other components; try most specific glob first. # flake8 is far too opinionated about lists - ugh. normalize_kwargs = { - 'version_globs': [ - '_%s' % self.version, - '_%s.*' % v.up_to(2), # should be: YYYY.Nupdate - '_*.*.*', # last resort + "version_globs": [ + "_%s" % self.version, + "_%s.*" % v.up_to(2), # should be: YYYY.Nupdate + "_*.*.*", # last resort ] } for rename_rule in [ # cs given as arg, in years, dir actually used, [version_globs] - [None, ':2015', 'composer_xe'], - [None, '2016:', 'compilers_and_libraries'], - ['advisor', ':2016', 'advisor_xe'], - ['inspector', ':2016', 'inspector_xe'], - ['vtune_profiler', ':2017', 'vtune_amplifier_xe'], - ['vtune', ':2017', 'vtune_amplifier_xe'], # alt. - ['vtune_profiler', ':2019', 'vtune_amplifier'], - ['itac', ':', 'itac', [os.sep + standalone_glob]], + [None, ":2015", "composer_xe"], + [None, "2016:", "compilers_and_libraries"], + ["advisor", ":2016", "advisor_xe"], + ["inspector", ":2016", "inspector_xe"], + ["vtune_profiler", ":2017", "vtune_amplifier_xe"], + ["vtune", ":2017", "vtune_amplifier_xe"], # alt. + ["vtune_profiler", ":2019", "vtune_amplifier"], + ["itac", ":", "itac", [os.sep + standalone_glob]], ]: if cs == rename_rule[0] and v.satisfies(ver(rename_rule[1])): cs = rename_rule[2] if len(rename_rule) > 3: - normalize_kwargs = {'version_globs': rename_rule[3]} + normalize_kwargs = {"version_globs": rename_rule[3]} break d = self.normalize_suite_dir(cs, **normalize_kwargs) # Help find components not located directly under d. # NB: ancestor() not well suited if version_globs may contain os.sep . - parent_dir = re.sub(os.sep + re.escape(cs) + '.*', '', d) + parent_dir = re.sub(os.sep + re.escape(cs) + ".*", "", d) reparent_as = {} - if cs == 'compilers_and_libraries': # must qualify further - d = os.path.join(d, _expand_fields('{platform}')) - elif cs == 'composer_xe': - reparent_as = {'mpi': 'impi'} + if cs == "compilers_and_libraries": # must qualify further + d = os.path.join(d, _expand_fields("{platform}")) + elif cs == "composer_xe": + reparent_as = {"mpi": "impi"} # ignore 'imb' (MPI Benchmarks) for nominal_p, actual_p in reparent_as.items(): if component_path.startswith(nominal_p): - dirs = glob.glob( - os.path.join(parent_dir, actual_p, standalone_glob)) - debug_print('reparent dirs: %s' % dirs) + dirs = glob.glob(os.path.join(parent_dir, actual_p, standalone_glob)) + debug_print("reparent dirs: %s" % dirs) # Brazenly assume last match is the most recent version; # convert back to relative of parent_dir, and re-assemble. rel_dir = dirs[-1].split(parent_dir + os.sep, 1)[-1] @@ -589,31 +597,31 @@ class IntelPackage(PackageBase): def component_bin_dir(self, component, **kwargs): d = self.normalize_path(component, **kwargs) - if component == 'compiler': # bin dir is always under PARENT - d = os.path.join(ancestor(d), 'bin', _expand_fields('{libarch}')) - d = d.rstrip(os.sep) # cosmetics, when {libarch} is empty + if component == "compiler": # bin dir is always under PARENT + d = os.path.join(ancestor(d), "bin", _expand_fields("{libarch}")) + d = d.rstrip(os.sep) # cosmetics, when {libarch} is empty # NB: Works fine even with relative=True, e.g.: # composer_xe/compiler -> composer_xe/bin/intel64 - elif component == 'mpi': - d = os.path.join(d, _expand_fields('{libarch}'), 'bin') + elif component == "mpi": + d = os.path.join(d, _expand_fields("{libarch}"), "bin") else: - d = os.path.join(d, 'bin') + d = os.path.join(d, "bin") debug_print(d) return d def component_lib_dir(self, component, **kwargs): - '''Provide directory suitable for find_libraries() and + """Provide directory suitable for find_libraries() and SPACK_COMPILER_EXTRA_RPATHS. - ''' + """ d = self.normalize_path(component, **kwargs) - if component == 'mpi': - d = os.path.join(d, _expand_fields('{libarch}'), 'lib') + if component == "mpi": + d = os.path.join(d, _expand_fields("{libarch}"), "lib") else: - d = os.path.join(d, 'lib', _expand_fields('{libarch}')) - d = d.rstrip(os.sep) # cosmetics, when {libarch} is empty + d = os.path.join(d, "lib", _expand_fields("{libarch}")) + d = d.rstrip(os.sep) # cosmetics, when {libarch} is empty - if component == 'tbb': # must qualify further for abi + if component == "tbb": # must qualify further for abi d = os.path.join(d, self._tbb_abi) debug_print(d) @@ -622,42 +630,42 @@ class IntelPackage(PackageBase): def component_include_dir(self, component, **kwargs): d = self.normalize_path(component, **kwargs) - if component == 'mpi': - d = os.path.join(d, _expand_fields('{libarch}'), 'include') + if component == "mpi": + d = os.path.join(d, _expand_fields("{libarch}"), "include") else: - d = os.path.join(d, 'include') + d = os.path.join(d, "include") debug_print(d) return d @property def file_to_source(self): - '''Full path of file to source for initializing an Intel package. + """Full path of file to source for initializing an Intel package. A client package could override as follows: ` @property` ` def file_to_source(self):` ` return self.normalize_path("apsvars.sh", "vtune_amplifier")` - ''' + """ vars_file_info_for = { # key (usu. spack package name) -> [rel_path, component_suite_dir] # Extension note: handle additions by Spack name or ad-hoc keys. - '@early_compiler': ['bin/compilervars', None], - 'intel-parallel-studio': ['bin/psxevars', 'parallel_studio_xe'], - 'intel': ['bin/compilervars', None], - 'intel-daal': ['daal/bin/daalvars', None], - 'intel-ipp': ['ipp/bin/ippvars', None], - 'intel-mkl': ['mkl/bin/mklvars', None], - 'intel-mpi': ['mpi/{libarch}/bin/mpivars', None], + "@early_compiler": ["bin/compilervars", None], + "intel-parallel-studio": ["bin/psxevars", "parallel_studio_xe"], + "intel": ["bin/compilervars", None], + "intel-daal": ["daal/bin/daalvars", None], + "intel-ipp": ["ipp/bin/ippvars", None], + "intel-mkl": ["mkl/bin/mklvars", None], + "intel-mpi": ["mpi/{libarch}/bin/mpivars", None], } key = self.name - if self.version_yearlike.satisfies(ver(':2015')): + if self.version_yearlike.satisfies(ver(":2015")): # Same file as 'intel' but 'None' for component_suite_dir will # resolve differently. Listed as a separate entry to serve as # example and to avoid pitfalls upon possible refactoring. - key = '@early_compiler' + key = "@early_compiler" f, component_suite_dir = vars_file_info_for[key] - f = _expand_fields(f) + '.sh' + f = _expand_fields(f) + ".sh" # TODO?? win32 would have to handle os.sep, '.bat' (unless POSIX??) f = self.normalize_path(f, component_suite_dir) @@ -668,50 +676,53 @@ class IntelPackage(PackageBase): # --------------------------------------------------------------------- @property def openmp_libs(self): - '''Supply LibraryList for linking OpenMP''' + """Supply LibraryList for linking OpenMP""" - if '%intel' in self.spec: + if "%intel" in self.spec: # NB: Hunting down explicit library files may be the Spack way of # doing things, but be aware that "{icc|ifort} --help openmp" # steers us towards options instead: -qopenmp-link={dynamic,static} - omp_libnames = ['libiomp5'] + omp_libnames = ["libiomp5"] omp_libs = find_libraries( omp_libnames, - root=self.component_lib_dir('compiler'), - shared=('+shared' in self.spec)) + root=self.component_lib_dir("compiler"), + shared=("+shared" in self.spec), + ) # Note about search root here: For MKL, the directory # "$MKLROOT/../compiler" will be present even for an MKL-only # product installation (as opposed to one being ghosted via # packages.yaml), specificially to provide the 'iomp5' libs. - elif '%gcc' in self.spec: + elif "%gcc" in self.spec: with self.compiler.compiler_environment(): omp_lib_path = Executable(self.compiler.cc)( - '--print-file-name', 'libgomp.%s' % dso_suffix, output=str) + "--print-file-name", "libgomp.%s" % dso_suffix, output=str + ) omp_libs = LibraryList(omp_lib_path.strip()) - elif '%clang' in self.spec: + elif "%clang" in self.spec: with self.compiler.compiler_environment(): omp_lib_path = Executable(self.compiler.cc)( - '--print-file-name', 'libomp.%s' % dso_suffix, output=str) + "--print-file-name", "libomp.%s" % dso_suffix, output=str + ) omp_libs = LibraryList(omp_lib_path.strip()) if len(omp_libs) < 1: - raise_lib_error('Cannot locate OpenMP libraries:', omp_libnames) + raise_lib_error("Cannot locate OpenMP libraries:", omp_libnames) debug_print(omp_libs) return omp_libs @property def _gcc_executable(self): - '''Return GCC executable''' + """Return GCC executable""" # Match the available gcc, as it's done in tbbvars.sh. - gcc_name = 'gcc' + gcc_name = "gcc" # but first check if -gcc-name is specified in cflags - for flag in self.spec.compiler_flags['cflags']: - if flag.startswith('-gcc-name='): - gcc_name = flag.split('-gcc-name=')[1] + for flag in self.spec.compiler_flags["cflags"]: + if flag.startswith("-gcc-name="): + gcc_name = flag.split("-gcc-name=")[1] break debug_print(gcc_name) return Executable(gcc_name) @@ -720,24 +731,21 @@ class IntelPackage(PackageBase): def tbb_headers(self): # Note: TBB is included as # #include <tbb/task_scheduler_init.h> - return HeaderList([ - self.component_include_dir('tbb') + '/dummy.h']) + return HeaderList([self.component_include_dir("tbb") + "/dummy.h"]) @property def tbb_libs(self): - '''Supply LibraryList for linking TBB''' + """Supply LibraryList for linking TBB""" # TODO: When is 'libtbbmalloc' needed? - tbb_lib = find_libraries( - ['libtbb'], root=self.component_lib_dir('tbb')) + tbb_lib = find_libraries(["libtbb"], root=self.component_lib_dir("tbb")) # NB: Like icc with -qopenmp, so does icpc steer us towards using an # option: "icpc -tbb" # TODO: clang(?) - gcc = self._gcc_executable # must be gcc, not self.compiler.cc + gcc = self._gcc_executable # must be gcc, not self.compiler.cc with self.compiler.compiler_environment(): - cxx_lib_path = gcc( - '--print-file-name', 'libstdc++.%s' % dso_suffix, output=str) + cxx_lib_path = gcc("--print-file-name", "libstdc++.%s" % dso_suffix, output=str) libs = tbb_lib + LibraryList(cxx_lib_path.rstrip()) debug_print(libs) @@ -745,23 +753,26 @@ class IntelPackage(PackageBase): @property def _tbb_abi(self): - '''Select the ABI needed for linking TBB''' + """Select the ABI needed for linking TBB""" gcc = self._gcc_executable with self.compiler.compiler_environment(): - matches = re.search(r'(gcc|LLVM).* ([0-9]+\.[0-9]+\.[0-9]+).*', - gcc('--version', output=str), re.I | re.M) - abi = '' - if sys.platform == 'darwin': + matches = re.search( + r"(gcc|LLVM).* ([0-9]+\.[0-9]+\.[0-9]+).*", + gcc("--version", output=str), + re.I | re.M, + ) + abi = "" + if sys.platform == "darwin": pass elif matches: # TODO: Confirm that this covers clang (needed on Linux only) gcc_version = Version(matches.groups()[1]) - if gcc_version >= ver('4.7'): - abi = 'gcc4.7' - elif gcc_version >= ver('4.4'): - abi = 'gcc4.4' + if gcc_version >= ver("4.7"): + abi = "gcc4.7" + elif gcc_version >= ver("4.4"): + abi = "gcc4.4" else: - abi = 'gcc4.1' # unlikely, one hopes. + abi = "gcc4.1" # unlikely, one hopes. # Alrighty then ... debug_print(abi) @@ -776,38 +787,41 @@ class IntelPackage(PackageBase): # For reference, see The Intel Math Kernel Library Link Line Advisor: # https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor/ - mkl_integer = 'libmkl_intel_' + self.intel64_int_suffix + mkl_integer = "libmkl_intel_" + self.intel64_int_suffix - if self.spec.satisfies('threads=openmp'): - if '%intel' in self.spec: - mkl_threading = 'libmkl_intel_thread' - elif '%gcc' in self.spec or '%clang' in self.spec: - mkl_threading = 'libmkl_gnu_thread' + if self.spec.satisfies("threads=openmp"): + if "%intel" in self.spec: + mkl_threading = "libmkl_intel_thread" + elif "%gcc" in self.spec or "%clang" in self.spec: + mkl_threading = "libmkl_gnu_thread" threading_engine_libs = self.openmp_libs - elif self.spec.satisfies('threads=tbb'): - mkl_threading = 'libmkl_tbb_thread' + elif self.spec.satisfies("threads=tbb"): + mkl_threading = "libmkl_tbb_thread" threading_engine_libs = self.tbb_libs - elif self.spec.satisfies('threads=none'): - mkl_threading = 'libmkl_sequential' + elif self.spec.satisfies("threads=none"): + mkl_threading = "libmkl_sequential" threading_engine_libs = LibraryList([]) else: - raise_lib_error('Cannot determine MKL threading libraries.') + raise_lib_error("Cannot determine MKL threading libraries.") - mkl_libnames = [mkl_integer, mkl_threading, 'libmkl_core'] + mkl_libnames = [mkl_integer, mkl_threading, "libmkl_core"] mkl_libs = find_libraries( - mkl_libnames, - root=self.component_lib_dir('mkl'), - shared=('+shared' in self.spec)) + mkl_libnames, root=self.component_lib_dir("mkl"), shared=("+shared" in self.spec) + ) debug_print(mkl_libs) if len(mkl_libs) < 3: - raise_lib_error('Cannot locate core MKL libraries:', mkl_libnames, - 'in:', self.component_lib_dir('mkl')) + raise_lib_error( + "Cannot locate core MKL libraries:", + mkl_libnames, + "in:", + self.component_lib_dir("mkl"), + ) # The Intel MKL link line advisor recommends these system libraries system_libs = find_system_libraries( - 'libpthread libm libdl'.split(), - shared=('+shared' in self.spec)) + "libpthread libm libdl".split(), shared=("+shared" in self.spec) + ) debug_print(system_libs) return mkl_libs + threading_engine_libs + system_libs @@ -823,40 +837,40 @@ class IntelPackage(PackageBase): # we must supply a personality matching the MPI implementation that # is active for the root package that asked for ScaLapack. spec_root = self.spec.root - if sys.platform == 'darwin' and '^mpich' in spec_root: + if sys.platform == "darwin" and "^mpich" in spec_root: # The only supported choice for MKL 2018 on Mac. - blacs_lib = 'libmkl_blacs_mpich' - elif '^openmpi' in spec_root: - blacs_lib = 'libmkl_blacs_openmpi' - elif '^mpich@1' in spec_root: + blacs_lib = "libmkl_blacs_mpich" + elif "^openmpi" in spec_root: + blacs_lib = "libmkl_blacs_openmpi" + elif "^mpich@1" in spec_root: # Was supported only up to 2015. - blacs_lib = 'libmkl_blacs' - elif ('^mpich@2:' in spec_root or - '^cray-mpich' in spec_root or - '^mvapich2' in spec_root or - '^intel-mpi' in spec_root or - '^intel-oneapi-mpi' in spec_root or - '^intel-parallel-studio' in spec_root): - blacs_lib = 'libmkl_blacs_intelmpi' - elif '^mpt' in spec_root: - blacs_lib = 'libmkl_blacs_sgimpt' + blacs_lib = "libmkl_blacs" + elif ( + "^mpich@2:" in spec_root + or "^cray-mpich" in spec_root + or "^mvapich2" in spec_root + or "^intel-mpi" in spec_root + or "^intel-oneapi-mpi" in spec_root + or "^intel-parallel-studio" in spec_root + ): + blacs_lib = "libmkl_blacs_intelmpi" + elif "^mpt" in spec_root: + blacs_lib = "libmkl_blacs_sgimpt" else: - raise_lib_error('Cannot find a BLACS library for the given MPI.') + raise_lib_error("Cannot find a BLACS library for the given MPI.") - int_suff = '_' + self.intel64_int_suffix + int_suff = "_" + self.intel64_int_suffix scalapack_libnames = [ - 'libmkl_scalapack' + int_suff, + "libmkl_scalapack" + int_suff, blacs_lib + int_suff, ] sca_libs = find_libraries( - scalapack_libnames, - root=self.component_lib_dir('mkl'), - shared=('+shared' in self.spec)) + scalapack_libnames, root=self.component_lib_dir("mkl"), shared=("+shared" in self.spec) + ) debug_print(sca_libs) if len(sca_libs) < 2: - raise_lib_error( - 'Cannot locate ScaLapack/BLACS libraries:', scalapack_libnames) + raise_lib_error("Cannot locate ScaLapack/BLACS libraries:", scalapack_libnames) # NB: ScaLapack is installed as "cluster" components within MKL or # MKL-encompassing products. But those were *optional* for the ca. # 2015/2016 product releases, which was easy to overlook, and I have @@ -871,8 +885,7 @@ class IntelPackage(PackageBase): # --------------------------------------------------------------------- @property def mpi_compiler_wrappers(self): - '''Return paths to compiler wrappers as a dict of env-like names - ''' + """Return paths to compiler wrappers as a dict of env-like names""" # Intel comes with 2 different flavors of MPI wrappers: # # * mpiicc, mpiicpc, and mpiifort are hardcoded to wrap around @@ -885,30 +898,29 @@ class IntelPackage(PackageBase): # and friends are set to point to the Intel compilers, but in # practice, mpicc fails to compile some applications while # mpiicc works. - bindir = self.component_bin_dir('mpi') - if self.compiler.name == 'intel': + bindir = self.component_bin_dir("mpi") + if self.compiler.name == "intel": wrapper_vars = { # eschew Prefix objects -- emphasize the command strings. - 'MPICC': os.path.join(bindir, 'mpiicc'), - 'MPICXX': os.path.join(bindir, 'mpiicpc'), - 'MPIF77': os.path.join(bindir, 'mpiifort'), - 'MPIF90': os.path.join(bindir, 'mpiifort'), - 'MPIFC': os.path.join(bindir, 'mpiifort'), + "MPICC": os.path.join(bindir, "mpiicc"), + "MPICXX": os.path.join(bindir, "mpiicpc"), + "MPIF77": os.path.join(bindir, "mpiifort"), + "MPIF90": os.path.join(bindir, "mpiifort"), + "MPIFC": os.path.join(bindir, "mpiifort"), } else: wrapper_vars = { - 'MPICC': os.path.join(bindir, 'mpicc'), - 'MPICXX': os.path.join(bindir, 'mpicxx'), - 'MPIF77': os.path.join(bindir, 'mpif77'), - 'MPIF90': os.path.join(bindir, 'mpif90'), - 'MPIFC': os.path.join(bindir, 'mpif90'), + "MPICC": os.path.join(bindir, "mpicc"), + "MPICXX": os.path.join(bindir, "mpicxx"), + "MPIF77": os.path.join(bindir, "mpif77"), + "MPIF90": os.path.join(bindir, "mpif90"), + "MPIFC": os.path.join(bindir, "mpif90"), } # debug_print("wrapper_vars =", wrapper_vars) return wrapper_vars - def mpi_setup_dependent_build_environment( - self, env, dependent_spec, compilers_of_client={}): - '''Unified back-end for setup_dependent_build_environment() of + def mpi_setup_dependent_build_environment(self, env, dependent_spec, compilers_of_client={}): + """Unified back-end for setup_dependent_build_environment() of Intel packages that provide 'mpi'. Parameters: @@ -918,16 +930,16 @@ class IntelPackage(PackageBase): compilers_of_client (dict): Conveys spack_cc, spack_cxx, etc., from the scope of dependent packages; constructed in caller. - ''' + """ # See also: setup_dependent_package() wrapper_vars = { - 'I_MPI_CC': compilers_of_client['CC'], - 'I_MPI_CXX': compilers_of_client['CXX'], - 'I_MPI_F77': compilers_of_client['F77'], - 'I_MPI_F90': compilers_of_client['F90'], - 'I_MPI_FC': compilers_of_client['FC'], + "I_MPI_CC": compilers_of_client["CC"], + "I_MPI_CXX": compilers_of_client["CXX"], + "I_MPI_F77": compilers_of_client["F77"], + "I_MPI_F90": compilers_of_client["F90"], + "I_MPI_FC": compilers_of_client["FC"], # NB: Normally set by the modulefile, but that is not active here: - 'I_MPI_ROOT': self.normalize_path('mpi'), + "I_MPI_ROOT": self.normalize_path("mpi"), } # CAUTION - SIMILAR code in: @@ -936,27 +948,31 @@ class IntelPackage(PackageBase): # var/spack/repos/builtin/packages/mvapich2/package.py # # On Cray, the regular compiler wrappers *are* the MPI wrappers. - if 'platform=cray' in self.spec: + if "platform=cray" in self.spec: # TODO: Confirm - wrapper_vars.update({ - 'MPICC': compilers_of_client['CC'], - 'MPICXX': compilers_of_client['CXX'], - 'MPIF77': compilers_of_client['F77'], - 'MPIF90': compilers_of_client['F90'], - }) + wrapper_vars.update( + { + "MPICC": compilers_of_client["CC"], + "MPICXX": compilers_of_client["CXX"], + "MPIF77": compilers_of_client["F77"], + "MPIF90": compilers_of_client["F90"], + } + ) else: compiler_wrapper_commands = self.mpi_compiler_wrappers - wrapper_vars.update({ - 'MPICC': compiler_wrapper_commands['MPICC'], - 'MPICXX': compiler_wrapper_commands['MPICXX'], - 'MPIF77': compiler_wrapper_commands['MPIF77'], - 'MPIF90': compiler_wrapper_commands['MPIF90'], - }) + wrapper_vars.update( + { + "MPICC": compiler_wrapper_commands["MPICC"], + "MPICXX": compiler_wrapper_commands["MPICXX"], + "MPIF77": compiler_wrapper_commands["MPIF77"], + "MPIF90": compiler_wrapper_commands["MPIF90"], + } + ) # Ensure that the directory containing the compiler wrappers is in the # PATH. Spack packages add `prefix.bin` to their dependents' paths, # but because of the intel directory hierarchy that is insufficient. - env.prepend_path('PATH', os.path.dirname(wrapper_vars['MPICC'])) + env.prepend_path("PATH", os.path.dirname(wrapper_vars["MPICC"])) for key, value in wrapper_vars.items(): env.set(key, value) @@ -969,17 +985,17 @@ class IntelPackage(PackageBase): @property def headers(self): result = HeaderList([]) - if '+mpi' in self.spec or self.provides('mpi'): + if "+mpi" in self.spec or self.provides("mpi"): result += find_headers( - ['mpi'], - root=self.component_include_dir('mpi'), - recursive=False) - if '+mkl' in self.spec or self.provides('mkl'): + ["mpi"], root=self.component_include_dir("mpi"), recursive=False + ) + if "+mkl" in self.spec or self.provides("mkl"): result += find_headers( - ['mkl_cblas', 'mkl_lapacke'], - root=self.component_include_dir('mkl'), - recursive=False) - if '+tbb' in self.spec or self.provides('tbb'): + ["mkl_cblas", "mkl_lapacke"], + root=self.component_include_dir("mkl"), + recursive=False, + ) + if "+tbb" in self.spec or self.provides("tbb"): result += self.tbb_headers debug_print(result) @@ -988,35 +1004,35 @@ class IntelPackage(PackageBase): @property def libs(self): result = LibraryList([]) - if '+tbb' in self.spec or self.provides('tbb'): + if "+tbb" in self.spec or self.provides("tbb"): result = self.tbb_libs + result - if '+mkl' in self.spec or self.provides('blas'): + if "+mkl" in self.spec or self.provides("blas"): result = self.blas_libs + result - if '+mkl' in self.spec or self.provides('lapack'): + if "+mkl" in self.spec or self.provides("lapack"): result = self.lapack_libs + result - if '+mpi' in self.spec or self.provides('mpi'): + if "+mpi" in self.spec or self.provides("mpi"): # If prefix is too general, recursive searches may get files from # supported but inappropriate sub-architectures like 'mic'. - libnames = ['libmpifort', 'libmpi'] - if 'cxx' in self.spec.last_query.extra_parameters: - libnames = ['libmpicxx'] + libnames - result = find_libraries( - libnames, - root=self.component_lib_dir('mpi'), - shared=True, recursive=True) + result + libnames = ["libmpifort", "libmpi"] + if "cxx" in self.spec.last_query.extra_parameters: + libnames = ["libmpicxx"] + libnames + result = ( + find_libraries( + libnames, root=self.component_lib_dir("mpi"), shared=True, recursive=True + ) + + result + ) # Intel MPI since 2019 depends on libfabric which is not in the # lib directory but in a directory of its own which should be # included in the rpath - if self.version_yearlike >= ver('2019'): - d = ancestor(self.component_lib_dir('mpi')) - if '+external-libfabric' in self.spec: - result += self.spec['libfabric'].libs + if self.version_yearlike >= ver("2019"): + d = ancestor(self.component_lib_dir("mpi")) + if "+external-libfabric" in self.spec: + result += self.spec["libfabric"].libs else: - result += find_libraries(['libfabric'], - os.path.join(d, 'libfabric', 'lib')) + result += find_libraries(["libfabric"], os.path.join(d, "libfabric", "lib")) - if '^mpi' in self.spec.root and ('+mkl' in self.spec or - self.provides('scalapack')): + if "^mpi" in self.spec.root and ("+mkl" in self.spec or self.provides("scalapack")): result = self.scalapack_libs + result debug_print(result) @@ -1037,7 +1053,7 @@ class IntelPackage(PackageBase): # All Intel packages expect at least the architecture as argument. # Some accept more args, but those are not (yet?) handled here. - args = (_expand_fields('{arch}'),) + args = (_expand_fields("{arch}"),) # On Mac, the platform is *also required*, at least as of 2018. # I am not sure about earlier versions. @@ -1046,14 +1062,14 @@ class IntelPackage(PackageBase): env.extend(EnvironmentModifications.from_sourcing_file(f, *args)) - if self.spec.name in ('intel', 'intel-parallel-studio'): + if self.spec.name in ("intel", "intel-parallel-studio"): # this package provides compilers # TODO: fix check above when compilers are dependencies - env.set('CC', self.prefix.bin.icc) - env.set('CXX', self.prefix.bin.icpc) - env.set('FC', self.prefix.bin.ifort) - env.set('F77', self.prefix.bin.ifort) - env.set('F90', self.prefix.bin.ifort) + env.set("CC", self.prefix.bin.icc) + env.set("CXX", self.prefix.bin.icpc) + env.set("FC", self.prefix.bin.ifort) + env.set("F77", self.prefix.bin.ifort) + env.set("F90", self.prefix.bin.ifort) def setup_dependent_build_environment(self, env, dependent_spec): # NB: This function is overwritten by 'mpi' provider packages: @@ -1067,13 +1083,12 @@ class IntelPackage(PackageBase): # Handle everything in a callback version. self._setup_dependent_env_callback(env, dependent_spec) - def _setup_dependent_env_callback( - self, env, dependent_spec, compilers_of_client={}): + def _setup_dependent_env_callback(self, env, dependent_spec, compilers_of_client={}): # Expected to be called from a client's # setup_dependent_build_environment(), # with args extended to convey the client's compilers as needed. - if '+mkl' in self.spec or self.provides('mkl'): + if "+mkl" in self.spec or self.provides("mkl"): # Spack's env philosophy demands that we replicate some of the # settings normally handled by file_to_source ... # @@ -1084,49 +1099,48 @@ class IntelPackage(PackageBase): # # Use a local dict to facilitate debug_print(): env_mods = { - 'MKLROOT': self.normalize_path('mkl'), - 'SPACK_COMPILER_EXTRA_RPATHS': self.component_lib_dir('mkl'), - 'CMAKE_PREFIX_PATH': self.normalize_path('mkl'), - 'CMAKE_LIBRARY_PATH': self.component_lib_dir('mkl'), - 'CMAKE_INCLUDE_PATH': self.component_include_dir('mkl'), + "MKLROOT": self.normalize_path("mkl"), + "SPACK_COMPILER_EXTRA_RPATHS": self.component_lib_dir("mkl"), + "CMAKE_PREFIX_PATH": self.normalize_path("mkl"), + "CMAKE_LIBRARY_PATH": self.component_lib_dir("mkl"), + "CMAKE_INCLUDE_PATH": self.component_include_dir("mkl"), } - env.set('MKLROOT', env_mods['MKLROOT']) - env.append_path('SPACK_COMPILER_EXTRA_RPATHS', - env_mods['SPACK_COMPILER_EXTRA_RPATHS']) - env.append_path('CMAKE_PREFIX_PATH', env_mods['CMAKE_PREFIX_PATH']) - env.append_path('CMAKE_LIBRARY_PATH', - env_mods['CMAKE_LIBRARY_PATH']) - env.append_path('CMAKE_INCLUDE_PATH', - env_mods['CMAKE_INCLUDE_PATH']) + env.set("MKLROOT", env_mods["MKLROOT"]) + env.append_path("SPACK_COMPILER_EXTRA_RPATHS", env_mods["SPACK_COMPILER_EXTRA_RPATHS"]) + env.append_path("CMAKE_PREFIX_PATH", env_mods["CMAKE_PREFIX_PATH"]) + env.append_path("CMAKE_LIBRARY_PATH", env_mods["CMAKE_LIBRARY_PATH"]) + env.append_path("CMAKE_INCLUDE_PATH", env_mods["CMAKE_INCLUDE_PATH"]) debug_print("adding/modifying build env:", env_mods) - if '+mpi' in self.spec or self.provides('mpi'): + if "+mpi" in self.spec or self.provides("mpi"): if compilers_of_client: self.mpi_setup_dependent_build_environment( - env, dependent_spec, compilers_of_client) + env, dependent_spec, compilers_of_client + ) # We could forego this nonce function and inline its code here, # but (a) it sisters mpi_compiler_wrappers() [needed twice] # which performs dizzyingly similar but necessarily different # actions, and (b) function code leaves a bit more breathing # room within the suffocating corset of flake8 line length. else: - raise InstallError('compilers_of_client arg required for MPI') + raise InstallError("compilers_of_client arg required for MPI") def setup_dependent_package(self, module, dep_spec): # https://spack.readthedocs.io/en/latest/spack.html#spack.package_base.PackageBase.setup_dependent_package # Reminder: "module" refers to Python module. # Called before the install() method of dependents. - if '+mpi' in self.spec or self.provides('mpi'): + if "+mpi" in self.spec or self.provides("mpi"): compiler_wrapper_commands = self.mpi_compiler_wrappers - self.spec.mpicc = compiler_wrapper_commands['MPICC'] - self.spec.mpicxx = compiler_wrapper_commands['MPICXX'] - self.spec.mpif77 = compiler_wrapper_commands['MPIF77'] - self.spec.mpifc = compiler_wrapper_commands['MPIFC'] - debug_print(("spec '%s' received .mpi* properties:" % self.spec), - compiler_wrapper_commands) + self.spec.mpicc = compiler_wrapper_commands["MPICC"] + self.spec.mpicxx = compiler_wrapper_commands["MPICXX"] + self.spec.mpif77 = compiler_wrapper_commands["MPIF77"] + self.spec.mpifc = compiler_wrapper_commands["MPIFC"] + debug_print( + ("spec '%s' received .mpi* properties:" % self.spec), compiler_wrapper_commands + ) # --------------------------------------------------------------------- # Specifics for installation phase @@ -1137,19 +1151,20 @@ class IntelPackage(PackageBase): All Intel software shares the same license, so we store it in a common 'intel' directory.""" - return os.path.join(self.global_license_dir, 'intel', 'license.lic') + return os.path.join(self.global_license_dir, "intel", "license.lic") @property def _determine_license_type(self): - '''Provide appropriate license tokens for the installer (silent.cfg). - ''' + """Provide appropriate license tokens for the installer (silent.cfg).""" # See: # ./README-intel.rst, section "Details for licensing tokens". # ./build_systems/README-intel.rst, section "Licenses" # # Ideally, we just tell the installer to look around on the system. # Thankfully, we neither need to care nor emulate where it looks: - license_type = {'ACTIVATION_TYPE': 'exist_lic', } + license_type = { + "ACTIVATION_TYPE": "exist_lic", + } # However (and only), if the spack-internal Intel license file has been # populated beyond its templated explanatory comments, proffer it to @@ -1160,21 +1175,20 @@ class IntelPackage(PackageBase): # self.license_files having been populated, so the "if" is usually # true by the time the present function runs; ../hooks/licensing.py with open(f) as fh: - if re.search(r'^[ \t]*[^' + self.license_comment + '\n]', - fh.read(), re.MULTILINE): + if re.search(r"^[ \t]*[^" + self.license_comment + "\n]", fh.read(), re.MULTILINE): license_type = { - 'ACTIVATION_TYPE': 'license_file', - 'ACTIVATION_LICENSE_FILE': f, + "ACTIVATION_TYPE": "license_file", + "ACTIVATION_LICENSE_FILE": f, } debug_print(license_type) return license_type def configure(self, spec, prefix): - '''Generates the silent.cfg file to pass to installer.sh. + """Generates the silent.cfg file to pass to installer.sh. See https://software.intel.com/en-us/articles/configuration-file-format - ''' + """ # Both tokens AND values of the configuration file are validated during # the run of the underlying binary installer. Any unknown token or @@ -1191,136 +1205,130 @@ class IntelPackage(PackageBase): # our configuration accordingly. We can do this because the tokens are # quite long and specific. - validator_code = open('pset/check.awk', 'r').read() + validator_code = open("pset/check.awk", "r").read() # Let's go a little further and distill the tokens (plus some noise). - tokenlike_words = set(re.findall(r'[A-Z_]{4,}', validator_code)) + tokenlike_words = set(re.findall(r"[A-Z_]{4,}", validator_code)) # NB: .cfg files generated with the "--duplicate filename" option have # the COMPONENTS string begin with a separator - do not worry about it. - components_joined = ';'.join(self._filtered_components) - nonrpm_db_dir = os.path.join(prefix, 'nonrpm-db') + components_joined = ";".join(self._filtered_components) + nonrpm_db_dir = os.path.join(prefix, "nonrpm-db") config_draft = { # Basics first - these should be accepted in all products. - 'ACCEPT_EULA': 'accept', - 'PSET_MODE': 'install', - 'CONTINUE_WITH_OPTIONAL_ERROR': 'yes', - 'CONTINUE_WITH_INSTALLDIR_OVERWRITE': 'yes', - 'SIGNING_ENABLED': 'no', - + "ACCEPT_EULA": "accept", + "PSET_MODE": "install", + "CONTINUE_WITH_OPTIONAL_ERROR": "yes", + "CONTINUE_WITH_INSTALLDIR_OVERWRITE": "yes", + "SIGNING_ENABLED": "no", # Highly variable package specifics: - 'PSET_INSTALL_DIR': prefix, - 'NONRPM_DB_DIR': nonrpm_db_dir, - 'COMPONENTS': components_joined, - + "PSET_INSTALL_DIR": prefix, + "NONRPM_DB_DIR": nonrpm_db_dir, + "COMPONENTS": components_joined, # Conditional tokens; the first is supported post-2015 only. # Ignore ia32; most recent products don't even provide it. - 'ARCH_SELECTED': 'INTEL64', # was: 'ALL' - + "ARCH_SELECTED": "INTEL64", # was: 'ALL' # 'ism' component -- see uninstall_ism(); also varies by release. - 'PHONEHOME_SEND_USAGE_DATA': 'no', + "PHONEHOME_SEND_USAGE_DATA": "no", # Ah, as of 2018.2, that somewhat loaded term got replaced by one # in business-speak. We uphold our preference, both out of general # principles and for technical reasons like overhead and non-routed # compute nodes. - 'INTEL_SW_IMPROVEMENT_PROGRAM_CONSENT': 'no', + "INTEL_SW_IMPROVEMENT_PROGRAM_CONSENT": "no", } # Deal with licensing only if truly needed. # NB: Token was 'ACTIVATION' pre ~2013, so basically irrelevant here. - if 'ACTIVATION_TYPE' in tokenlike_words: + if "ACTIVATION_TYPE" in tokenlike_words: config_draft.update(self._determine_license_type) # Write sorted *by token* so the file looks less like a hash dump. - f = open('silent.cfg', 'w') + f = open("silent.cfg", "w") for token, value in sorted(config_draft.items()): if token in tokenlike_words: - f.write('%s=%s\n' % (token, value)) + f.write("%s=%s\n" % (token, value)) f.close() def install(self, spec, prefix): - '''Runs Intel's install.sh installation script. Afterwards, save the + """Runs Intel's install.sh installation script. Afterwards, save the installer config and logs to <prefix>/.spack - ''' + """ # prepare - tmpdir = tempfile.mkdtemp(prefix='spack-intel-') + tmpdir = tempfile.mkdtemp(prefix="spack-intel-") - install_script = Executable('./install.sh') - install_script.add_default_env('TMPDIR', tmpdir) + install_script = Executable("./install.sh") + install_script.add_default_env("TMPDIR", tmpdir) # Need to set HOME to avoid using ~/intel - install_script.add_default_env('HOME', prefix) + install_script.add_default_env("HOME", prefix) # perform - install_script('--silent', 'silent.cfg') + install_script("--silent", "silent.cfg") # preserve config and logs - dst = os.path.join(self.prefix, '.spack') - install('silent.cfg', dst) - for f in glob.glob('%s/intel*log' % tmpdir): + dst = os.path.join(self.prefix, ".spack") + install("silent.cfg", dst) + for f in glob.glob("%s/intel*log" % tmpdir): install(f, dst) - @run_after('install') + @run_after("install") def validate_install(self): # Sometimes the installer exits with an error but doesn't pass a # non-zero exit code to spack. Check for the existence of a 'bin' # directory to catch this error condition. if not os.path.exists(self.prefix.bin): - raise InstallError('The installer has failed to install anything.') + raise InstallError("The installer has failed to install anything.") - @run_after('install') + @run_after("install") def configure_rpath(self): - if '+rpath' not in self.spec: + if "+rpath" not in self.spec: return # https://software.intel.com/en-us/cpp-compiler-18.0-developer-guide-and-reference-using-configuration-files - compilers_bin_dir = self.component_bin_dir('compiler') - compilers_lib_dir = self.component_lib_dir('compiler') + compilers_bin_dir = self.component_bin_dir("compiler") + compilers_lib_dir = self.component_lib_dir("compiler") - for compiler_name in 'icc icpc ifort'.split(): + for compiler_name in "icc icpc ifort".split(): f = os.path.join(compilers_bin_dir, compiler_name) if not os.path.isfile(f): - raise InstallError( - 'Cannot find compiler command to configure rpath:\n\t' + f) + raise InstallError("Cannot find compiler command to configure rpath:\n\t" + f) - compiler_cfg = os.path.abspath(f + '.cfg') - with open(compiler_cfg, 'w') as fh: - fh.write('-Xlinker -rpath={0}\n'.format(compilers_lib_dir)) + compiler_cfg = os.path.abspath(f + ".cfg") + with open(compiler_cfg, "w") as fh: + fh.write("-Xlinker -rpath={0}\n".format(compilers_lib_dir)) - @run_after('install') + @run_after("install") def configure_auto_dispatch(self): if self._has_compilers: - if ('auto_dispatch=none' in self.spec): + if "auto_dispatch=none" in self.spec: return - compilers_bin_dir = self.component_bin_dir('compiler') + compilers_bin_dir = self.component_bin_dir("compiler") - for compiler_name in 'icc icpc ifort'.split(): + for compiler_name in "icc icpc ifort".split(): f = os.path.join(compilers_bin_dir, compiler_name) if not os.path.isfile(f): raise InstallError( - 'Cannot find compiler command to configure ' - 'auto_dispatch:\n\t' + f) + "Cannot find compiler command to configure " "auto_dispatch:\n\t" + f + ) ad = [] for x in IntelPackage.auto_dispatch_options: - if 'auto_dispatch={0}'.format(x) in self.spec: + if "auto_dispatch={0}".format(x) in self.spec: ad.append(x) - compiler_cfg = os.path.abspath(f + '.cfg') - with open(compiler_cfg, 'a') as fh: - fh.write('-ax{0}\n'.format(','.join(ad))) + compiler_cfg = os.path.abspath(f + ".cfg") + with open(compiler_cfg, "a") as fh: + fh.write("-ax{0}\n".format(",".join(ad))) - @run_after('install') + @run_after("install") def filter_compiler_wrappers(self): - if (('+mpi' in self.spec or self.provides('mpi')) and - '~newdtags' in self.spec): - bin_dir = self.component_bin_dir('mpi') - for f in 'mpif77 mpif90 mpigcc mpigxx mpiicc mpiicpc ' \ - 'mpiifort'.split(): + if ("+mpi" in self.spec or self.provides("mpi")) and "~newdtags" in self.spec: + bin_dir = self.component_bin_dir("mpi") + for f in "mpif77 mpif90 mpigcc mpigxx mpiicc mpiicpc " "mpiifort".split(): f = os.path.join(bin_dir, f) - filter_file('-Xlinker --enable-new-dtags', ' ', f, string=True) + filter_file("-Xlinker --enable-new-dtags", " ", f, string=True) - @run_after('install') + @run_after("install") def uninstall_ism(self): # The "Intel(R) Software Improvement Program" [ahem] gets installed, # apparently regardless of PHONEHOME_SEND_USAGE_DATA. @@ -1331,12 +1339,11 @@ class IntelPackage(PackageBase): # "... you can also uninstall the Intel(R) Software Manager # completely: <installdir>/intel/ism/uninstall.sh" - f = os.path.join(self.normalize_path('ism'), 'uninstall.sh') + f = os.path.join(self.normalize_path("ism"), "uninstall.sh") if os.path.isfile(f): - tty.warn('Uninstalling "Intel Software Improvement Program"' - 'component') + tty.warn('Uninstalling "Intel Software Improvement Program"' "component") uninstall = Executable(f) - uninstall('--silent') + uninstall("--silent") # TODO? also try # ~/intel/ism/uninstall --silent @@ -1346,15 +1353,14 @@ class IntelPackage(PackageBase): @property def base_lib_dir(self): - """Provide the library directory located in the base of Intel installation. - """ - d = self.normalize_path('') - d = os.path.join(d, 'lib') + """Provide the library directory located in the base of Intel installation.""" + d = self.normalize_path("") + d = os.path.join(d, "lib") debug_print(d) return d - @run_after('install') + @run_after("install") def modify_LLVMgold_rpath(self): """Add libimf.so and other required libraries to the RUNPATH of LLVMgold.so. @@ -1362,8 +1368,9 @@ class IntelPackage(PackageBase): `ld -plugin LLVMgold.so` is called by the compiler. """ if self._has_compilers: - LLVMgold_libs = find_libraries('LLVMgold', self.base_lib_dir, - shared=True, recursive=True) + LLVMgold_libs = find_libraries( + "LLVMgold", self.base_lib_dir, shared=True, recursive=True + ) # Ignore ia32 entries as they mostly ignore throughout the rest # of the file. # The first entry in rpath preserves the original, the seconds entry @@ -1371,15 +1378,19 @@ class IntelPackage(PackageBase): # in compiler releases, then we need to search for libimf.so instead # of this static path. for lib in LLVMgold_libs: - if not self.spec.satisfies('^patchelf'): + if not self.spec.satisfies("^patchelf"): raise spack.error.SpackError( - 'Attempting to patch RPATH in LLVMgold.so.' - + '`patchelf` dependency should be set in package.py' + "Attempting to patch RPATH in LLVMgold.so." + + "`patchelf` dependency should be set in package.py" ) - patchelf = Executable('patchelf') - rpath = ':'.join([patchelf('--print-rpath', lib, output=str).strip(), - '$ORIGIN/../compiler/lib/intel64_lin']) - patchelf('--set-rpath', rpath, lib) + patchelf = Executable("patchelf") + rpath = ":".join( + [ + patchelf("--print-rpath", lib, output=str).strip(), + "$ORIGIN/../compiler/lib/intel64_lin", + ] + ) + patchelf("--set-rpath", rpath, lib) # Check that self.prefix is there after installation - run_after('install')(PackageBase.sanity_check_prefix) + run_after("install")(PackageBase.sanity_check_prefix) |