summaryrefslogtreecommitdiff
path: root/var
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2020-07-31 13:07:48 +0200
committerPeter Scheibel <scheibel1@llnl.gov>2020-08-10 11:59:05 -0700
commitc0d490ffbe7268e72b3214764d7b03aee9f65502 (patch)
tree4b186cfc39499cf346e7c61c23259b842aed15e0 /var
parent193e8333fa23a2e9b44d44a80e153d9a27033860 (diff)
downloadspack-c0d490ffbe7268e72b3214764d7b03aee9f65502.tar.gz
spack-c0d490ffbe7268e72b3214764d7b03aee9f65502.tar.bz2
spack-c0d490ffbe7268e72b3214764d7b03aee9f65502.tar.xz
spack-c0d490ffbe7268e72b3214764d7b03aee9f65502.zip
Simplify the detection protocol for packages
Packages can implement “detect_version” to support detection of external instances of a package. This is generally easier than implementing “determine_spec_details”. The API for determine_version is similar: for example you can return “None” to indicate that an executable is not an instance of a package. Users may implement a “determine_variants” method for a package. When doing external detection, executables are grouped by version and each group results in a single invocation of “determine_variants” for the associated spec. The method returns a string specifying the variants for the package. The method may additionally return a dictionary representing extra attributes for the package. These will be stored in the spec yaml and can be retrieved from self.spec.extra_attributes The Spack GCC package has been updated with an implementation of “determine_variants” which adds the following extra attributes to the package: c, cxx, fortran
Diffstat (limited to 'var')
-rw-r--r--var/spack/repos/builtin/packages/automake/package.py24
-rw-r--r--var/spack/repos/builtin/packages/cmake/package.py29
-rw-r--r--var/spack/repos/builtin/packages/gcc/package.py110
3 files changed, 118 insertions, 45 deletions
diff --git a/var/spack/repos/builtin/packages/automake/package.py b/var/spack/repos/builtin/packages/automake/package.py
index 0e9d22cb37..aa14dc290e 100644
--- a/var/spack/repos/builtin/packages/automake/package.py
+++ b/var/spack/repos/builtin/packages/automake/package.py
@@ -2,10 +2,6 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-from spack import *
-
-import os
import re
@@ -28,23 +24,13 @@ class Automake(AutotoolsPackage, GNUMirrorPackage):
build_directory = 'spack-build'
- executables = ['automake']
+ executables = ['^automake$']
@classmethod
- def determine_spec_details(cls, prefix, exes_in_prefix):
- exe_to_path = dict(
- (os.path.basename(p), p) for p in exes_in_prefix
- )
- if 'automake' not in exe_to_path:
- return None
-
- exe = spack.util.executable.Executable(exe_to_path['automake'])
- output = exe('--version', output=str)
- if output:
- match = re.search(r'GNU automake\)\s+(\S+)', output)
- if match:
- version_str = match.group(1)
- return Spec('automake@{0}'.format(version_str))
+ def determine_version(cls, exe):
+ output = Executable(exe)('--version', output=str)
+ match = re.search(r'GNU automake\)\s+(\S+)', output)
+ return match.group(1) if match else None
def patch(self):
# The full perl shebang might be too long
diff --git a/var/spack/repos/builtin/packages/cmake/package.py b/var/spack/repos/builtin/packages/cmake/package.py
index 2cf30956be..1cb3cf33f6 100644
--- a/var/spack/repos/builtin/packages/cmake/package.py
+++ b/var/spack/repos/builtin/packages/cmake/package.py
@@ -2,21 +2,18 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-from spack import *
-
import re
-import os
class Cmake(Package):
"""A cross-platform, open-source build system. CMake is a family of
- tools designed to build, test and package software."""
+ tools designed to build, test and package software.
+ """
homepage = 'https://www.cmake.org'
- url = 'https://github.com/Kitware/CMake/releases/download/v3.15.5/cmake-3.15.5.tar.gz'
+ url = 'https://github.com/Kitware/CMake/releases/download/v3.15.5/cmake-3.15.5.tar.gz'
maintainers = ['chuckatkins']
- executables = ['cmake']
+ executables = ['^cmake$']
version('3.18.1', sha256='c0e3338bd37e67155b9d1e9526fec326b5c541f74857771b7ffed0c46ad62508')
version('3.18.0', sha256='83b4ffcb9482a73961521d2bafe4a16df0168f03f56e6624c419c461e5317e29')
@@ -163,20 +160,10 @@ class Cmake(Package):
phases = ['bootstrap', 'build', 'install']
@classmethod
- def determine_spec_details(cls, prefix, exes_in_prefix):
- exe_to_path = dict(
- (os.path.basename(p), p) for p in exes_in_prefix
- )
- if 'cmake' not in exe_to_path:
- return None
-
- cmake = spack.util.executable.Executable(exe_to_path['cmake'])
- output = cmake('--version', output=str)
- if output:
- match = re.search(r'cmake.*version\s+(\S+)', output)
- if match:
- version_str = match.group(1)
- return Spec('cmake@{0}'.format(version_str))
+ def determine_version(cls, exe):
+ output = Executable(exe)('--version', output=str)
+ match = re.search(r'cmake.*version\s+(\S+)', output)
+ return match.group(1) if match else None
def flag_handler(self, name, flags):
if name == 'cxxflags' and self.compiler.name == 'fj':
diff --git a/var/spack/repos/builtin/packages/gcc/package.py b/var/spack/repos/builtin/packages/gcc/package.py
index d762c3af6b..dc7b13742d 100644
--- a/var/spack/repos/builtin/packages/gcc/package.py
+++ b/var/spack/repos/builtin/packages/gcc/package.py
@@ -2,16 +2,17 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-from spack import *
-from spack.operating_systems.mac_os import macos_version, macos_sdk_path
-from llnl.util import tty
-
import glob
import itertools
import os
+import re
import sys
+import llnl.util.tty as tty
+import spack.util.executable
+
+from spack.operating_systems.mac_os import macos_version, macos_sdk_path
+
class Gcc(AutotoolsPackage, GNUMirrorPackage):
"""The GNU Compiler Collection includes front ends for C, C++, Objective-C,
@@ -269,6 +270,105 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
build_directory = 'spack-build'
+ @property
+ def executables(self):
+ names = [r'gcc', r'[^\w]?g\+\+', r'gfortran']
+ suffixes = [r'', r'-mp-\d+\.\d', r'-\d+\.\d', r'-\d+', r'\d\d']
+ return [r''.join(x) for x in itertools.product(names, suffixes)]
+
+ @classmethod
+ def filter_detected_exes(cls, prefix, exes_in_prefix):
+ result = []
+ for exe in exes_in_prefix:
+ # clang++ matches g++ -> clan[g++]
+ if any(x in exe for x in ('clang', 'ranlib')):
+ continue
+ # Filter out links in favor of real executables
+ if os.path.islink(exe):
+ continue
+ result.append(exe)
+ return result
+
+ @classmethod
+ def determine_version(cls, exe):
+ version_regex = re.compile(r'([\d\.]+)')
+ for vargs in ('-dumpfullversion', '-dumpversion'):
+ try:
+ output = spack.compiler.get_compiler_version_output(exe, vargs)
+ match = version_regex.search(output)
+ if match:
+ return match.group(1)
+ except spack.util.executable.ProcessError:
+ pass
+ except Exception as e:
+ tty.debug(e)
+
+ return None
+
+ @classmethod
+ def determine_variants(cls, exes, version_str):
+ languages, compilers = set(), {}
+ for exe in exes:
+ basename = os.path.basename(exe)
+ if 'gcc' in basename:
+ languages.add('c')
+ compilers['c'] = exe
+ elif 'g++' in basename:
+ languages.add('c++')
+ compilers['cxx'] = exe
+ elif 'gfortran' in basename:
+ languages.add('fortran')
+ compilers['fortran'] = exe
+ variant_str = 'languages={0}'.format(','.join(languages))
+ return variant_str, {'compilers': compilers}
+
+ @classmethod
+ def validate_detected_spec(cls, spec, extra_attributes):
+ # For GCC 'compilers' is a mandatory attribute
+ msg = ('the extra attribute "compilers" must be set for '
+ 'the detected spec "{0}"'.format(spec))
+ assert 'compilers' in extra_attributes, msg
+
+ compilers = extra_attributes['compilers']
+ for constraint, key in {
+ 'languages=c': 'c',
+ 'languages=c++': 'cxx',
+ 'languages=fortran': 'fortran'
+ }.items():
+ if spec.satisfies(constraint, strict=True):
+ msg = '{0} not in {1}'
+ assert key in compilers, msg.format(key, spec)
+
+ @property
+ def cc(self):
+ msg = "cannot retrieve C compiler [spec is not concrete]"
+ assert self.spec.concrete, msg
+ if self.spec.external:
+ return self.spec.extra_attributes['compilers'].get('c', None)
+ return self.spec.prefix.bin.gcc if 'languages=c' in self.spec else None
+
+ @property
+ def cxx(self):
+ msg = "cannot retrieve C++ compiler [spec is not concrete]"
+ assert self.spec.concrete, msg
+ if self.spec.external:
+ return self.spec.extra_attributes['compilers'].get('cxx', None)
+ result = None
+ if 'languages=c++' in self.spec:
+ result = os.path.join(self.spec.prefix.bin, 'g++')
+ return result
+
+ @property
+ def fortran(self):
+ msg = "cannot retrieve Fortran compiler [spec is not concrete]"
+ assert self.spec.concrete, msg
+ if self.spec.external:
+ return self.spec.extra_attributes['compilers'].get('fortran', None)
+ result = None
+ if 'languages=fortran' in self.spec:
+ result = self.spec.prefix.bin.gfortran
+ return result
+
def url_for_version(self, version):
# This function will be called when trying to fetch from url, before
# mirrors are tried. It takes care of modifying the suffix of gnu