diff options
-rw-r--r-- | lib/spack/spack/build_systems/python.py | 16 | ||||
-rw-r--r-- | lib/spack/spack/build_systems/sip.py | 5 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/clingo/package.py | 3 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/migraphx/package.py | 3 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/python/package.py | 176 |
5 files changed, 90 insertions, 113 deletions
diff --git a/lib/spack/spack/build_systems/python.py b/lib/spack/spack/build_systems/python.py index 27b1d4a10c..c3bf323d84 100644 --- a/lib/spack/spack/build_systems/python.py +++ b/lib/spack/spack/build_systems/python.py @@ -127,7 +127,10 @@ class PythonPackage(PackageBase): list: list of strings of module names """ modules = [] - root = self.spec['python'].package.get_python_lib(prefix=self.prefix) + root = os.path.join( + self.prefix, + self.spec['python'].package.config_vars['python_lib']['false']['false'], + ) # Some Python libraries are packages: collections of modules # distributed in directories containing __init__.py files @@ -252,12 +255,11 @@ class PythonPackage(PackageBase): # Get all relative paths since we set the root to `prefix` # We query the python with which these will be used for the lib and inc # directories. This ensures we use `lib`/`lib64` as expected by python. - pure_site_packages_dir = spec['python'].package.get_python_lib( - plat_specific=False, prefix='') - plat_site_packages_dir = spec['python'].package.get_python_lib( - plat_specific=True, prefix='') - inc_dir = spec['python'].package.get_python_inc( - plat_specific=True, prefix='') + pure_site_packages_dir = spec['python'].package.config_vars[ + 'python_lib']['false']['false'] + plat_site_packages_dir = spec['python'].package.config_vars[ + 'python_lib']['true']['false'] + inc_dir = spec['python'].package.config_vars['python_inc']['true'] args += ['--root=%s' % prefix, '--install-purelib=%s' % pure_site_packages_dir, diff --git a/lib/spack/spack/build_systems/sip.py b/lib/spack/spack/build_systems/sip.py index 744989e2d6..1b9d01fbf4 100644 --- a/lib/spack/spack/build_systems/sip.py +++ b/lib/spack/spack/build_systems/sip.py @@ -64,7 +64,10 @@ class SIPPackage(PackageBase): list: list of strings of module names """ modules = [] - root = self.spec['python'].package.get_python_lib(prefix=self.prefix) + root = os.path.join( + self.prefix, + self.spec['python'].package.config_vars['python_lib']['false']['false'], + ) # Some Python libraries are packages: collections of modules # distributed in directories containing __init__.py files diff --git a/var/spack/repos/builtin/packages/clingo/package.py b/var/spack/repos/builtin/packages/clingo/package.py index 6c716fce73..aa9772109b 100644 --- a/var/spack/repos/builtin/packages/clingo/package.py +++ b/var/spack/repos/builtin/packages/clingo/package.py @@ -66,7 +66,8 @@ class Clingo(CMakePackage): current spec is the one found by CMake find_package(Python, ...) """ python_spec = self.spec['python'] - include_dir = python_spec.package.get_python_inc() + include_dir = join_path( + python_spec.prefix, python_spec.package.config_vars['python_inc']['false']) return [ self.define('Python_EXECUTABLE', str(python_spec.command)), self.define('Python_INCLUDE_DIR', include_dir) diff --git a/var/spack/repos/builtin/packages/migraphx/package.py b/var/spack/repos/builtin/packages/migraphx/package.py index ffccce8057..9e2c316e28 100644 --- a/var/spack/repos/builtin/packages/migraphx/package.py +++ b/var/spack/repos/builtin/packages/migraphx/package.py @@ -62,7 +62,8 @@ class Migraphx(CMakePackage): CMake based on current spec """ python_spec = self.spec['python'] - include_dir = python_spec.package.get_python_inc() + include_dir = join_path( + python_spec.prefix, python_spec.package.config_vars['python_inc']['false']) return [ self.define('Python_INCLUDE_DIR', include_dir) ] diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 1f5f2046f0..470b05f6ac 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import json import os import platform import re @@ -231,8 +232,8 @@ class Python(AutotoolsPackage): conflicts('%nvhpc') - # Used to cache home locations, since computing them might be expensive - _homes = {} + # Used to cache various attributes that are expensive to compute + _config_vars = {} # An in-source build with --enable-optimizations fails for python@3.X build_directory = 'spack-build' @@ -506,7 +507,7 @@ class Python(AutotoolsPackage): kwargs = {'ignore_absent': True, 'backup': False, 'string': True} filenames = [ - self.get_sysconfigdata_name(), self.get_makefile_filename() + self.get_sysconfigdata_name(), self.config_vars['makefile_filename'] ] filter_file(spack_cc, self.compiler.cc, *filenames, **kwargs) @@ -686,87 +687,59 @@ class Python(AutotoolsPackage): else: return 'print({0})'.format(string) - def get_config_var(self, key): - """Return the value of a single variable. Wrapper around - ``distutils.sysconfig.get_config_var()``.""" - - cmd = 'from distutils.sysconfig import get_config_var; ' - cmd += self.print_string("get_config_var('{0}')".format(key)) - - return self.command('-c', cmd, output=str).strip() - - def get_config_h_filename(self): - """Return the full path name of the configuration header. - Wrapper around ``distutils.sysconfig.get_config_h_filename()``.""" - - cmd = 'from distutils.sysconfig import get_config_h_filename; ' - cmd += self.print_string('get_config_h_filename()') - - return self.command('-c', cmd, output=str).strip() - - def get_makefile_filename(self): - """Return the full path name of ``Makefile`` used to build Python. - Wrapper around ``distutils.sysconfig.get_makefile_filename()``.""" - - cmd = 'from distutils.sysconfig import get_makefile_filename; ' - cmd += self.print_string('get_makefile_filename()') - - return self.command('-c', cmd, output=str).strip() - - def get_python_inc(self, plat_specific=False, prefix=None): - """Return the directory for either the general or platform-dependent C - include files. Wrapper around ``distutils.sysconfig.get_python_inc()``. - - Parameters: - plat_specific (bool): if true, the platform-dependent include directory - is returned, else the platform-independent directory is returned - prefix (str): prefix to use instead of ``distutils.sysconfig.PREFIX`` - - Returns: - str: include files directory - """ - # Wrap strings in quotes - if prefix is not None: - prefix = '"{0}"'.format(prefix) - - args = 'plat_specific={0}, prefix={1}'.format(plat_specific, prefix) - - cmd = 'from distutils.sysconfig import get_python_inc; ' - cmd += self.print_string('get_python_inc({0})'.format(args)) - - return self.command('-c', cmd, output=str).strip() - - def get_python_lib(self, plat_specific=False, standard_lib=False, prefix=None): - """Return the directory for either the general or platform-dependent - library installation. Wrapper around ``distutils.sysconfig.get_python_lib()``. + @property + def config_vars(self): + """Return a set of variable definitions associated with a Python installation. - Parameters: - plat_specific (bool): if true, the platform-dependent library directory - is returned, else the platform-independent directory is returned - standard_lib (bool): if true, the directory for the standard library is - returned rather than the directory for the installation of - third-party extensions - prefix (str): prefix to use instead of ``distutils.sysconfig.PREFIX`` + Wrapper around various ``distutils.sysconfig`` functions. Returns: - str: library installation directory + dict: variable definitions """ - # Wrap strings in quotes - if prefix is not None: - prefix = '"{0}"'.format(prefix) + # TODO: distutils is deprecated in Python 3.10 and will be removed in + # Python 3.12, find a different way to access this information. + # Also, calling the python executable disallows us from cross-compiling, + # so we want to try to avoid that if possible. + cmd = """ +import json +from distutils.sysconfig import ( + get_config_vars, + get_config_h_filename, + get_makefile_filename, + get_python_inc, + get_python_lib, +) + +config = get_config_vars() +config['config_h_filename'] = get_config_h_filename() +config['makefile_filename'] = get_makefile_filename() +config['python_inc'] = {} +config['python_lib'] = {} + +for plat_specific in [True, False]: + config['python_inc'][plat_specific] = get_python_inc(plat_specific, prefix='') + config['python_lib'][plat_specific] = {} + for standard_lib in [True, False]: + config['python_lib'][plat_specific][standard_lib] = get_python_lib( + plat_specific, standard_lib, prefix='' + ) + +%s +""" % self.print_string("json.dumps(config)") - args = 'plat_specific={0}, standard_lib={1}, prefix={2}'.format( - plat_specific, standard_lib, prefix) - - cmd = 'from distutils.sysconfig import get_python_lib; ' - cmd += self.print_string('get_python_lib({0})'.format(args)) - - return self.command('-c', cmd, output=str).strip() + dag_hash = self.spec.dag_hash() + if dag_hash not in self._config_vars: + try: + config = json.loads(self.command('-c', cmd, output=str)) + except (ProcessError, RuntimeError): + config = {} + self._config_vars[dag_hash] = config + return self._config_vars[dag_hash] def get_sysconfigdata_name(self): """Return the full path name of the sysconfigdata file.""" - libdest = self.get_config_var('LIBDEST') + libdest = self.config_vars['LIBDEST'] filename = '_sysconfigdata.py' if self.spec.satisfies('@3.6:'): @@ -790,14 +763,11 @@ class Python(AutotoolsPackage): determine exactly where it is installed. Fall back on ``spec['python'].prefix`` if that doesn't work.""" - dag_hash = self.spec.dag_hash() - if dag_hash not in self._homes: - try: - prefix = self.get_config_var('prefix') - except ProcessError: - prefix = self.prefix - self._homes[dag_hash] = Prefix(prefix) - return self._homes[dag_hash] + if 'prefix' in self.config_vars: + prefix = self.config_vars['prefix'] + else: + prefix = self.prefix + return Prefix(prefix) @property def libs(self): @@ -805,19 +775,19 @@ class Python(AutotoolsPackage): # installs them into lib64. If the user is using an externally # installed package, it may be in either lib or lib64, so we need # to ask Python where its LIBDIR is. - libdir = self.get_config_var('LIBDIR') + libdir = self.config_vars['LIBDIR'] # In Ubuntu 16.04.6 and python 2.7.12 from the system, lib could be # in LBPL # https://mail.python.org/pipermail/python-dev/2013-April/125733.html - libpl = self.get_config_var('LIBPL') + libpl = self.config_vars['LIBPL'] # The system Python installation on macOS and Homebrew installations # install libraries into a Frameworks directory - frameworkprefix = self.get_config_var('PYTHONFRAMEWORKPREFIX') + frameworkprefix = self.config_vars['PYTHONFRAMEWORKPREFIX'] if '+shared' in self.spec: - ldlibrary = self.get_config_var('LDLIBRARY') + ldlibrary = self.config_vars['LDLIBRARY'] if os.path.exists(os.path.join(libdir, ldlibrary)): return LibraryList(os.path.join(libdir, ldlibrary)) @@ -829,7 +799,7 @@ class Python(AutotoolsPackage): msg = 'Unable to locate {0} libraries in {1}' raise RuntimeError(msg.format(ldlibrary, libdir)) else: - library = self.get_config_var('LIBRARY') + library = self.config_vars['LIBRARY'] if os.path.exists(os.path.join(libdir, library)): return LibraryList(os.path.join(libdir, library)) @@ -841,16 +811,16 @@ class Python(AutotoolsPackage): @property def headers(self): - try: - config_h = self.get_config_h_filename() + if 'config_h_filename' in self.config_vars: + config_h = self.config_vars['config_h_filename'] if not os.path.exists(config_h): - includepy = self.get_config_var('INCLUDEPY') + includepy = self.config_vars['INCLUDEPY'] msg = 'Unable to locate {0} headers in {1}' raise RuntimeError(msg.format(self.name, includepy)) headers = HeaderList(config_h) - except ProcessError: + else: headers = find_headers( 'pyconfig', self.prefix.include, recursive=True) config_h = headers[0] @@ -871,9 +841,9 @@ class Python(AutotoolsPackage): Returns: str: include files directory """ - try: - return self.get_python_inc(prefix='') - except (ProcessError, RuntimeError): + if 'python_inc' in self.config_vars: + return self.config_vars['python_inc']['false'] + else: return os.path.join('include', 'python{0}'.format(self.version.up_to(2))) @property @@ -895,9 +865,9 @@ class Python(AutotoolsPackage): Returns: str: standard library directory """ - try: - return self.get_python_lib(standard_lib=True, prefix='') - except (ProcessError, RuntimeError): + if 'python_lib' in self.config_vars: + return self.config_vars['python_lib']['false']['true'] + else: return os.path.join('lib', 'python{0}'.format(self.version.up_to(2))) @property @@ -919,9 +889,9 @@ class Python(AutotoolsPackage): Returns: str: site-packages directory """ - try: - return self.get_python_lib(prefix='') - except (ProcessError, RuntimeError): + if 'python_lib' in self.config_vars: + return self.config_vars['python_lib']['false']['false'] + else: return self.default_site_packages_dir @property @@ -978,8 +948,8 @@ class Python(AutotoolsPackage): for compile_var, link_var in [('CC', 'LDSHARED'), ('CXX', 'LDCXXSHARED')]: # First, we get the values from the sysconfigdata: - config_compile = self.get_config_var(compile_var) - config_link = self.get_config_var(link_var) + config_compile = self.config_vars[compile_var] + config_link = self.config_vars[link_var] # The dependent environment will have the compilation command set to # the following: |