From f6e92e46105ff02c0ba28268b9f24f71fcc8b439 Mon Sep 17 00:00:00 2001
From: Eleni Mathioulaki <emathioulaki@athenarc.gr>
Date: Wed, 3 May 2023 14:24:10 +0000
Subject: [PATCH] relax numpy and scipy dep on setuptools (#31)

---
 packages/py-numpy/add_fj_compiler.patch    |  56 +++
 packages/py-numpy/add_fj_compiler2.patch   |  56 +++
 packages/py-numpy/add_fj_compiler3.patch   |  56 +++
 packages/py-numpy/add_fj_compiler4.patch   |  56 +++
 packages/py-numpy/blas-lapack-order.patch  | 347 +++++++++++++++++++
 packages/py-numpy/check_executables.patch  |  16 +
 packages/py-numpy/check_executables2.patch |  16 +
 packages/py-numpy/check_executables3.patch |  16 +
 packages/py-numpy/check_executables4.patch |  16 +
 packages/py-numpy/check_executables5.patch |  16 +
 packages/py-numpy/package.py               | 384 +++++++++++++++++++++
 packages/py-scipy/package.py               |   2 +-
 12 files changed, 1036 insertions(+), 1 deletion(-)
 create mode 100644 packages/py-numpy/add_fj_compiler.patch
 create mode 100644 packages/py-numpy/add_fj_compiler2.patch
 create mode 100644 packages/py-numpy/add_fj_compiler3.patch
 create mode 100644 packages/py-numpy/add_fj_compiler4.patch
 create mode 100644 packages/py-numpy/blas-lapack-order.patch
 create mode 100644 packages/py-numpy/check_executables.patch
 create mode 100644 packages/py-numpy/check_executables2.patch
 create mode 100644 packages/py-numpy/check_executables3.patch
 create mode 100644 packages/py-numpy/check_executables4.patch
 create mode 100644 packages/py-numpy/check_executables5.patch
 create mode 100644 packages/py-numpy/package.py

diff --git a/packages/py-numpy/add_fj_compiler.patch b/packages/py-numpy/add_fj_compiler.patch
new file mode 100644
index 00000000..50df9635
--- /dev/null
+++ b/packages/py-numpy/add_fj_compiler.patch
@@ -0,0 +1,56 @@
+diff -urN numpy-1.19.4.org/numpy/distutils/fcompiler/fujitsu.py numpy-1.19.4/numpy/distutils/fcompiler/fujitsu.py
+--- numpy-1.19.4.org/numpy/distutils/fcompiler/fujitsu.py	1970-01-01 09:00:00.000000000 +0900
++++ numpy-1.19.4/numpy/distutils/fcompiler/fujitsu.py	2020-11-10 17:21:43.324928283 +0900
+@@ -0,0 +1,40 @@
++from numpy.distutils.fcompiler import FCompiler
++
++compilers = ['FujitsuFCompiler']
++
++class FujitsuFCompiler(FCompiler):
++    compiler_type = 'fujitsu'
++    description = 'Fujitsu Fortran Compiler'
++
++    possible_executables = ['frt']
++    version_pattern = r'frt \(FRT\) (?P<version>[a-z\d.]+)'
++    # $ frt --version
++    # frt (FRT) x.x.x yyyymmdd
++
++    executables = {
++        'version_cmd'  : ["<F77>", "--version"],
++        'compiler_f77' : ["frt", "-Fixed"],
++        'compiler_fix' : ["frt", "-Fixed"],
++        'compiler_f90' : ["frt"],
++        'linker_so'    : ["frt", "-shared"],
++        'archiver'     : ["ar", "-cr"],
++        'ranlib'       : ["ranlib"]
++        }
++    pic_flags = ['-KPIC']
++    module_dir_switch = '-M'
++    module_include_switch = '-I'
++
++    def get_flags_opt(self):
++        return ['-O3']
++    def get_flags_debug(self):
++        return ['-g']
++    def runtime_library_dir_option(self, dir):
++        return f'-Wl,-rpath={dir}'
++    def get_libraries(self):
++        return ['fj90f', 'fj90i', 'fjsrcinfo']
++
++if __name__ == '__main__':
++    from distutils import log
++    from numpy.distutils import customized_fcompiler
++    log.set_verbosity(2)
++    print(customized_fcompiler('fujitsu').get_version())
+diff -urN numpy-1.19.4.org/numpy/distutils/fcompiler/__init__.py numpy-1.19.4/numpy/distutils/fcompiler/__init__.py
+--- numpy-1.19.4.org/numpy/distutils/fcompiler/__init__.py	2020-11-09 10:51:35.693490207 +0900
++++ numpy-1.19.4/numpy/distutils/fcompiler/__init__.py	2020-11-16 17:48:49.316744476 +0900
+@@ -746,7 +746,7 @@
+                'intelvem', 'intelem', 'flang')),
+     ('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')),
+     ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'nv', 'absoft', 'nag', 'vast', 'compaq',
+-                 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor')),
++                 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor', 'fujitsu')),
+     ('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')),
+     ('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')),
+     ('irix.*', ('mips', 'gnu', 'gnu95',)),
diff --git a/packages/py-numpy/add_fj_compiler2.patch b/packages/py-numpy/add_fj_compiler2.patch
new file mode 100644
index 00000000..4526ddea
--- /dev/null
+++ b/packages/py-numpy/add_fj_compiler2.patch
@@ -0,0 +1,56 @@
+diff -urN spack-src.org/numpy/distutils/fcompiler/fujitsu.py spack-src/numpy/distutils/fcompiler/fujitsu.py
+--- spack-src.org/numpy/distutils/fcompiler/fujitsu.py	1970-01-01 09:00:00.000000000 +0900
++++ spack-src/numpy/distutils/fcompiler/fujitsu.py	2020-11-16 17:55:57.608802456 +0900
+@@ -0,0 +1,40 @@
++from numpy.distutils.fcompiler import FCompiler
++
++compilers = ['FujitsuFCompiler']
++
++class FujitsuFCompiler(FCompiler):
++    compiler_type = 'fujitsu'
++    description = 'Fujitsu Fortran Compiler'
++
++    possible_executables = ['frt']
++    version_pattern = r'frt \(FRT\) (?P<version>[a-z\d.]+)'
++    # $ frt --version
++    # frt (FRT) x.x.x yyyymmdd
++
++    executables = {
++        'version_cmd'  : ["<F77>", "--version"],
++        'compiler_f77' : ["frt", "-Fixed"],
++        'compiler_fix' : ["frt", "-Fixed"],
++        'compiler_f90' : ["frt"],
++        'linker_so'    : ["frt", "-shared"],
++        'archiver'     : ["ar", "-cr"],
++        'ranlib'       : ["ranlib"]
++        }
++    pic_flags = ['-KPIC']
++    module_dir_switch = '-M'
++    module_include_switch = '-I'
++
++    def get_flags_opt(self):
++        return ['-O3']
++    def get_flags_debug(self):
++        return ['-g']
++    def runtime_library_dir_option(self, dir):
++        return f'-Wl,-rpath={dir}'
++    def get_libraries(self):
++        return ['fj90f', 'fj90i', 'fjsrcinfo']
++
++if __name__ == '__main__':
++    from distutils import log
++    from numpy.distutils import customized_fcompiler
++    log.set_verbosity(2)
++    print(customized_fcompiler('fujitsu').get_version())
+diff -urN spack-src.org/numpy/distutils/fcompiler/__init__.py spack-src/numpy/distutils/fcompiler/__init__.py
+--- spack-src.org/numpy/distutils/fcompiler/__init__.py	2020-11-16 17:55:31.638677631 +0900
++++ spack-src/numpy/distutils/fcompiler/__init__.py	2020-11-16 17:56:29.978957954 +0900
+@@ -746,7 +746,7 @@
+                'intelvem', 'intelem', 'flang')),
+     ('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')),
+     ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'absoft', 'nag', 'vast', 'compaq',
+-                 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor')),
++                 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor', 'fujitsu')),
+     ('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')),
+     ('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')),
+     ('irix.*', ('mips', 'gnu', 'gnu95',)),
diff --git a/packages/py-numpy/add_fj_compiler3.patch b/packages/py-numpy/add_fj_compiler3.patch
new file mode 100644
index 00000000..034cac06
--- /dev/null
+++ b/packages/py-numpy/add_fj_compiler3.patch
@@ -0,0 +1,56 @@
+diff -urN spack-src.org/numpy/distutils/fcompiler/fujitsu.py spack-src/numpy/distutils/fcompiler/fujitsu.py
+--- spack-src.org/numpy/distutils/fcompiler/fujitsu.py	1970-01-01 09:00:00.000000000 +0900
++++ spack-src/numpy/distutils/fcompiler/fujitsu.py	2020-11-16 18:30:06.698641953 +0900
+@@ -0,0 +1,40 @@
++from numpy.distutils.fcompiler import FCompiler
++
++compilers = ['FujitsuFCompiler']
++
++class FujitsuFCompiler(FCompiler):
++    compiler_type = 'fujitsu'
++    description = 'Fujitsu Fortran Compiler'
++
++    possible_executables = ['frt']
++    version_pattern = r'frt \(FRT\) (?P<version>[a-z\d.]+)'
++    # $ frt --version
++    # frt (FRT) x.x.x yyyymmdd
++
++    executables = {
++        'version_cmd'  : ["<F77>", "--version"],
++        'compiler_f77' : ["frt", "-Fixed"],
++        'compiler_fix' : ["frt", "-Fixed"],
++        'compiler_f90' : ["frt"],
++        'linker_so'    : ["frt", "-shared"],
++        'archiver'     : ["ar", "-cr"],
++        'ranlib'       : ["ranlib"]
++        }
++    pic_flags = ['-KPIC']
++    module_dir_switch = '-M'
++    module_include_switch = '-I'
++
++    def get_flags_opt(self):
++        return ['-O3']
++    def get_flags_debug(self):
++        return ['-g']
++    def runtime_library_dir_option(self, dir):
++        return '-Wl,-rpath=%s' %dir
++    def get_libraries(self):
++        return ['fj90f', 'fj90i', 'fjsrcinfo']
++
++if __name__ == '__main__':
++    from distutils import log
++    from numpy.distutils import customized_fcompiler
++    log.set_verbosity(2)
++    print(customized_fcompiler('fujitsu').get_version())
+diff -urN spack-src.org/numpy/distutils/fcompiler/__init__.py spack-src/numpy/distutils/fcompiler/__init__.py
+--- spack-src.org/numpy/distutils/fcompiler/__init__.py	2020-11-16 18:25:26.087294181 +0900
++++ spack-src/numpy/distutils/fcompiler/__init__.py	2020-11-16 18:26:19.987553070 +0900
+@@ -750,7 +750,7 @@
+                'intelvem', 'intelem', 'flang')),
+     ('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')),
+     ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'absoft', 'nag', 'vast', 'compaq',
+-                 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor')),
++                 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor', 'fujitsu')),
+     ('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')),
+     ('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')),
+     ('irix.*', ('mips', 'gnu', 'gnu95',)),
diff --git a/packages/py-numpy/add_fj_compiler4.patch b/packages/py-numpy/add_fj_compiler4.patch
new file mode 100644
index 00000000..83f2be5d
--- /dev/null
+++ b/packages/py-numpy/add_fj_compiler4.patch
@@ -0,0 +1,56 @@
+diff -urN spack-src.org/numpy/distutils/fcompiler/fujitsu.py spack-src/numpy/distutils/fcompiler/fujitsu.py
+--- spack-src.org/numpy/distutils/fcompiler/fujitsu.py	1970-01-01 09:00:00.000000000 +0900
++++ spack-src/numpy/distutils/fcompiler/fujitsu.py	2020-11-16 18:42:47.672297372 +0900
+@@ -0,0 +1,40 @@
++from numpy.distutils.fcompiler import FCompiler
++
++compilers = ['FujitsuFCompiler']
++
++class FujitsuFCompiler(FCompiler):
++    compiler_type = 'fujitsu'
++    description = 'Fujitsu Fortran Compiler'
++
++    possible_executables = ['frt']
++    version_pattern = r'frt \(FRT\) (?P<version>[a-z\d.]+)'
++    # $ frt --version
++    # frt (FRT) x.x.x yyyymmdd
++
++    executables = {
++        'version_cmd'  : ["<F77>", "--version"],
++        'compiler_f77' : ["frt", "-Fixed"],
++        'compiler_fix' : ["frt", "-Fixed"],
++        'compiler_f90' : ["frt"],
++        'linker_so'    : ["frt", "-shared"],
++        'archiver'     : ["ar", "-cr"],
++        'ranlib'       : ["ranlib"]
++        }
++    pic_flags = ['-KPIC']
++    module_dir_switch = '-M'
++    module_include_switch = '-I'
++
++    def get_flags_opt(self):
++        return ['-O3']
++    def get_flags_debug(self):
++        return ['-g']
++    def runtime_library_dir_option(self, dir):
++        return '-Wl,-rpath=%s' %dir
++    def get_libraries(self):
++        return ['fj90f', 'fj90i', 'fjsrcinfo']
++
++if __name__ == '__main__':
++    from distutils import log
++    from numpy.distutils import customized_fcompiler
++    log.set_verbosity(2)
++    print(customized_fcompiler('fujitsu').get_version())
+diff -urN spack-src.org/numpy/distutils/fcompiler/__init__.py spack-src/numpy/distutils/fcompiler/__init__.py
+--- spack-src.org/numpy/distutils/fcompiler/__init__.py	2020-11-16 18:43:18.112443626 +0900
++++ spack-src/numpy/distutils/fcompiler/__init__.py	2020-11-16 18:44:54.062904636 +0900
+@@ -709,7 +709,7 @@
+                'intelvem', 'intelem')),
+     ('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')),
+     ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'absoft', 'nag', 'vast', 'compaq',
+-                'intele', 'intelem', 'gnu', 'g95', 'pathf95')),
++                'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'fujitsu')),
+     ('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')),
+     ('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')),
+     ('irix.*', ('mips', 'gnu', 'gnu95',)),
diff --git a/packages/py-numpy/blas-lapack-order.patch b/packages/py-numpy/blas-lapack-order.patch
new file mode 100644
index 00000000..ac27d87d
--- /dev/null
+++ b/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/packages/py-numpy/check_executables.patch b/packages/py-numpy/check_executables.patch
new file mode 100644
index 00000000..ee4ac1b4
--- /dev/null
+++ b/packages/py-numpy/check_executables.patch
@@ -0,0 +1,16 @@
+--- numpy-1.20.0/numpy/distutils/fcompiler/__init__.py.org	2021-02-04 17:38:42.000000000 +0900
++++ numpy-1.20.0/numpy/distutils/fcompiler/__init__.py	2021-02-04 18:29:21.000000000 +0900
+@@ -314,7 +314,12 @@
+             if not exe_from_environ:
+                 possibles = [f90, f77] + self.possible_executables
+             else:
+-                possibles = [exe_from_environ] + self.possible_executables
++                matching_executables = []
++                for e in exe_from_environ:
++                    for p in self.possible_executables:
++                        if p in e:
++                            matching_executables.append(e)
++                possibles = [matching_executables] + self.possible_executables
+
+             seen = set()
+             unique_possibles = []
diff --git a/packages/py-numpy/check_executables2.patch b/packages/py-numpy/check_executables2.patch
new file mode 100644
index 00000000..0d0b78f6
--- /dev/null
+++ b/packages/py-numpy/check_executables2.patch
@@ -0,0 +1,16 @@
+--- spack-src/numpy/distutils/fcompiler/__init__.py.orig	2021-01-04 15:16:38.000000000 +0900
++++ spack-src/numpy/distutils/fcompiler/__init__.py	2021-02-12 17:20:07.327563118 +0900
+@@ -316,7 +316,12 @@
+             if not exe_from_environ:
+                 possibles = [f90, f77] + self.possible_executables
+             else:
+-                possibles = [exe_from_environ] + self.possible_executables
++                matching_executables = []
++                for e in exe_from_environ:
++                    for p in self.possible_executables:
++                        if p in e:
++                            matching_executables.append(e)
++                possibles = [matching_executables] + self.possible_executables
+ 
+             seen = set()
+             unique_possibles = []
diff --git a/packages/py-numpy/check_executables3.patch b/packages/py-numpy/check_executables3.patch
new file mode 100644
index 00000000..078211e3
--- /dev/null
+++ b/packages/py-numpy/check_executables3.patch
@@ -0,0 +1,16 @@
+--- spack-src/numpy/distutils/fcompiler/__init__.py.orig	2020-06-02 17:24:58.000000000 +0900
++++ spack-src/numpy/distutils/fcompiler/__init__.py	2021-02-12 17:33:11.483728471 +0900
+@@ -320,7 +320,12 @@
+             if not exe_from_environ:
+                 possibles = [f90, f77] + self.possible_executables
+             else:
+-                possibles = [exe_from_environ] + self.possible_executables
++                matching_executables = []
++                for e in exe_from_environ:
++                    for p in self.possible_executables:
++                        if p in e:
++                            matching_executables.append(e)
++                possibles = [matching_executables] + self.possible_executables
+ 
+             seen = set()
+             unique_possibles = []
diff --git a/packages/py-numpy/check_executables4.patch b/packages/py-numpy/check_executables4.patch
new file mode 100644
index 00000000..b553acb4
--- /dev/null
+++ b/packages/py-numpy/check_executables4.patch
@@ -0,0 +1,16 @@
+--- spack-src/numpy/distutils/fcompiler/__init__.py.orig	2018-11-03 10:49:58.000000000 +0900
++++ spack-src/numpy/distutils/fcompiler/__init__.py	2021-02-12 17:57:50.632263931 +0900
+@@ -318,7 +318,12 @@
+             if not exe_from_environ:
+                 possibles = [f90, f77] + self.possible_executables
+             else:
+-                possibles = [exe_from_environ] + self.possible_executables
++                matching_executables = []
++                for e in exe_from_environ:
++                    for p in self.possible_executables:
++                        if p in e:
++                            matching_executables.append(e)
++                possibles = [matching_executables] + self.possible_executables
+ 
+             seen = set()
+             unique_possibles = []
diff --git a/packages/py-numpy/check_executables5.patch b/packages/py-numpy/check_executables5.patch
new file mode 100644
index 00000000..4ae9fe40
--- /dev/null
+++ b/packages/py-numpy/check_executables5.patch
@@ -0,0 +1,16 @@
+--- spack-src/numpy/distutils/fcompiler/__init__.py.orig	2017-09-29 13:31:46.000000000 +0900
++++ spack-src/numpy/distutils/fcompiler/__init__.py	2021-02-12 18:06:12.001479417 +0900
+@@ -322,7 +322,12 @@
+             if not exe_from_environ:
+                 possibles = [f90, f77] + self.possible_executables
+             else:
+-                possibles = [exe_from_environ] + self.possible_executables
++                matching_executables = []
++                for e in exe_from_environ:
++                    for p in self.possible_executables:
++                        if p in e:
++                            matching_executables.append(e)
++                possibles = [matching_executables] + self.possible_executables
+ 
+             seen = set()
+             unique_possibles = []
diff --git a/packages/py-numpy/package.py b/packages/py-numpy/package.py
new file mode 100644
index 00000000..2cabb573
--- /dev/null
+++ b/packages/py-numpy/package.py
@@ -0,0 +1,384 @@
+# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import platform
+import subprocess
+
+from spack.package import *
+
+
+class PyNumpy(PythonPackage):
+    """NumPy is the fundamental package for scientific computing with Python.
+    It contains among other things: a powerful N-dimensional array object,
+    sophisticated (broadcasting) functions, tools for integrating C/C++ and
+    Fortran code, and useful linear algebra, Fourier transform, and random
+    number capabilities"""
+
+    homepage = "https://numpy.org/"
+    pypi = "numpy/numpy-1.23.0.tar.gz"
+    git = "https://github.com/numpy/numpy.git"
+
+    maintainers = ["adamjstewart", "rgommers"]
+
+    version("main", branch="main")
+    version("1.23.4", sha256="ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c")
+    version("1.23.3", sha256="51bf49c0cd1d52be0a240aa66f3458afc4b95d8993d2d04f0d91fa60c10af6cd")
+    version("1.23.2", sha256="b78d00e48261fbbd04aa0d7427cf78d18401ee0abd89c7559bbf422e5b1c7d01")
+    version("1.23.1", sha256="d748ef349bfef2e1194b59da37ed5a29c19ea8d7e6342019921ba2ba4fd8b624")
+    version("1.23.0", sha256="bd3fa4fe2e38533d5336e1272fc4e765cabbbde144309ccee8675509d5cd7b05")
+    version("1.22.4", sha256="425b390e4619f58d8526b3dcf656dde069133ae5c240229821f01b5f44ea07af")
+    version("1.22.3", sha256="dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18")
+    version("1.22.2", sha256="076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf")
+    version("1.22.1", sha256="e348ccf5bc5235fc405ab19d53bec215bb373300e5523c7b476cc0da8a5e9973")
+    version("1.22.0", sha256="a955e4128ac36797aaffd49ab44ec74a71c11d6938df83b1285492d277db5397")
+    version("1.21.6", sha256="ecb55251139706669fdec2ff073c98ef8e9a84473e51e716211b41aa0f18e656")
+    version("1.21.5", sha256="6a5928bc6241264dce5ed509e66f33676fc97f464e7a919edc672fb5532221ee")
+    version("1.21.4", sha256="e6c76a87633aa3fa16614b61ccedfae45b91df2767cf097aa9c933932a7ed1e0")
+    version("1.21.3", sha256="63571bb7897a584ca3249c86dd01c10bcb5fe4296e3568b2e9c1a55356b6410e")
+    version("1.21.2", sha256="423216d8afc5923b15df86037c6053bf030d15cc9e3224206ef868c2d63dd6dc")
+    version("1.21.1", sha256="dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd")
+    version("1.21.0", sha256="e80fe25cba41c124d04c662f33f6364909b985f2eb5998aaa5ae4b9587242cce")
+    version("1.20.3", sha256="e55185e51b18d788e49fe8305fd73ef4470596b33fc2c1ceb304566b99c71a69")
+    version("1.20.2", sha256="878922bf5ad7550aa044aa9301d417e2d3ae50f0f577de92051d739ac6096cee")
+    version("1.20.1", sha256="3bc63486a870294683980d76ec1e3efc786295ae00128f9ea38e2c6e74d5a60a")
+    version("1.20.0", sha256="3d8233c03f116d068d5365fed4477f2947c7229582dad81e5953088989294cec")
+    version("1.19.5", sha256="a76f502430dd98d7546e1ea2250a7360c065a5fdea52b2dffe8ae7180909b6f4")
+    version("1.19.4", sha256="141ec3a3300ab89c7f2b0775289954d193cc8edb621ea05f99db9cb181530512")
+    version("1.19.3", sha256="35bf5316af8dc7c7db1ad45bec603e5fb28671beb98ebd1d65e8059efcfd3b72")
+    version("1.19.2", sha256="0d310730e1e793527065ad7dde736197b705d0e4c9999775f212b03c44a8484c")
+    version("1.19.1", sha256="b8456987b637232602ceb4d663cb34106f7eb780e247d51a260b84760fd8f491")
+    version("1.19.0", sha256="76766cc80d6128750075378d3bb7812cf146415bd29b588616f72c943c00d598")
+    version("1.18.5", sha256="34e96e9dae65c4839bd80012023aadd6ee2ccb73ce7fdf3074c62f301e63120b")
+    version("1.18.4", sha256="bbcc85aaf4cd84ba057decaead058f43191cc0e30d6bc5d44fe336dc3d3f4509")
+    version("1.18.3", sha256="e46e2384209c91996d5ec16744234d1c906ab79a701ce1a26155c9ec890b8dc8")
+    version("1.18.2", sha256="e7894793e6e8540dbeac77c87b489e331947813511108ae097f1715c018b8f3d")
+    version("1.18.1", sha256="b6ff59cee96b454516e47e7721098e6ceebef435e3e21ac2d6c3b8b02628eb77")
+    version("1.18.0", sha256="a9d72d9abaf65628f0f31bbb573b7d9304e43b1e6bbae43149c17737a42764c4")
+    version("1.17.5", sha256="16507ba6617f62ae3c6ab1725ae6f550331025d4d9a369b83f6d5a470446c342")
+    version("1.17.4", sha256="f58913e9227400f1395c7b800503ebfdb0772f1c33ff8cb4d6451c06cabdf316")
+    version("1.17.3", sha256="a0678793096205a4d784bd99f32803ba8100f639cf3b932dc63b21621390ea7e")
+    version("1.17.2", sha256="73615d3edc84dd7c4aeb212fa3748fb83217e00d201875a47327f55363cef2df")
+    version("1.17.1", sha256="f11331530f0eff69a758d62c2461cd98cdc2eae0147279d8fc86e0464eb7e8ca")
+    version("1.17.0", sha256="951fefe2fb73f84c620bec4e001e80a80ddaa1b84dce244ded7f1e0cbe0ed34a")
+    version("1.16.6", sha256="e5cf3fdf13401885e8eea8170624ec96225e2174eb0c611c6f26dd33b489e3ff")
+    version("1.16.5", sha256="8bb452d94e964b312205b0de1238dd7209da452343653ab214b5d681780e7a0c")
+    version("1.16.4", sha256="7242be12a58fec245ee9734e625964b97cf7e3f2f7d016603f9e56660ce479c7")
+    version("1.16.3", sha256="78a6f89da87eeb48014ec652a65c4ffde370c036d780a995edaeb121d3625621")
+    version("1.16.2", sha256="6c692e3879dde0b67a9dc78f9bfb6f61c666b4562fd8619632d7043fb5b691b0")
+    version("1.16.1", sha256="31d3fe5b673e99d33d70cfee2ea8fe8dccd60f265c3ed990873a88647e3dd288")
+    version("1.16.0", sha256="cb189bd98b2e7ac02df389b6212846ab20661f4bafe16b5a70a6f1728c1cc7cb")
+    version("1.15.4", sha256="3d734559db35aa3697dadcea492a423118c5c55d176da2f3be9c98d4803fc2a7")
+    version("1.15.3", sha256="1c0c80e74759fa4942298044274f2c11b08c86230b25b8b819e55e644f5ff2b6")
+    version("1.15.2", sha256="27a0d018f608a3fe34ac5e2b876f4c23c47e38295c47dd0775cc294cd2614bc1")
+    version("1.15.2", sha256="27a0d018f608a3fe34ac5e2b876f4c23c47e38295c47dd0775cc294cd2614bc1")
+    version("1.15.1", sha256="7b9e37f194f8bcdca8e9e6af92e2cbad79e360542effc2dd6b98d63955d8d8a3")
+    version("1.15.0", sha256="f28e73cf18d37a413f7d5de35d024e6b98f14566a10d82100f9dc491a7d449f9")
+    version("1.14.6", sha256="1250edf6f6c43e1d7823f0967416bc18258bb271dc536298eb0ea00a9e45b80a")
+    version("1.14.5", sha256="a4a433b3a264dbc9aa9c7c241e87c0358a503ea6394f8737df1683c7c9a102ac")
+    version("1.14.4", sha256="2185a0f31ecaa0792264fa968c8e0ba6d96acf144b26e2e1d1cd5b77fc11a691")
+    version("1.14.3", sha256="9016692c7d390f9d378fc88b7a799dc9caa7eb938163dda5276d3f3d6f75debf")
+    version("1.14.2", sha256="facc6f925c3099ac01a1f03758100772560a0b020fb9d70f210404be08006bcb")
+    version("1.14.1", sha256="fa0944650d5d3fb95869eaacd8eedbd2d83610c85e271bd9d3495ffa9bc4dc9c")
+    version("1.14.0", sha256="3de643935b212307b420248018323a44ec51987a336d1d747c1322afc3c099fb")
+    version("1.13.3", sha256="36ee86d5adbabc4fa2643a073f93d5504bdfed37a149a3a49f4dde259f35a750")
+    version("1.13.1", sha256="c9b0283776085cb2804efff73e9955ca279ba4edafd58d3ead70b61d209c4fbb")
+    version("1.13.0", sha256="dcff367b725586830ff0e20b805c7654c876c2d4585c0834a6049502b9d6cf7e")
+    version("1.12.1", sha256="a65266a4ad6ec8936a1bc85ce51f8600634a31a258b722c9274a80ff189d9542")
+    version("1.12.0", sha256="ff320ecfe41c6581c8981dce892fe6d7e69806459a899e294e4bf8229737b154")
+    version("1.11.3", sha256="2e0fc5248246a64628656fe14fcab0a959741a2820e003bd15538226501b82f7")
+    version("1.11.2", sha256="c1ed4d1d2a795409c7df1eb4bfee65c0e3326cfc7c57875fa39e5c7414116d9a")
+    version("1.11.1", sha256="4e9c289b9d764d10353a224a5286dda3e0425b13b112719bdc3e9864ae648d79")
+    version("1.11.0", sha256="9109f260850627e4b83a3c4bcef4f2f99357eb4a5eaae75dec51c32f3c197aa3")
+    version("1.10.4", sha256="8ce443dc79656a9fc97a7837f1444d324aef2c9b53f31f83441f57ad1f1f3659")
+    version("1.9.3", sha256="baa074bb1c7f9c822122fb81459b7caa5fc49267ca94cca69465c8dcfd63ac79")
+    version("1.9.2", sha256="e37805754f4ebb575c434d134f6bebb8b857d9843c393f6943c7be71ef57311c")
+    version("1.9.1", sha256="2a545c0d096d86035b12160fcba5e4c0a08dcabbf902b4f867eb64deb31a2b7a")
+
+    variant("blas", default=True, description="Build with BLAS support")
+    variant("lapack", default=True, description="Build with LAPACK support")
+
+    depends_on("python@2.7:2.8,3.4:3.6", type=("build", "link", "run"), when="@:1.13")
+    depends_on("python@2.7:2.8,3.4:3.8", type=("build", "link", "run"), when="@1.14:1.15")
+    depends_on("python@2.7:2.8,3.5:3.9", type=("build", "link", "run"), when="@1.16")
+    depends_on("python@3.5:3.9", type=("build", "link", "run"), when="@1.17:1.18")
+    depends_on("python@3.6:3.10", type=("build", "link", "run"), when="@1.19")
+    depends_on("python@3.7:3.10", type=("build", "link", "run"), when="@1.20:1.21")
+    depends_on("python@3.8:", type=("build", "link", "run"), when="@1.22:")
+    # https://github.com/spack/spack/pull/32078
+    # https://github.com/spack/spack/pull/34475#discussion_r1046146311
+    depends_on("py-setuptools@:63", type=("build", "run"))
+    depends_on("py-setuptools@:59", when="@:1.22.1", type=("build", "run"))
+    # Check pyproject.toml for updates to the required cython version
+    depends_on("py-cython@0.29.13:2", when="@1.18.0:", type="build")
+    depends_on("py-cython@0.29.14:2", when="@1.18.1:", type="build")
+    depends_on("py-cython@0.29.21:2", when="@1.19.1:", type="build")
+    depends_on("py-cython@0.29.24:2", when="@1.21.2:", type="build")
+    depends_on("py-cython@0.29.30:2", when="@1.22.4:", type="build")
+    depends_on("blas", when="+blas")
+    depends_on("lapack", when="+lapack")
+
+    depends_on("py-nose@1.0.0:", when="@:1.14", type="test")
+    depends_on("py-pytest", when="@1.15:", type="test")
+    depends_on("py-hypothesis", when="@1.19:", type="test")
+    depends_on("py-typing-extensions@4.2:", when="@1.23:", type="test")
+
+    # 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")
+
+    # Add Fujitsu Fortran compiler
+    patch("add_fj_compiler.patch", when="@1.19.3:1.19.5%fj")
+    patch("add_fj_compiler2.patch", when="@1.19.0:1.19.2%fj")
+    patch("add_fj_compiler3.patch", when="@1.14.0:1.18.5%fj")
+    patch("add_fj_compiler4.patch", when="@:1.13.3%fj")
+
+    patch("check_executables.patch", when="@1.20.0:")
+    patch("check_executables2.patch", when="@1.19.0:1.19.5")
+    patch("check_executables3.patch", when="@1.16.0:1.18.5")
+    patch("check_executables4.patch", when="@1.14.0:1.15.4")
+    patch("check_executables5.patch", when="@:1.13.3")
+
+    # Backport bug fix for f2py's define for threading when building with Mingw
+    patch(
+        "https://github.com/numpy/numpy/pull/20881.patch?full_index=1",
+        sha256="802970a9034d40a8a8f49a03f489d5361d5eabf69249621e6757651448910f1a",
+        when="@1.20.3:1.22.1",
+    )
+    # Patch to update compiler flags.
+    # See https://github.com/spack/spack/issues/30373
+    patch(
+        "https://github.com/numpy/numpy/pull/21448.patch?full_index=1",
+        sha256="e9508c3b3a1e1a24669014a0c1b9f3b009a149ea3886cf711eaef2a32b247fdb",
+        when="@1.22.0:1.22.3",
+    )
+
+    # version 1.21.0 runs into an infinit loop during printing
+    # (e.g. print(numpy.ones(1000)) when compiled with gcc 11
+    conflicts("%gcc@11:", when="@1.21.0")
+
+    # GCC 4.8 is the minimum version that works
+    conflicts("%gcc@:4.7", msg="GCC 4.8+ required")
+
+    # NVHPC support added in https://github.com/numpy/numpy/pull/17344
+    conflicts("%nvhpc", when="@:1.19")
+
+    # Newer versions will not build with Intel https://github.com/numpy/numpy/issues/22011
+    conflicts("%intel", when="@1.23.0:")
+    conflicts("%oneapi", when="@1.23.0:")
+
+    def url_for_version(self, version):
+        url = "https://files.pythonhosted.org/packages/source/n/numpy/numpy-{}.{}"
+        if version >= Version("1.23"):
+            ext = "tar.gz"
+        else:
+            ext = "zip"
+        return url.format(version, ext)
+
+    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)
+        # Check gcc version in use by intel compiler
+        # This will essentially check the system gcc compiler unless a gcc
+        # module is already loaded.
+        if self.spec.satisfies("%intel") and name == "cflags":
+            p1 = subprocess.Popen([self.compiler.cc, "-v"], stderr=subprocess.PIPE)
+            p2 = subprocess.Popen(
+                ["grep", "compatibility"], stdin=p1.stderr, stdout=subprocess.PIPE
+            )
+            p1.stderr.close()
+            out, err = p2.communicate()
+            gcc_version = Version(out.split()[5].decode("utf-8"))
+            if gcc_version < Version("4.8"):
+                raise InstallError(
+                    "The GCC version that the Intel compiler "
+                    "uses must be >= 4.8. The GCC in use is "
+                    "{0}".format(gcc_version)
+                )
+            if gcc_version <= Version("5.1"):
+                flags.append(self.compiler.c99_flag)
+
+        return (flags, None, None)
+
+    @run_before("install")
+    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 = {0}\n".format(dirs))
+            if not (
+                (platform.system() == "Darwin")
+                and (Version(platform.mac_ver()[0]).up_to(2) == Version("10.12"))
+            ):
+                f.write("rpath = {0}\n".format(dirs))
+
+        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_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
+                or "^intel-oneapi-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 or "^amdblis" 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 or "^amdlibflame" 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 or "^cray-libsci" in spec:
+                # netlib and Cray require 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 "^fujitsu-ssl2" in spec:
+                if spec.satisfies("+blas"):
+                    f.write("[blas]\n")
+                    f.write("libraries = {0}\n".format(spec["blas"].libs.names[0]))
+                    write_library_dirs(f, blas_lib_dirs)
+                    f.write("include_dirs = {0}\n".format(blas_header_dirs))
+                    f.write("extra_link_args = {0}\n".format(self.spec["blas"].libs.ld_flags))
+                if spec.satisfies("+lapack"):
+                    f.write("[lapack]\n")
+                    f.write("libraries = {0}\n".format(spec["lapack"].libs.names[0]))
+                    write_library_dirs(f, lapack_lib_dirs)
+                    f.write("include_dirs = {0}\n".format(lapack_header_dirs))
+                    f.write("extra_link_args = {0}\n".format(self.spec["lapack"].libs.ld_flags))
+
+    def setup_build_environment(self, 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" not in spec:
+            blas = ""
+        elif (
+            spec["blas"].name == "intel-mkl"
+            or spec["blas"].name == "intel-parallel-studio"
+            or spec["blas"].name == "intel-oneapi-mkl"
+        ):
+            blas = "mkl"
+        elif spec["blas"].name == "blis" or spec["blas"].name == "amdblis":
+            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"
+
+        env.set("NPY_BLAS_ORDER", blas)
+
+        # https://numpy.org/devdocs/user/building.html#lapack
+        if "lapack" not in spec:
+            lapack = ""
+        elif (
+            spec["lapack"].name == "intel-mkl"
+            or spec["lapack"].name == "intel-parallel-studio"
+            or spec["lapack"].name == "intel-oneapi-mkl"
+        ):
+            lapack = "mkl"
+        elif spec["lapack"].name == "openblas":
+            lapack = "openblas"
+        elif spec["lapack"].name == "libflame" or spec["lapack"].name == "amdlibflame":
+            lapack = "flame"
+        elif spec["lapack"].name == "atlas":
+            lapack = "atlas"
+        elif spec["lapack"].name == "veclibfort":
+            lapack = "accelerate"
+        else:
+            lapack = "lapack"
+
+        env.set("NPY_LAPACK_ORDER", lapack)
+
+    @run_after("install")
+    @on_package_attributes(run_tests=True)
+    def install_test(self):
+        with working_dir("spack-test", create=True):
+            python("-c", 'import numpy; numpy.test("full", verbose=2)')
diff --git a/packages/py-scipy/package.py b/packages/py-scipy/package.py
index d689b89b..d47a3896 100644
--- a/packages/py-scipy/package.py
+++ b/packages/py-scipy/package.py
@@ -62,7 +62,7 @@ class PyScipy(PythonPackage):
     depends_on("py-setuptools", type="build")
     depends_on("py-setuptools@:51.0.0", when="@1.6", type="build")
     depends_on("py-setuptools@:57", when="@1.7", type="build")
-    depends_on("py-setuptools@:59", when="@1.8:", type="build")
+    depends_on("py-setuptools@:63", when="@1.8:", type="build")
     depends_on("py-cython@0.29.18:2", when="@1.7:", type="build")
     depends_on("py-pybind11@2.2.4:", when="@1.4.0", type=("build", "link"))
     depends_on("py-pybind11@2.4.0:", when="@1.4.1:1.4", type=("build", "link"))
-- 
GitLab