summaryrefslogtreecommitdiff
path: root/var
diff options
context:
space:
mode:
authorAdam J. Stewart <ajstewart426@gmail.com>2019-08-06 18:20:23 -0500
committerGitHub <noreply@github.com>2019-08-06 18:20:23 -0500
commit66e9b1279a306e872008f41624bd12246484c42d (patch)
tree5def4565ffbd5e6c425636eb930879d435845fee /var
parent15884a679b07e1d9a1f4a600862bc05707d0c9b3 (diff)
downloadspack-66e9b1279a306e872008f41624bd12246484c42d.tar.gz
spack-66e9b1279a306e872008f41624bd12246484c42d.tar.bz2
spack-66e9b1279a306e872008f41624bd12246484c42d.tar.xz
spack-66e9b1279a306e872008f41624bd12246484c42d.zip
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
Diffstat (limited to 'var')
-rw-r--r--var/spack/repos/builtin/packages/atlas/package.py31
-rw-r--r--var/spack/repos/builtin/packages/libflame/package.py9
-rw-r--r--var/spack/repos/builtin/packages/py-meep/package.py5
-rw-r--r--var/spack/repos/builtin/packages/py-numpy/blas-lapack-order.patch347
-rw-r--r--var/spack/repos/builtin/packages/py-numpy/package.py280
-rw-r--r--var/spack/repos/builtin/packages/veclibfort/package.py6
6 files changed, 544 insertions, 134 deletions
diff --git a/var/spack/repos/builtin/packages/atlas/package.py b/var/spack/repos/builtin/packages/atlas/package.py
index ee9d8ae3f9..5e69b8f9a8 100644
--- a/var/spack/repos/builtin/packages/atlas/package.py
+++ b/var/spack/repos/builtin/packages/atlas/package.py
@@ -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 @@ class Atlas(Package):
'-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' %
diff --git a/var/spack/repos/builtin/packages/libflame/package.py b/var/spack/repos/builtin/packages/libflame/package.py
index d3b547e5c5..bad6b0a223 100644
--- a/var/spack/repos/builtin/packages/libflame/package.py
+++ b/var/spack/repos/builtin/packages/libflame/package.py
@@ -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 @@ class Libflame(AutotoolsPackage):
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
diff --git a/var/spack/repos/builtin/packages/py-meep/package.py b/var/spack/repos/builtin/packages/py-meep/package.py
index 764f46e7b9..b7dea8b798 100644
--- a/var/spack/repos/builtin/packages/py-meep/package.py
+++ b/var/spack/repos/builtin/packages/py-meep/package.py
@@ -38,7 +38,10 @@ class PyMeep(PythonPackage):
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 = [
diff --git a/var/spack/repos/builtin/packages/py-numpy/blas-lapack-order.patch b/var/spack/repos/builtin/packages/py-numpy/blas-lapack-order.patch
new file mode 100644
index 0000000000..ac27d87dcd
--- /dev/null
+++ b/var/spack/repos/builtin/packages/py-numpy/blas-lapack-order.patch
@@ -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):
diff --git a/var/spack/repos/builtin/packages/py-numpy/package.py b/var/spack/repos/builtin/packages/py-numpy/package.py
index dd3f2507e3..9e5a4d160a 100644
--- a/var/spack/repos/builtin/packages/py-numpy/package.py
+++ b/var/spack/repos/builtin/packages/py-numpy/package.py
@@ -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)
+ 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 = []
+ blas_libs = LibraryList([])
+ blas_headers = HeaderList([])
+ if '+blas' in spec:
+ blas_libs = spec['blas'].libs
+ blas_headers = spec['blas'].headers
+ lapack_libs = LibraryList([])
+ lapack_headers = HeaderList([])
if '+lapack' in spec:
- lapack_info += spec['lapack'].libs
+ lapack_libs = spec['lapack'].libs
+ lapack_headers = spec['lapack'].headers
+
+ lapackblas_libs = lapack_libs + blas_libs
+ lapackblas_headers = lapack_headers + blas_headers
+
+ blas_lib_names = ','.join(blas_libs.names)
+ blas_lib_dirs = ':'.join(blas_libs.directories)
+ 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:
+ 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 '^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 '^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 '^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))
- if '+blas' in spec:
- blas_info += spec['blas'].libs
-
- lapackblas_info = lapack_info + blas_info
-
- def write_empty_libs(f, provider):
- f.write('[{0}]\n'.format(provider))
- f.write('libraries=\n')
- write_library_dirs(f, '')
-
- 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)
-
- handled_blas_and_lapack = False
-
- # 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')
-
- 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')
-
- 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 '^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 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)
+ 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 @@ class PyNumpy(PythonPackage):
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:
diff --git a/var/spack/repos/builtin/packages/veclibfort/package.py b/var/spack/repos/builtin/packages/veclibfort/package.py
index c1295dcf24..ad05471dae 100644
--- a/var/spack/repos/builtin/packages/veclibfort/package.py
+++ b/var/spack/repos/builtin/packages/veclibfort/package.py
@@ -33,6 +33,12 @@ class Veclibfort(Package):
'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')