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/"
|
homepage = "http://math-atlas.sourceforge.net/"
|
||||||
|
|
||||||
version('3.11.39', '5f3252fa980f5f060f93edd4669321e2',
|
# Developer (unstable)
|
||||||
url='http://sourceforge.net/projects/math-atlas/files/Developer%20%28unstable%29/3.11.39/atlas3.11.39.tar.bz2')
|
version('3.11.41', sha256='477d567a8d683e891d786e9e8bb6ad6659daa9ba18e8dd0e2f70b7a54095f8de')
|
||||||
|
version('3.11.39', '5f3252fa980f5f060f93edd4669321e2')
|
||||||
|
version('3.11.34', '0b6c5389c095c4c8785fd0f724ec6825')
|
||||||
|
|
||||||
version('3.11.34', '0b6c5389c095c4c8785fd0f724ec6825',
|
# Stable
|
||||||
url='http://sourceforge.net/projects/math-atlas/files/Developer%20%28unstable%29/3.11.34/atlas3.11.34.tar.bz2')
|
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
|
# 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.
|
# Lapack routines. Stick with 3.5.0 until this is fixed.
|
||||||
resource(name='lapack',
|
resource(name='lapack',
|
||||||
|
@ -57,6 +55,16 @@ class Atlas(Package):
|
||||||
|
|
||||||
parallel = False
|
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):
|
def patch(self):
|
||||||
# Disable thread check. LLNL's environment does not allow
|
# Disable thread check. LLNL's environment does not allow
|
||||||
# disabling of CPU throttling in a way that ATLAS actually
|
# disabling of CPU throttling in a way that ATLAS actually
|
||||||
|
@ -94,6 +102,11 @@ def install(self, spec, prefix):
|
||||||
'-C', 'if', spack_f77
|
'-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
|
# Lapack resource to provide full lapack build. Note that
|
||||||
# ATLAS only provides a few LAPACK routines natively.
|
# ATLAS only provides a few LAPACK routines natively.
|
||||||
options.append('--with-netlib-lapack-tarfile=%s' %
|
options.append('--with-netlib-lapack-tarfile=%s' %
|
||||||
|
|
|
@ -51,6 +51,12 @@ class Libflame(AutotoolsPackage):
|
||||||
# https://groups.google.com/forum/#!topic/libflame-discuss/lQKEfjyudOY
|
# https://groups.google.com/forum/#!topic/libflame-discuss/lQKEfjyudOY
|
||||||
patch('Makefile_5.1.0.patch', when='@5.1.0')
|
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):
|
def configure_args(self):
|
||||||
config_args = []
|
config_args = []
|
||||||
|
|
||||||
|
@ -83,7 +89,6 @@ def configure_args(self):
|
||||||
config_args.append("--disable-supermatrix")
|
config_args.append("--disable-supermatrix")
|
||||||
|
|
||||||
# https://github.com/flame/libflame/issues/21
|
# 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
|
return config_args
|
||||||
|
|
|
@ -38,7 +38,10 @@ def setup_file(self):
|
||||||
def common_args(self, spec, prefix):
|
def common_args(self, spec, prefix):
|
||||||
include_dirs = [
|
include_dirs = [
|
||||||
spec['meep'].prefix.include,
|
spec['meep'].prefix.include,
|
||||||
spec['py-numpy'].include
|
os.path.join(
|
||||||
|
spec['py-numpy'].prefix,
|
||||||
|
spec['python'].package.python_include_dir
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
library_dirs = [
|
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"""
|
number capabilities"""
|
||||||
|
|
||||||
homepage = "http://www.numpy.org/"
|
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']
|
install_time_test_callbacks = ['install_test', 'import_module_test']
|
||||||
|
|
||||||
import_modules = [
|
import_modules = [
|
||||||
|
@ -26,6 +27,7 @@ class PyNumpy(PythonPackage):
|
||||||
'numpy.distutils.command', 'numpy.distutils.fcompiler'
|
'numpy.distutils.command', 'numpy.distutils.fcompiler'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
version('1.17.0', sha256='951fefe2fb73f84c620bec4e001e80a80ddaa1b84dce244ded7f1e0cbe0ed34a')
|
||||||
version('1.16.4', sha256='7242be12a58fec245ee9734e625964b97cf7e3f2f7d016603f9e56660ce479c7')
|
version('1.16.4', sha256='7242be12a58fec245ee9734e625964b97cf7e3f2f7d016603f9e56660ce479c7')
|
||||||
version('1.16.3', sha256='78a6f89da87eeb48014ec652a65c4ffde370c036d780a995edaeb121d3625621')
|
version('1.16.3', sha256='78a6f89da87eeb48014ec652a65c4ffde370c036d780a995edaeb121d3625621')
|
||||||
version('1.16.2', sha256='6c692e3879dde0b67a9dc78f9bfb6f61c666b4562fd8619632d7043fb5b691b0')
|
version('1.16.2', sha256='6c692e3879dde0b67a9dc78f9bfb6f61c666b4562fd8619632d7043fb5b691b0')
|
||||||
|
@ -62,6 +64,8 @@ class PyNumpy(PythonPackage):
|
||||||
variant('lapack', default=True, description='Build with LAPACK support')
|
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.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('py-setuptools', type='build')
|
||||||
depends_on('blas', when='+blas')
|
depends_on('blas', when='+blas')
|
||||||
depends_on('lapack', when='+lapack')
|
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-nose@1.0.0:', when='@:1.14', type='test')
|
||||||
depends_on('py-pytest', when='@1.15:', type='test')
|
depends_on('py-pytest', when='@1.15:', type='test')
|
||||||
|
|
||||||
def setup_dependent_package(self, module, dependent_spec):
|
# Allows you to specify order of BLAS/LAPACK preference
|
||||||
python_version = self.spec['python'].version.up_to(2)
|
# https://github.com/numpy/numpy/pull/13132
|
||||||
|
patch('blas-lapack-order.patch', when='@1.15:1.16')
|
||||||
|
|
||||||
self.spec.include = join_path(
|
# GCC 4.8 is the minimum version that works
|
||||||
self.prefix.lib,
|
conflicts('%gcc@:4.7', msg='GCC 4.8+ required')
|
||||||
'python{0}'.format(python_version),
|
|
||||||
'site-packages',
|
|
||||||
'numpy/core/include')
|
|
||||||
|
|
||||||
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
|
spec = self.spec
|
||||||
|
if '+blas' not in spec and '+lapack' not in spec:
|
||||||
|
return
|
||||||
|
|
||||||
def write_library_dirs(f, dirs):
|
def write_library_dirs(f, dirs):
|
||||||
f.write('library_dirs=%s\n' % dirs)
|
f.write('library_dirs = {0}\n'.format(dirs))
|
||||||
if not ((platform.system() == "Darwin") and
|
if not ((platform.system() == 'Darwin') and
|
||||||
(Version(platform.mac_ver()[0]).up_to(2) == Version(
|
(Version(platform.mac_ver()[0]).up_to(2) == Version(
|
||||||
'10.12'))):
|
'10.12'))):
|
||||||
f.write('rpath=%s\n' % dirs)
|
f.write('rpath = {0}\n'.format(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
|
|
||||||
|
|
||||||
|
blas_libs = LibraryList([])
|
||||||
|
blas_headers = HeaderList([])
|
||||||
if '+blas' in spec:
|
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):
|
lapackblas_libs = lapack_libs + blas_libs
|
||||||
f.write('[{0}]\n'.format(provider))
|
lapackblas_headers = lapack_headers + blas_headers
|
||||||
f.write('libraries=\n')
|
|
||||||
write_library_dirs(f, '')
|
|
||||||
|
|
||||||
if '+blas' in spec or '+lapack' in spec:
|
blas_lib_names = ','.join(blas_libs.names)
|
||||||
# note that one should not use [blas_opt] and [lapack_opt], see
|
blas_lib_dirs = ':'.join(blas_libs.directories)
|
||||||
# https://github.com/numpy/numpy/commit/ffd4332262ee0295cb942c94ed124f043d801eb6
|
blas_header_dirs = ':'.join(blas_headers.directories)
|
||||||
|
|
||||||
|
lapack_lib_names = ','.join(lapack_libs.names)
|
||||||
|
lapack_lib_dirs = ':'.join(lapack_libs.directories)
|
||||||
|
lapack_header_dirs = ':'.join(lapack_headers.directories)
|
||||||
|
|
||||||
|
lapackblas_lib_names = ','.join(lapackblas_libs.names)
|
||||||
|
lapackblas_lib_dirs = ':'.join(lapackblas_libs.directories)
|
||||||
|
lapackblas_header_dirs = ':'.join(lapackblas_headers.directories)
|
||||||
|
|
||||||
|
# Tell numpy where to find BLAS/LAPACK libraries
|
||||||
with open('site.cfg', 'w') as f:
|
with open('site.cfg', 'w') as f:
|
||||||
# Unfortunately, numpy prefers to provide each BLAS/LAPACK
|
if '^intel-mkl' in spec or '^intel-parallel-studio+mkl' in spec:
|
||||||
# differently.
|
f.write('[mkl]\n')
|
||||||
blas_names = ','.join(blas_info.names)
|
# FIXME: as of @1.11.2, numpy does not work with separately
|
||||||
blas_dirs = ':'.join(blas_info.directories)
|
# specified threading and interface layers. A workaround is a
|
||||||
lapack_names = ','.join(lapack_info.names)
|
# terribly bad idea to use mkl_rt. In this case Spack will no
|
||||||
lapack_dirs = ':'.join(lapack_info.directories)
|
# longer be able to guarantee that one and the same variant of
|
||||||
lapackblas_names = ','.join(lapackblas_info.names)
|
# Blas/Lapack (32/64bit, threaded/serial) is used within the
|
||||||
lapackblas_dirs = ':'.join(lapackblas_info.directories)
|
# 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))
|
||||||
|
|
||||||
handled_blas_and_lapack = False
|
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))
|
||||||
|
|
||||||
# Special treatment for some (!) BLAS/LAPACK. Note that
|
|
||||||
# in this case library_dirs can not be specified within [ALL].
|
|
||||||
if '^openblas' in spec:
|
if '^openblas' in spec:
|
||||||
f.write('[openblas]\n')
|
f.write('[openblas]\n')
|
||||||
f.write('libraries=%s\n' % lapackblas_names)
|
f.write('libraries = {0}\n'.format(lapackblas_lib_names))
|
||||||
write_library_dirs(f, lapackblas_dirs)
|
write_library_dirs(f, lapackblas_lib_dirs)
|
||||||
handled_blas_and_lapack = True
|
f.write('include_dirs = {0}\n'.format(lapackblas_header_dirs))
|
||||||
else:
|
|
||||||
write_empty_libs(f, 'openblas')
|
|
||||||
|
|
||||||
if '^mkl' in spec:
|
if '^libflame' in spec:
|
||||||
# numpy does not expect system libraries needed for MKL
|
f.write('[flame]\n')
|
||||||
# here.
|
f.write('libraries = {0}\n'.format(lapack_lib_names))
|
||||||
# names = [x for x in names if x.startswith('mkl')]
|
write_library_dirs(f, lapack_lib_dirs)
|
||||||
# FIXME: as of @1.11.2, numpy does not work with separately
|
f.write('include_dirs = {0}\n'.format(lapack_header_dirs))
|
||||||
# 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')
|
|
||||||
|
|
||||||
if '^atlas' in spec:
|
if '^atlas' in spec:
|
||||||
f.write('[atlas]\n')
|
f.write('[atlas]\n')
|
||||||
f.write('atlas_libs=%s\n' % lapackblas_names)
|
f.write('libraries = {0}\n'.format(lapackblas_lib_names))
|
||||||
write_library_dirs(f, lapackblas_dirs)
|
write_library_dirs(f, lapackblas_lib_dirs)
|
||||||
handled_blas_and_lapack = True
|
f.write('include_dirs = {0}\n'.format(lapackblas_header_dirs))
|
||||||
else:
|
|
||||||
write_empty_libs(f, 'atlas')
|
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:
|
if '^netlib-lapack' in spec:
|
||||||
# netlib requires blas and lapack listed
|
# netlib requires blas and lapack listed
|
||||||
# separately so that scipy can find them
|
# separately so that scipy can find them
|
||||||
if spec.satisfies('+blas'):
|
if spec.satisfies('+blas'):
|
||||||
f.write('[blas]\n')
|
f.write('[blas]\n')
|
||||||
f.write('blas_libs=%s\n' % blas_names)
|
f.write('libraries = {0}\n'.format(blas_lib_names))
|
||||||
write_library_dirs(f, blas_dirs)
|
write_library_dirs(f, blas_lib_dirs)
|
||||||
|
f.write('include_dirs = {0}\n'.format(blas_header_dirs))
|
||||||
if spec.satisfies('+lapack'):
|
if spec.satisfies('+lapack'):
|
||||||
f.write('[lapack]\n')
|
f.write('[lapack]\n')
|
||||||
f.write('lapack_libs=%s\n' % lapack_names)
|
f.write('libraries = {0}\n'.format(lapack_lib_names))
|
||||||
write_library_dirs(f, lapack_dirs)
|
write_library_dirs(f, lapack_lib_dirs)
|
||||||
handled_blas_and_lapack = True
|
f.write('include_dirs = {0}\n'.format(lapack_header_dirs))
|
||||||
|
|
||||||
if not handled_blas_and_lapack:
|
def setup_environment(self, spack_env, run_env):
|
||||||
# The section title for the defaults changed in @1.10, see
|
# Tell numpy which BLAS/LAPACK libraries we want to use.
|
||||||
# https://github.com/numpy/numpy/blob/master/site.cfg.example
|
# https://github.com/numpy/numpy/pull/13132
|
||||||
if spec.satisfies('@:1.9.2'):
|
# https://numpy.org/devdocs/user/building.html#accelerated-blas-lapack-libraries
|
||||||
f.write('[DEFAULT]\n')
|
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:
|
else:
|
||||||
f.write('[ALL]\n')
|
blas = 'blas'
|
||||||
f.write('libraries=%s\n' % lapackblas_names)
|
|
||||||
write_library_dirs(f, lapackblas_dirs)
|
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):
|
def build_args(self, spec, prefix):
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
# From NumPy 1.10.0 on it's possible to do a parallel build.
|
# 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'):
|
if self.version >= Version('1.10.0'):
|
||||||
# But Parallel build in Python 3.5+ is broken. See:
|
# But Parallel build in Python 3.5+ is broken. See:
|
||||||
# https://github.com/spack/spack/issues/7927
|
# https://github.com/spack/spack/issues/7927
|
||||||
|
@ -201,20 +251,6 @@ def build_args(self, spec, prefix):
|
||||||
|
|
||||||
return args
|
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):
|
def test(self):
|
||||||
# `setup.py test` is not supported. Use one of the following
|
# `setup.py test` is not supported. Use one of the following
|
||||||
# instead:
|
# instead:
|
||||||
|
|
|
@ -33,6 +33,12 @@ def libs(self):
|
||||||
'libvecLibFort', root=self.prefix, shared=shared, recursive=True
|
'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):
|
def install(self, spec, prefix):
|
||||||
if sys.platform != 'darwin':
|
if sys.platform != 'darwin':
|
||||||
raise InstallError('vecLibFort can be installed on macOS only')
|
raise InstallError('vecLibFort can be installed on macOS only')
|
||||||
|
|
Loading…
Reference in a new issue