Overhaul numpy package (#12170)
* Add numpy 1.17.0 * Overhaul numpy package * Flake8 fixes * Undefined reference fix * HeaderList and LibraryList need an arg * veclibfort has no headers * Add patch for older versions of py-numpy * Remove py-meep hack from py-numpy package * libflame: always add max arg hack flag * Fix build with GCC 4.8 * Compiler flags come from self.compiler * Only apply -std=c99 to cflags * Try to fix libflame package * Fix ATLAS build on macOS * --force-clang flag added in 3.10.3
This commit is contained in:
parent
15884a679b
commit
66e9b1279a
6 changed files with 537 additions and 127 deletions
|
@ -18,17 +18,15 @@ class Atlas(Package):
|
|||
"""
|
||||
homepage = "http://math-atlas.sourceforge.net/"
|
||||
|
||||
version('3.11.39', '5f3252fa980f5f060f93edd4669321e2',
|
||||
url='http://sourceforge.net/projects/math-atlas/files/Developer%20%28unstable%29/3.11.39/atlas3.11.39.tar.bz2')
|
||||
# Developer (unstable)
|
||||
version('3.11.41', sha256='477d567a8d683e891d786e9e8bb6ad6659daa9ba18e8dd0e2f70b7a54095f8de')
|
||||
version('3.11.39', '5f3252fa980f5f060f93edd4669321e2')
|
||||
version('3.11.34', '0b6c5389c095c4c8785fd0f724ec6825')
|
||||
|
||||
version('3.11.34', '0b6c5389c095c4c8785fd0f724ec6825',
|
||||
url='http://sourceforge.net/projects/math-atlas/files/Developer%20%28unstable%29/3.11.34/atlas3.11.34.tar.bz2')
|
||||
# Stable
|
||||
version('3.10.3', 'd6ce4f16c2ad301837cfb3dade2f7cef', preferred=True)
|
||||
version('3.10.2', 'a4e21f343dec8f22e7415e339f09f6da')
|
||||
|
||||
version('3.10.3', 'd6ce4f16c2ad301837cfb3dade2f7cef',
|
||||
url='https://sourceforge.net/projects/math-atlas/files/Stable/3.10.3/atlas3.10.3.tar.bz2')
|
||||
|
||||
version('3.10.2', 'a4e21f343dec8f22e7415e339f09f6da',
|
||||
url='https://sourceforge.net/projects/math-atlas/files/Stable/3.10.2/atlas3.10.2.tar.bz2', preferred=True)
|
||||
# not all packages (e.g. Trilinos@12.6.3) stopped using deprecated in 3.6.0
|
||||
# Lapack routines. Stick with 3.5.0 until this is fixed.
|
||||
resource(name='lapack',
|
||||
|
@ -57,6 +55,16 @@ class Atlas(Package):
|
|||
|
||||
parallel = False
|
||||
|
||||
def url_for_version(self, version):
|
||||
url = 'https://sourceforge.net/projects/math-atlas/files/'
|
||||
|
||||
if version >= Version('3.11'):
|
||||
url += 'Developer%20%28unstable%29/{0}/atlas{0}.tar.bz2'
|
||||
else:
|
||||
url += 'Stable/{0}/atlas{0}.tar.bz2'
|
||||
|
||||
return url.format(version)
|
||||
|
||||
def patch(self):
|
||||
# Disable thread check. LLNL's environment does not allow
|
||||
# disabling of CPU throttling in a way that ATLAS actually
|
||||
|
@ -94,6 +102,11 @@ def install(self, spec, prefix):
|
|||
'-C', 'if', spack_f77
|
||||
])
|
||||
|
||||
# Workaround for macOS Clang:
|
||||
# http://math-atlas.sourceforge.net/atlas_install/node66.html
|
||||
if spec.satisfies('@3.10.3: %clang platform=darwin'):
|
||||
options.append('--force-clang=' + spack_cc)
|
||||
|
||||
# Lapack resource to provide full lapack build. Note that
|
||||
# ATLAS only provides a few LAPACK routines natively.
|
||||
options.append('--with-netlib-lapack-tarfile=%s' %
|
||||
|
|
|
@ -51,6 +51,12 @@ class Libflame(AutotoolsPackage):
|
|||
# https://groups.google.com/forum/#!topic/libflame-discuss/lQKEfjyudOY
|
||||
patch('Makefile_5.1.0.patch', when='@5.1.0')
|
||||
|
||||
def flag_handler(self, name, flags):
|
||||
# -std=gnu99 at least required, old versions of GCC default to -std=c90
|
||||
if self.spec.satisfies('%gcc@:5.1') and name == 'cflags':
|
||||
flags.append('-std=gnu99')
|
||||
return (flags, None, None)
|
||||
|
||||
def configure_args(self):
|
||||
config_args = []
|
||||
|
||||
|
@ -83,7 +89,6 @@ def configure_args(self):
|
|||
config_args.append("--disable-supermatrix")
|
||||
|
||||
# https://github.com/flame/libflame/issues/21
|
||||
if self.spec.satisfies('@5.1.99:'):
|
||||
config_args.append("--enable-max-arg-list-hack")
|
||||
config_args.append("--enable-max-arg-list-hack")
|
||||
|
||||
return config_args
|
||||
|
|
|
@ -38,7 +38,10 @@ def setup_file(self):
|
|||
def common_args(self, spec, prefix):
|
||||
include_dirs = [
|
||||
spec['meep'].prefix.include,
|
||||
spec['py-numpy'].include
|
||||
os.path.join(
|
||||
spec['py-numpy'].prefix,
|
||||
spec['python'].package.python_include_dir
|
||||
)
|
||||
]
|
||||
|
||||
library_dirs = [
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
Allows you to specify order of BLAS/LAPACK preference
|
||||
https://github.com/numpy/numpy/pull/13132
|
||||
diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py
|
||||
index 806f4f7d3..0480d7b5a 100644
|
||||
--- a/numpy/distutils/system_info.py
|
||||
+++ b/numpy/distutils/system_info.py
|
||||
@@ -474,6 +474,13 @@ class LapackSrcNotFoundError(LapackNotFoundError):
|
||||
the LAPACK_SRC environment variable."""
|
||||
|
||||
|
||||
+class BlasOptNotFoundError(NotFoundError):
|
||||
+ """
|
||||
+ Optimized (vendor) Blas libraries are not found.
|
||||
+ Falls back to netlib Blas library which has worse performance.
|
||||
+ A better performance should be easily gained by switching
|
||||
+ Blas library."""
|
||||
+
|
||||
class BlasNotFoundError(NotFoundError):
|
||||
"""
|
||||
Blas (http://www.netlib.org/blas/) libraries not found.
|
||||
@@ -1541,139 +1548,219 @@ Make sure that -lgfortran is used for C++ extensions.
|
||||
class lapack_opt_info(system_info):
|
||||
|
||||
notfounderror = LapackNotFoundError
|
||||
+ # Default order of LAPACK checks
|
||||
+ lapack_order = ['mkl', 'openblas', 'atlas', 'accelerate', 'lapack']
|
||||
|
||||
- def calc_info(self):
|
||||
+ def _calc_info_mkl(self):
|
||||
+ info = get_info('lapack_mkl')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- lapack_mkl_info = get_info('lapack_mkl')
|
||||
- if lapack_mkl_info:
|
||||
- self.set_info(**lapack_mkl_info)
|
||||
- return
|
||||
+ def _calc_info_openblas(self):
|
||||
+ info = get_info('openblas_lapack')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ info = get_info('openblas_clapack')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- openblas_info = get_info('openblas_lapack')
|
||||
- if openblas_info:
|
||||
- self.set_info(**openblas_info)
|
||||
- return
|
||||
+ def _calc_info_atlas(self):
|
||||
+ info = get_info('atlas_3_10_threads')
|
||||
+ if not info:
|
||||
+ info = get_info('atlas_3_10')
|
||||
+ if not info:
|
||||
+ info = get_info('atlas_threads')
|
||||
+ if not info:
|
||||
+ info = get_info('atlas')
|
||||
+ if info:
|
||||
+ # Figure out if ATLAS has lapack...
|
||||
+ # If not we need the lapack library, but not BLAS!
|
||||
+ l = info.get('define_macros', [])
|
||||
+ if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \
|
||||
+ or ('ATLAS_WITHOUT_LAPACK', None) in l:
|
||||
+ # Get LAPACK (with possible warnings)
|
||||
+ # If not found we don't accept anything
|
||||
+ # since we can't use ATLAS with LAPACK!
|
||||
+ lapack_info = self._get_info_lapack()
|
||||
+ if not lapack_info:
|
||||
+ return False
|
||||
+ dict_append(info, **lapack_info)
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- openblas_info = get_info('openblas_clapack')
|
||||
- if openblas_info:
|
||||
- self.set_info(**openblas_info)
|
||||
- return
|
||||
+ def _calc_info_accelerate(self):
|
||||
+ info = get_info('accelerate')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- atlas_info = get_info('atlas_3_10_threads')
|
||||
- if not atlas_info:
|
||||
- atlas_info = get_info('atlas_3_10')
|
||||
- if not atlas_info:
|
||||
- atlas_info = get_info('atlas_threads')
|
||||
- if not atlas_info:
|
||||
- atlas_info = get_info('atlas')
|
||||
-
|
||||
- accelerate_info = get_info('accelerate')
|
||||
- if accelerate_info and not atlas_info:
|
||||
- self.set_info(**accelerate_info)
|
||||
- return
|
||||
+ def _get_info_blas(self):
|
||||
+ # Default to get the optimized BLAS implementation
|
||||
+ info = get_info('blas_opt')
|
||||
+ if not info:
|
||||
+ warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3)
|
||||
+ info_src = get_info('blas_src')
|
||||
+ if not info_src:
|
||||
+ warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3)
|
||||
+ return {}
|
||||
+ dict_append(info, libraries=[('fblas_src', info_src)])
|
||||
+ return info
|
||||
|
||||
- need_lapack = 0
|
||||
- need_blas = 0
|
||||
- info = {}
|
||||
- if atlas_info:
|
||||
- l = atlas_info.get('define_macros', [])
|
||||
- if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \
|
||||
- or ('ATLAS_WITHOUT_LAPACK', None) in l:
|
||||
- need_lapack = 1
|
||||
- info = atlas_info
|
||||
+ def _get_info_lapack(self):
|
||||
+ info = get_info('lapack')
|
||||
+ if not info:
|
||||
+ warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=3)
|
||||
+ info_src = get_info('lapack_src')
|
||||
+ if not info_src:
|
||||
+ warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=3)
|
||||
+ return {}
|
||||
+ dict_append(info, libraries=[('flapack_src', info_src)])
|
||||
+ return info
|
||||
|
||||
- else:
|
||||
- warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2)
|
||||
- need_blas = 1
|
||||
- need_lapack = 1
|
||||
+ def _calc_info_lapack(self):
|
||||
+ info = self._get_info_lapack()
|
||||
+ if info:
|
||||
+ info_blas = self._get_info_blas()
|
||||
+ dict_append(info, **info_blas)
|
||||
dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- if need_lapack:
|
||||
- lapack_info = get_info('lapack')
|
||||
- #lapack_info = {} ## uncomment for testing
|
||||
- if lapack_info:
|
||||
- dict_append(info, **lapack_info)
|
||||
- else:
|
||||
- warnings.warn(LapackNotFoundError.__doc__, stacklevel=2)
|
||||
- lapack_src_info = get_info('lapack_src')
|
||||
- if not lapack_src_info:
|
||||
- warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=2)
|
||||
- return
|
||||
- dict_append(info, libraries=[('flapack_src', lapack_src_info)])
|
||||
-
|
||||
- if need_blas:
|
||||
- blas_info = get_info('blas')
|
||||
- if blas_info:
|
||||
- dict_append(info, **blas_info)
|
||||
- else:
|
||||
- warnings.warn(BlasNotFoundError.__doc__, stacklevel=2)
|
||||
- blas_src_info = get_info('blas_src')
|
||||
- if not blas_src_info:
|
||||
- warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2)
|
||||
- return
|
||||
- dict_append(info, libraries=[('fblas_src', blas_src_info)])
|
||||
+ def calc_info(self):
|
||||
+ user_order = os.environ.get('NPY_LAPACK_ORDER', None)
|
||||
+ if user_order is None:
|
||||
+ lapack_order = self.lapack_order
|
||||
+ else:
|
||||
+ # the user has requested the order of the
|
||||
+ # check they are all in the available list, a COMMA SEPARATED list
|
||||
+ user_order = user_order.lower().split(',')
|
||||
+ non_existing = []
|
||||
+ lapack_order = []
|
||||
+ for order in user_order:
|
||||
+ if order in self.lapack_order:
|
||||
+ lapack_order.append(order)
|
||||
+ elif len(order) > 0:
|
||||
+ non_existing.append(order)
|
||||
+ if len(non_existing) > 0:
|
||||
+ raise ValueError("lapack_opt_info user defined "
|
||||
+ "LAPACK order has unacceptable "
|
||||
+ "values: {}".format(non_existing))
|
||||
+
|
||||
+ for lapack in lapack_order:
|
||||
+ if getattr(self, '_calc_info_{}'.format(lapack))():
|
||||
+ return
|
||||
|
||||
- self.set_info(**info)
|
||||
- return
|
||||
+ if 'lapack' not in lapack_order:
|
||||
+ # Since the user may request *not* to use any library, we still need
|
||||
+ # to raise warnings to signal missing packages!
|
||||
+ warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=2)
|
||||
+ warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=2)
|
||||
|
||||
|
||||
class blas_opt_info(system_info):
|
||||
|
||||
notfounderror = BlasNotFoundError
|
||||
+ # Default order of BLAS checks
|
||||
+ blas_order = ['mkl', 'blis', 'openblas', 'atlas', 'accelerate', 'blas']
|
||||
|
||||
- def calc_info(self):
|
||||
+ def _calc_info_mkl(self):
|
||||
+ info = get_info('blas_mkl')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- blas_mkl_info = get_info('blas_mkl')
|
||||
- if blas_mkl_info:
|
||||
- self.set_info(**blas_mkl_info)
|
||||
- return
|
||||
+ def _calc_info_blis(self):
|
||||
+ info = get_info('blis')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- blis_info = get_info('blis')
|
||||
- if blis_info:
|
||||
- self.set_info(**blis_info)
|
||||
- return
|
||||
+ def _calc_info_openblas(self):
|
||||
+ info = get_info('openblas')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- openblas_info = get_info('openblas')
|
||||
- if openblas_info:
|
||||
- self.set_info(**openblas_info)
|
||||
- return
|
||||
+ def _calc_info_atlas(self):
|
||||
+ info = get_info('atlas_3_10_blas_threads')
|
||||
+ if not info:
|
||||
+ info = get_info('atlas_3_10_blas')
|
||||
+ if not info:
|
||||
+ info = get_info('atlas_blas_threads')
|
||||
+ if not info:
|
||||
+ info = get_info('atlas_blas')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- atlas_info = get_info('atlas_3_10_blas_threads')
|
||||
- if not atlas_info:
|
||||
- atlas_info = get_info('atlas_3_10_blas')
|
||||
- if not atlas_info:
|
||||
- atlas_info = get_info('atlas_blas_threads')
|
||||
- if not atlas_info:
|
||||
- atlas_info = get_info('atlas_blas')
|
||||
-
|
||||
- accelerate_info = get_info('accelerate')
|
||||
- if accelerate_info and not atlas_info:
|
||||
- self.set_info(**accelerate_info)
|
||||
- return
|
||||
+ def _calc_info_accelerate(self):
|
||||
+ info = get_info('accelerate')
|
||||
+ if info:
|
||||
+ self.set_info(**info)
|
||||
+ return True
|
||||
+ return False
|
||||
|
||||
- need_blas = 0
|
||||
+ def _calc_info_blas(self):
|
||||
+ # Warn about a non-optimized BLAS library
|
||||
+ warnings.warn(BlasOptNotFoundError.__doc__ or '', stacklevel=3)
|
||||
info = {}
|
||||
- if atlas_info:
|
||||
- info = atlas_info
|
||||
+ dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
|
||||
+
|
||||
+ blas = get_info('blas')
|
||||
+ if blas:
|
||||
+ dict_append(info, **blas)
|
||||
else:
|
||||
- warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2)
|
||||
- need_blas = 1
|
||||
- dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
|
||||
+ # Not even BLAS was found!
|
||||
+ warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3)
|
||||
|
||||
- if need_blas:
|
||||
- blas_info = get_info('blas')
|
||||
- if blas_info:
|
||||
- dict_append(info, **blas_info)
|
||||
- else:
|
||||
- warnings.warn(BlasNotFoundError.__doc__, stacklevel=2)
|
||||
- blas_src_info = get_info('blas_src')
|
||||
- if not blas_src_info:
|
||||
- warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2)
|
||||
- return
|
||||
- dict_append(info, libraries=[('fblas_src', blas_src_info)])
|
||||
+ blas_src = get_info('blas_src')
|
||||
+ if not blas_src:
|
||||
+ warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3)
|
||||
+ return False
|
||||
+ dict_append(info, libraries=[('fblas_src', blas_src)])
|
||||
|
||||
self.set_info(**info)
|
||||
- return
|
||||
+ return True
|
||||
+
|
||||
+ def calc_info(self):
|
||||
+ user_order = os.environ.get('NPY_BLAS_ORDER', None)
|
||||
+ if user_order is None:
|
||||
+ blas_order = self.blas_order
|
||||
+ else:
|
||||
+ # the user has requested the order of the
|
||||
+ # check they are all in the available list
|
||||
+ user_order = user_order.lower().split(',')
|
||||
+ non_existing = []
|
||||
+ blas_order = []
|
||||
+ for order in user_order:
|
||||
+ if order in self.blas_order:
|
||||
+ blas_order.append(order)
|
||||
+ elif len(order) > 0:
|
||||
+ non_existing.append(order)
|
||||
+ if len(non_existing) > 0:
|
||||
+ raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(non_existing))
|
||||
+
|
||||
+ for blas in blas_order:
|
||||
+ if getattr(self, '_calc_info_{}'.format(blas))():
|
||||
+ return
|
||||
+
|
||||
+ if 'blas' not in blas_order:
|
||||
+ # Since the user may request *not* to use any library, we still need
|
||||
+ # to raise warnings to signal missing packages!
|
||||
+ warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=2)
|
||||
+ warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=2)
|
||||
|
||||
|
||||
class blas_info(system_info):
|
|
@ -15,8 +15,9 @@ class PyNumpy(PythonPackage):
|
|||
number capabilities"""
|
||||
|
||||
homepage = "http://www.numpy.org/"
|
||||
url = "https://pypi.io/packages/source/n/numpy/numpy-1.16.4.zip"
|
||||
url = "https://pypi.io/packages/source/n/numpy/numpy-1.17.0.zip"
|
||||
|
||||
maintainers = ['adamjstewart']
|
||||
install_time_test_callbacks = ['install_test', 'import_module_test']
|
||||
|
||||
import_modules = [
|
||||
|
@ -26,6 +27,7 @@ class PyNumpy(PythonPackage):
|
|||
'numpy.distutils.command', 'numpy.distutils.fcompiler'
|
||||
]
|
||||
|
||||
version('1.17.0', sha256='951fefe2fb73f84c620bec4e001e80a80ddaa1b84dce244ded7f1e0cbe0ed34a')
|
||||
version('1.16.4', sha256='7242be12a58fec245ee9734e625964b97cf7e3f2f7d016603f9e56660ce479c7')
|
||||
version('1.16.3', sha256='78a6f89da87eeb48014ec652a65c4ffde370c036d780a995edaeb121d3625621')
|
||||
version('1.16.2', sha256='6c692e3879dde0b67a9dc78f9bfb6f61c666b4562fd8619632d7043fb5b691b0')
|
||||
|
@ -62,6 +64,8 @@ class PyNumpy(PythonPackage):
|
|||
variant('lapack', default=True, description='Build with LAPACK support')
|
||||
|
||||
depends_on('python@2.7:2.8,3.4:', type=('build', 'run'))
|
||||
depends_on('python@2.7:2.8,3.5:', type=('build', 'run'), when='@1.16:')
|
||||
depends_on('python@3.5:', type=('build', 'run'), when='@1.17:')
|
||||
depends_on('py-setuptools', type='build')
|
||||
depends_on('blas', when='+blas')
|
||||
depends_on('lapack', when='+lapack')
|
||||
|
@ -69,129 +73,175 @@ class PyNumpy(PythonPackage):
|
|||
depends_on('py-nose@1.0.0:', when='@:1.14', type='test')
|
||||
depends_on('py-pytest', when='@1.15:', type='test')
|
||||
|
||||
def setup_dependent_package(self, module, dependent_spec):
|
||||
python_version = self.spec['python'].version.up_to(2)
|
||||
# Allows you to specify order of BLAS/LAPACK preference
|
||||
# https://github.com/numpy/numpy/pull/13132
|
||||
patch('blas-lapack-order.patch', when='@1.15:1.16')
|
||||
|
||||
self.spec.include = join_path(
|
||||
self.prefix.lib,
|
||||
'python{0}'.format(python_version),
|
||||
'site-packages',
|
||||
'numpy/core/include')
|
||||
# GCC 4.8 is the minimum version that works
|
||||
conflicts('%gcc@:4.7', msg='GCC 4.8+ required')
|
||||
|
||||
def patch(self):
|
||||
def flag_handler(self, name, flags):
|
||||
# -std=c99 at least required, old versions of GCC default to -std=c90
|
||||
if self.spec.satisfies('%gcc@:5.1') and name == 'cflags':
|
||||
flags.append(self.compiler.c99_flag)
|
||||
return (flags, None, None)
|
||||
|
||||
@run_before('build')
|
||||
def set_blas_lapack(self):
|
||||
# https://numpy.org/devdocs/user/building.html
|
||||
# https://github.com/numpy/numpy/blob/master/site.cfg.example
|
||||
|
||||
# Skip if no BLAS/LAPACK requested
|
||||
spec = self.spec
|
||||
if '+blas' not in spec and '+lapack' not in spec:
|
||||
return
|
||||
|
||||
def write_library_dirs(f, dirs):
|
||||
f.write('library_dirs=%s\n' % dirs)
|
||||
if not ((platform.system() == "Darwin") and
|
||||
f.write('library_dirs = {0}\n'.format(dirs))
|
||||
if not ((platform.system() == 'Darwin') and
|
||||
(Version(platform.mac_ver()[0]).up_to(2) == Version(
|
||||
'10.12'))):
|
||||
f.write('rpath=%s\n' % dirs)
|
||||
|
||||
# for build notes see http://www.scipy.org/scipylib/building/linux.html
|
||||
blas_info = []
|
||||
lapack_info = []
|
||||
lapackblas_info = []
|
||||
|
||||
if '+lapack' in spec:
|
||||
lapack_info += spec['lapack'].libs
|
||||
f.write('rpath = {0}\n'.format(dirs))
|
||||
|
||||
blas_libs = LibraryList([])
|
||||
blas_headers = HeaderList([])
|
||||
if '+blas' in spec:
|
||||
blas_info += spec['blas'].libs
|
||||
blas_libs = spec['blas'].libs
|
||||
blas_headers = spec['blas'].headers
|
||||
|
||||
lapackblas_info = lapack_info + blas_info
|
||||
lapack_libs = LibraryList([])
|
||||
lapack_headers = HeaderList([])
|
||||
if '+lapack' in spec:
|
||||
lapack_libs = spec['lapack'].libs
|
||||
lapack_headers = spec['lapack'].headers
|
||||
|
||||
def write_empty_libs(f, provider):
|
||||
f.write('[{0}]\n'.format(provider))
|
||||
f.write('libraries=\n')
|
||||
write_library_dirs(f, '')
|
||||
lapackblas_libs = lapack_libs + blas_libs
|
||||
lapackblas_headers = lapack_headers + blas_headers
|
||||
|
||||
if '+blas' in spec or '+lapack' in spec:
|
||||
# note that one should not use [blas_opt] and [lapack_opt], see
|
||||
# https://github.com/numpy/numpy/commit/ffd4332262ee0295cb942c94ed124f043d801eb6
|
||||
with open('site.cfg', 'w') as f:
|
||||
# Unfortunately, numpy prefers to provide each BLAS/LAPACK
|
||||
# differently.
|
||||
blas_names = ','.join(blas_info.names)
|
||||
blas_dirs = ':'.join(blas_info.directories)
|
||||
lapack_names = ','.join(lapack_info.names)
|
||||
lapack_dirs = ':'.join(lapack_info.directories)
|
||||
lapackblas_names = ','.join(lapackblas_info.names)
|
||||
lapackblas_dirs = ':'.join(lapackblas_info.directories)
|
||||
blas_lib_names = ','.join(blas_libs.names)
|
||||
blas_lib_dirs = ':'.join(blas_libs.directories)
|
||||
blas_header_dirs = ':'.join(blas_headers.directories)
|
||||
|
||||
handled_blas_and_lapack = False
|
||||
lapack_lib_names = ','.join(lapack_libs.names)
|
||||
lapack_lib_dirs = ':'.join(lapack_libs.directories)
|
||||
lapack_header_dirs = ':'.join(lapack_headers.directories)
|
||||
|
||||
# Special treatment for some (!) BLAS/LAPACK. Note that
|
||||
# in this case library_dirs can not be specified within [ALL].
|
||||
if '^openblas' in spec:
|
||||
f.write('[openblas]\n')
|
||||
f.write('libraries=%s\n' % lapackblas_names)
|
||||
write_library_dirs(f, lapackblas_dirs)
|
||||
handled_blas_and_lapack = True
|
||||
else:
|
||||
write_empty_libs(f, 'openblas')
|
||||
lapackblas_lib_names = ','.join(lapackblas_libs.names)
|
||||
lapackblas_lib_dirs = ':'.join(lapackblas_libs.directories)
|
||||
lapackblas_header_dirs = ':'.join(lapackblas_headers.directories)
|
||||
|
||||
if '^mkl' in spec:
|
||||
# numpy does not expect system libraries needed for MKL
|
||||
# here.
|
||||
# names = [x for x in names if x.startswith('mkl')]
|
||||
# FIXME: as of @1.11.2, numpy does not work with separately
|
||||
# specified threading and interface layers. A workaround is
|
||||
# a terribly bad idea to use mkl_rt. In this case Spack
|
||||
# will no longer be able to guarantee that one and the
|
||||
# same variant of Blas/Lapack (32/64bit, threaded/serial)
|
||||
# is used within the DAG. This may lead to a lot of
|
||||
# hard-to-debug segmentation faults on user's side. Users
|
||||
# may also break working installation by (unconsciously)
|
||||
# setting environment variable to switch between different
|
||||
# interface and threading layers dynamically. From this
|
||||
# perspective it is no different from throwing away RPATH's
|
||||
# and using LD_LIBRARY_PATH throughout Spack.
|
||||
f.write('[mkl]\n')
|
||||
f.write('mkl_libs=%s\n' % 'mkl_rt')
|
||||
write_library_dirs(f, lapackblas_dirs)
|
||||
handled_blas_and_lapack = True
|
||||
else:
|
||||
# Without explicitly setting the search directories to be
|
||||
# an empty list, numpy may retrieve and use mkl libs from
|
||||
# the system.
|
||||
write_empty_libs(f, 'mkl')
|
||||
# Tell numpy where to find BLAS/LAPACK libraries
|
||||
with open('site.cfg', 'w') as f:
|
||||
if '^intel-mkl' in spec or '^intel-parallel-studio+mkl' in spec:
|
||||
f.write('[mkl]\n')
|
||||
# FIXME: as of @1.11.2, numpy does not work with separately
|
||||
# specified threading and interface layers. A workaround is a
|
||||
# terribly bad idea to use mkl_rt. In this case Spack will no
|
||||
# longer be able to guarantee that one and the same variant of
|
||||
# Blas/Lapack (32/64bit, threaded/serial) is used within the
|
||||
# DAG. This may lead to a lot of hard-to-debug segmentation
|
||||
# faults on user's side. Users may also break working
|
||||
# installation by (unconsciously) setting environment variable
|
||||
# to switch between different interface and threading layers
|
||||
# dynamically. From this perspective it is no different from
|
||||
# throwing away RPATH's and using LD_LIBRARY_PATH throughout
|
||||
# Spack.
|
||||
f.write('libraries = {0}\n'.format('mkl_rt'))
|
||||
write_library_dirs(f, lapackblas_lib_dirs)
|
||||
f.write('include_dirs = {0}\n'.format(lapackblas_header_dirs))
|
||||
|
||||
if '^atlas' in spec:
|
||||
f.write('[atlas]\n')
|
||||
f.write('atlas_libs=%s\n' % lapackblas_names)
|
||||
write_library_dirs(f, lapackblas_dirs)
|
||||
handled_blas_and_lapack = True
|
||||
else:
|
||||
write_empty_libs(f, 'atlas')
|
||||
if '^blis' in spec:
|
||||
f.write('[blis]\n')
|
||||
f.write('libraries = {0}\n'.format(blas_lib_names))
|
||||
write_library_dirs(f, blas_lib_dirs)
|
||||
f.write('include_dirs = {0}\n'.format(blas_header_dirs))
|
||||
|
||||
if '^netlib-lapack' in spec:
|
||||
# netlib requires blas and lapack listed
|
||||
# separately so that scipy can find them
|
||||
if spec.satisfies('+blas'):
|
||||
f.write('[blas]\n')
|
||||
f.write('blas_libs=%s\n' % blas_names)
|
||||
write_library_dirs(f, blas_dirs)
|
||||
if spec.satisfies('+lapack'):
|
||||
f.write('[lapack]\n')
|
||||
f.write('lapack_libs=%s\n' % lapack_names)
|
||||
write_library_dirs(f, lapack_dirs)
|
||||
handled_blas_and_lapack = True
|
||||
if '^openblas' in spec:
|
||||
f.write('[openblas]\n')
|
||||
f.write('libraries = {0}\n'.format(lapackblas_lib_names))
|
||||
write_library_dirs(f, lapackblas_lib_dirs)
|
||||
f.write('include_dirs = {0}\n'.format(lapackblas_header_dirs))
|
||||
|
||||
if not handled_blas_and_lapack:
|
||||
# The section title for the defaults changed in @1.10, see
|
||||
# https://github.com/numpy/numpy/blob/master/site.cfg.example
|
||||
if spec.satisfies('@:1.9.2'):
|
||||
f.write('[DEFAULT]\n')
|
||||
else:
|
||||
f.write('[ALL]\n')
|
||||
f.write('libraries=%s\n' % lapackblas_names)
|
||||
write_library_dirs(f, lapackblas_dirs)
|
||||
if '^libflame' in spec:
|
||||
f.write('[flame]\n')
|
||||
f.write('libraries = {0}\n'.format(lapack_lib_names))
|
||||
write_library_dirs(f, lapack_lib_dirs)
|
||||
f.write('include_dirs = {0}\n'.format(lapack_header_dirs))
|
||||
|
||||
if '^atlas' in spec:
|
||||
f.write('[atlas]\n')
|
||||
f.write('libraries = {0}\n'.format(lapackblas_lib_names))
|
||||
write_library_dirs(f, lapackblas_lib_dirs)
|
||||
f.write('include_dirs = {0}\n'.format(lapackblas_header_dirs))
|
||||
|
||||
if '^veclibfort' in spec:
|
||||
f.write('[accelerate]\n')
|
||||
f.write('libraries = {0}\n'.format(lapackblas_lib_names))
|
||||
write_library_dirs(f, lapackblas_lib_dirs)
|
||||
|
||||
if '^netlib-lapack' in spec:
|
||||
# netlib requires blas and lapack listed
|
||||
# separately so that scipy can find them
|
||||
if spec.satisfies('+blas'):
|
||||
f.write('[blas]\n')
|
||||
f.write('libraries = {0}\n'.format(blas_lib_names))
|
||||
write_library_dirs(f, blas_lib_dirs)
|
||||
f.write('include_dirs = {0}\n'.format(blas_header_dirs))
|
||||
if spec.satisfies('+lapack'):
|
||||
f.write('[lapack]\n')
|
||||
f.write('libraries = {0}\n'.format(lapack_lib_names))
|
||||
write_library_dirs(f, lapack_lib_dirs)
|
||||
f.write('include_dirs = {0}\n'.format(lapack_header_dirs))
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
# Tell numpy which BLAS/LAPACK libraries we want to use.
|
||||
# https://github.com/numpy/numpy/pull/13132
|
||||
# https://numpy.org/devdocs/user/building.html#accelerated-blas-lapack-libraries
|
||||
spec = self.spec
|
||||
|
||||
# https://numpy.org/devdocs/user/building.html#blas
|
||||
if '~blas' in spec:
|
||||
blas = ''
|
||||
elif spec['blas'].name == 'intel-mkl' or \
|
||||
spec['blas'].name == 'intel-parallel-studio':
|
||||
blas = 'mkl'
|
||||
elif spec['blas'].name == 'blis':
|
||||
blas = 'blis'
|
||||
elif spec['blas'].name == 'openblas':
|
||||
blas = 'openblas'
|
||||
elif spec['blas'].name == 'atlas':
|
||||
blas = 'atlas'
|
||||
elif spec['blas'].name == 'veclibfort':
|
||||
blas = 'accelerate'
|
||||
else:
|
||||
blas = 'blas'
|
||||
|
||||
spack_env.set('NPY_BLAS_ORDER', blas)
|
||||
|
||||
# https://numpy.org/devdocs/user/building.html#lapack
|
||||
if '~lapack' in spec:
|
||||
lapack = ''
|
||||
elif spec['lapack'].name == 'intel-mkl' or \
|
||||
spec['lapack'].name == 'intel-parallel-studio':
|
||||
lapack = 'mkl'
|
||||
elif spec['lapack'].name == 'openblas':
|
||||
lapack = 'openblas'
|
||||
elif spec['lapack'].name == 'libflame':
|
||||
lapack = 'flame'
|
||||
elif spec['lapack'].name == 'atlas':
|
||||
lapack = 'atlas'
|
||||
elif spec['lapack'].name == 'veclibfort':
|
||||
lapack = 'accelerate'
|
||||
else:
|
||||
lapack = 'lapack'
|
||||
|
||||
spack_env.set('NPY_LAPACK_ORDER', lapack)
|
||||
|
||||
def build_args(self, spec, prefix):
|
||||
args = []
|
||||
|
||||
# From NumPy 1.10.0 on it's possible to do a parallel build.
|
||||
# https://numpy.org/devdocs/user/building.html#parallel-builds
|
||||
if self.version >= Version('1.10.0'):
|
||||
# But Parallel build in Python 3.5+ is broken. See:
|
||||
# https://github.com/spack/spack/issues/7927
|
||||
|
@ -201,20 +251,6 @@ def build_args(self, spec, prefix):
|
|||
|
||||
return args
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
# If py-numpy is installed as an external package, python won't
|
||||
# be available in the spec. See #9149 for details.
|
||||
if 'python' in self.spec:
|
||||
python_version = self.spec['python'].version.up_to(2)
|
||||
|
||||
include_path = join_path(
|
||||
self.prefix.lib,
|
||||
'python{0}'.format(python_version),
|
||||
'site-packages',
|
||||
'numpy/core/include')
|
||||
|
||||
run_env.prepend_path('CPATH', include_path)
|
||||
|
||||
def test(self):
|
||||
# `setup.py test` is not supported. Use one of the following
|
||||
# instead:
|
||||
|
|
|
@ -33,6 +33,12 @@ def libs(self):
|
|||
'libvecLibFort', root=self.prefix, shared=shared, recursive=True
|
||||
)
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
# veclibfort does not come with any headers. Return an empty list
|
||||
# to avoid `spec['blas'].headers` from crashing.
|
||||
return HeaderList([])
|
||||
|
||||
def install(self, spec, prefix):
|
||||
if sys.platform != 'darwin':
|
||||
raise InstallError('vecLibFort can be installed on macOS only')
|
||||
|
|
Loading…
Reference in a new issue