diff --git a/.github/workflows/linux_blas.yml b/.github/workflows/linux_blas.yml index 17ff957bd2db..b90e32d00b32 100644 --- a/.github/workflows/linux_blas.yml +++ b/.github/workflows/linux_blas.yml @@ -10,9 +10,27 @@ name: BLAS tests (Linux) # - openblas32_stable_nightly: # Uses the 32-bit OpenBLAS builds, both the latest stable release # and a nightly build. -# -# TODO: coverage here is limited, we should add non-OpenBLAS libraries and -# exercise the BLAS-related build options (see `meson_options.txt`). +# - openblas_no_pkgconfig_fedora: +# Test OpenBLAS on Fedora. Fedora doesn't ship .pc files for OpenBLAS, +# hence this exercises the "system dependency" detection method. +# - flexiblas_fedora: +# Tests FlexiBLAS (the default on Fedora for its own packages), via +# pkg-config. FlexiBLAS allows runtime switching of BLAS/LAPACK +# libraries, which is a useful capability (not tested in this job). +# - openblas_cmake: +# Tests whether OpenBLAS LP64 is detected correctly when only CMake +# and not pkg-config is installed. +# - netlib: +# Installs vanilla blas/lapack, which is the last option tried in +# auto-detection. +# - mkl: +# Tests MKL installed from PyPI (because easiest/fastest, if broken) in +# 3 ways: both LP64 and ILP64 via pkg-config, and then using the +# Single Dynamic Library (SDL, or `libmkl_rt`). +# - blis: +# Simple test for LP64 via pkg-config +# - atlas: +# Simple test for LP64 via pkg-config on: pull_request: @@ -87,3 +105,253 @@ jobs: run: | pip install pytest pytest-xdist hypothesis typing_extensions spin test -j auto + + + openblas_no_pkgconfig_fedora: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + container: fedora:39 + name: "OpenBLAS (Fedora, no pkg-config, LP64/ILP64)" + steps: + - name: Install system dependencies + run: | + dnf install git gcc-gfortran g++ python3-devel openblas-devel -y + + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest hypothesis typing_extensions + + - name: Build (LP64) + run: spin build -- -Dblas=openblas -Dlapack=openblas -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build (ILP64) + run: | + rm -rf build + spin build -- -Duse-ilp64=true -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + + flexiblas_fedora: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + container: fedora:39 + name: "FlexiBLAS (LP64, ILP64 on Fedora)" + steps: + - name: Install system dependencies + run: | + dnf install git gcc-gfortran g++ python3-devel flexiblas-devel -y + + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest hypothesis typing_extensions + + - name: Build + run: spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build (ILP64) + run: | + rm -rf build + spin build -- -Ddisable-optimization=true -Duse-ilp64=true + + - name: Test (ILP64) + run: spin test -- numpy/linalg + + + openblas_cmake: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "OpenBLAS with CMake" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + sudo apt-get install libopenblas-dev cmake + sudo apt-get remove pkg-config + + - name: Build + run: spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -j auto -- numpy/linalg + + + netlib: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "Netlib BLAS/LAPACK" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + sudo apt-get install liblapack-dev pkg-config + + - name: Build + run: | + spin build -- -Ddisable-optimization=true + + - name: Test + run: | + pip install pytest pytest-xdist hypothesis typing_extensions + spin test -j auto -- numpy/linalg + + + mkl: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "MKL (LP64, ILP64, SDL)" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + pip install mkl mkl-devel + + - name: Repair MKL pkg-config files and symlinks + run: | + # MKL 2023.2 works when installed from conda-forge (except for `-iomp` + # and `-tbb` pkg-config files), Spack, or with the standalone Intel + # installer. The standalone installer is the worst option, since it's + # large and clumsy to install and requires running a setvars.sh script + # before things work. The PyPI MKL packages are broken and need the + # fixes in this step. For details, see + # https://github.com/conda-forge/intel_repack-feedstock/issues/34 + cd $Python3_ROOT_DIR/lib/pkgconfig + sed -i 's/\/intel64//g' mkl*.pc + # add the expected .so -> .so.2 symlinks to fix linking + cd .. + for i in $( ls libmkl*.so.2 ); do ln -s $i ${i%.*}; done + + - name: Build with defaults (LP64) + run: | + pkg-config --libs mkl-dynamic-lp64-seq # check link flags + spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build with ILP64 + run: | + git clean -xdf > /dev/null + pkg-config --libs mkl-dynamic-ilp64-seq + spin build -- -Duse-ilp64=true -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + - name: Build without pkg-config (default options, SDL) + run: | + git clean -xdf > /dev/null + pushd $Python3_ROOT_DIR/lib/pkgconfig + rm mkl*.pc + popd + export MKLROOT=$Python3_ROOT_DIR + spin build -- -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + blis: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "BLIS" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + sudo apt-get install libblis-dev libopenblas-dev pkg-config + + - name: Add BLIS pkg-config file + run: | + # Needed because blis.pc missing in Debian: + # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989076 + # The alternative here would be to use another distro or Miniforge + sudo cp tools/ci/_blis_debian.pc /usr/lib/x86_64-linux-gnu/pkgconfig/blis.pc + # Check if the patch works: + pkg-config --libs blis + pkg-config --cflags blis + + - name: Build + run: spin build -- -Dblas=blis -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + + atlas: + if: "github.repository == 'numpy/numpy'" + runs-on: ubuntu-latest + name: "ATLAS" + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r build_requirements.txt + pip install pytest pytest-xdist hypothesis typing_extensions + sudo apt-get install libatlas-base-dev pkg-config + + - name: Build + run: spin build -- -Dblas=blas-atlas -Dlapack=lapack-atlas -Ddisable-optimization=true + + - name: Test + run: spin test -- numpy/linalg + diff --git a/.github/workflows/linux_musl.yml b/.github/workflows/linux_musl.yml index 5f6da2ba765d..5c65a2b2e8b9 100644 --- a/.github/workflows/linux_musl.yml +++ b/.github/workflows/linux_musl.yml @@ -60,7 +60,7 @@ jobs: pip install -r build_requirements.txt -r test_requirements.txt # use meson to build and test - spin build --with-scipy-openblas=64 + spin build --with-scipy-openblas=64 -- -Duse-ilp64=true spin test -j auto - name: Meson Log diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 0a7aa38c0ae7..8768b64e17cd 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -100,7 +100,7 @@ jobs: ccache -s accelerate: - name: Accelerate ILP64 + name: Accelerate (LP64, ILP64) if: "github.repository == 'numpy/numpy'" runs-on: macos-13 steps: @@ -122,14 +122,15 @@ jobs: pip install -r build_requirements.txt pip install pytest pytest-xdist hypothesis - - name: Build NumPy against Accelerate (ILP64) - run: | - spin build -- -Dblas=accelerate -Dlapack=accelerate -Duse-ilp64=true + - name: Build against Accelerate (LP64) + run: spin build -- -Ddisable-optimization=true - - name: Show meson-log.txt - if: always() - run: 'cat build/meson-logs/meson-log.txt' + - name: Test (linalg only) + run: spin test -j2 -- numpy/linalg - - name: Test + - name: Build NumPy against Accelerate (ILP64) run: | - spin test -j2 + spin build -- -Duse-ilp64=true + + - name: Test (fast tests) + run: spin test -j2 diff --git a/azure-steps-windows.yml b/azure-steps-windows.yml index ce11d06f5148..2c12287bbcfb 100644 --- a/azure-steps-windows.yml +++ b/azure-steps-windows.yml @@ -31,7 +31,7 @@ steps: } elseif ( Test-Path env:NPY_USE_BLAS_ILP64 ) { python -m pip install scipy-openblas64 spin - spin config-openblas --with-scipy-openblas=64 + spin config-openblas --with-scipy-openblas=64 -- -Duse-ilp64=true $env:PKG_CONFIG_PATH="$pwd/.openblas" python -m pip install . -v -Csetup-args="--vsenv" } else { diff --git a/meson.build b/meson.build index 9ba86f393d6d..264160d132eb 100644 --- a/meson.build +++ b/meson.build @@ -12,8 +12,6 @@ project( 'b_ndebug=if-release', 'c_std=c99', 'cpp_std=c++17', - 'blas=openblas', - 'lapack=openblas', 'pkgconfig.relocatable=true', ], ) diff --git a/meson_options.txt b/meson_options.txt index b126e22d1f63..588d0e404d22 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,13 +1,19 @@ -option('blas', type: 'string', value: 'openblas', - description: 'Option for BLAS library switching') -option('lapack', type: 'string', value: 'openblas', - description: 'Option for LAPACK library switching') +option('blas', type: 'string', value: 'auto', + description: 'Option for BLAS library selection. By default, try to find any in the order given by `blas-order`') +option('lapack', type: 'string', value: 'auto', + description: 'Option for LAPACK library selection. By default, try to find any in the order given by `lapack-order`') option('allow-noblas', type: 'boolean', value: false, description: 'If set to true, allow building with (slow!) internal fallback routines') +option('blas-order', type: 'array', + value: ['mkl', 'accelerate', 'openblas', 'flexiblas', 'blis', 'blas']) +option('lapack-order', type: 'array', + value: ['mkl', 'accelerate', 'openblas', 'flexiblas', 'lapack']) option('use-ilp64', type: 'boolean', value: false, description: 'Use ILP64 (64-bit integer) BLAS and LAPACK interfaces') -option('blas-symbol-suffix', type: 'string', value: '', - description: 'BLAS and LAPACK symbol suffix to use, if any (often `64_` for ILP64)') +option('blas-symbol-suffix', type: 'string', value: 'auto', + description: 'BLAS and LAPACK symbol suffix to use, if any') +option('mkl-threading', type: 'string', value: 'auto', + description: 'MKL threading method, one of: `seq`, `iomp`, `gomp`, `tbb`') option('disable-svml', type: 'boolean', value: false, description: 'Disable building against SVML') option('disable-threading', type: 'boolean', value: false, diff --git a/numpy/core/src/common/npy_cblas.h b/numpy/core/src/common/npy_cblas.h index dad9599f605e..596a7c68cedd 100644 --- a/numpy/core/src/common/npy_cblas.h +++ b/numpy/core/src/common/npy_cblas.h @@ -57,8 +57,21 @@ enum CBLAS_SIDE {CblasLeft=141, CblasRight=142}; #define BLAS_FUNC_CONCAT(name,prefix,suffix,suffix2) prefix ## name ## suffix ## suffix2 #define BLAS_FUNC_EXPAND(name,prefix,suffix,suffix2) BLAS_FUNC_CONCAT(name,prefix,suffix,suffix2) -#define CBLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,,BLAS_SYMBOL_SUFFIX) +/* + * Use either the OpenBLAS scheme with the `64_` suffix behind the Fortran + * compiler symbol mangling, or the MKL scheme (and upcoming + * reference-lapack#666) which does it the other way around and uses `_64`. + */ +#ifdef OPENBLAS_ILP64_NAMING_SCHEME #define BLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,BLAS_FORTRAN_SUFFIX,BLAS_SYMBOL_SUFFIX) +#else +#define BLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,BLAS_SYMBOL_SUFFIX,BLAS_FORTRAN_SUFFIX) +#endif +/* + * Note that CBLAS doesn't include Fortran compiler symbol mangling, so ends up + * being the same in both schemes + */ +#define CBLAS_FUNC(name) BLAS_FUNC_EXPAND(name,BLAS_SYMBOL_PREFIX,,BLAS_SYMBOL_SUFFIX) #ifdef HAVE_BLAS_ILP64 #define CBLAS_INT npy_int64 diff --git a/numpy/meson.build b/numpy/meson.build index 98f40248de51..75d513d176e1 100644 --- a/numpy/meson.build +++ b/numpy/meson.build @@ -48,23 +48,18 @@ else ] endif -macOS13_3_or_later = false -if host_machine.system() == 'darwin' - r = run_command('xcrun', '-sdk', 'macosx', '--show-sdk-version', check: true) - sdkVersion = r.stdout().strip() - - macOS13_3_or_later = sdkVersion.version_compare('>=13.3') -endif - +blas_name = get_option('blas') +lapack_name = get_option('lapack') +allow_noblas = get_option('allow-noblas') # This is currently injected directly into CFLAGS/CXXFLAGS for wheel builds # (see cibuildwheel settings in pyproject.toml), but used by CI jobs already blas_symbol_suffix = get_option('blas-symbol-suffix') use_ilp64 = get_option('use-ilp64') if not use_ilp64 + # TODO: clean this up # For now, keep supporting the `NPY_USE_BLAS_ILP64` environment variable too - # (same as in setup.py) `false is the default for the CLI flag, so check if - # env var was set + # `false` is the default for the CLI flag, so check if env var was set use_ilp64 = run_command(py, [ '-c', @@ -74,138 +69,97 @@ if not use_ilp64 ).stdout().strip() == '1' endif +if use_ilp64 + blas_interface = ['interface: ilp64'] +else + blas_interface = ['interface: lp64'] +endif -# TODO: 64-bit (ILP64) BLAS and LAPACK support (e.g., check for more .pc files -# so we detect `openblas64_.so` directly). Partially supported now, needs more -# auto-detection. -# -# Note that this works as long as BLAS and LAPACK are detected properly via -# pkg-config. By default we look for OpenBLAS, other libraries can be configured via -# `meson configure -Dblas=blas -Dlapack=lapack` (example to build with Netlib -# BLAS and LAPACK). -# For MKL and for auto-detecting one of multiple libs, we'll need a custom -# dependency in Meson (like is done for scalapack) - see -# https://github.com/mesonbuild/meson/issues/2835 -blas_name = get_option('blas') -lapack_name = get_option('lapack') +# MKL-specific options +_threading_opt = get_option('mkl-threading') +if _threading_opt == 'auto' + # Switch default to iomp once conda-forge missing openmp.pc issue is fixed + mkl_opts = ['threading: seq'] +else + mkl_opts = ['threading: ' + _threading_opt] +endif +blas_opts = {'mkl': mkl_opts} +mkl_version_req = '>=2023.0' # see gh-24824 +mkl_may_use_sdl = not use_ilp64 and _threading_opt in ['auto', 'iomp'] + +# Note that we can only use a BLAS which provides a CBLAS interface. So disable +# BLAS completely if CBLAS is not found. -# pkg-config uses a lower-case name while CMake uses a capitalized name, so try -# that too to make the fallback detection with CMake work -if blas_name == 'openblas' - # first try scipy-openblas, and if found don't look for cblas or lapack +# First try scipy-openblas, and if found don't look for cblas or lapack, we +# know what's inside the scipy-openblas wheels already. +if blas_name == 'openblas' or blas_name == 'auto' blas = dependency('scipy-openblas', required: false) if blas.found() blas_name = 'scipy-openblas' - else - if use_ilp64 - _openblas_names = ['openblas64', 'openblas', 'OpenBLAS'] + endif +endif +if blas_name == 'auto' + foreach _name : get_option('blas-order') + if _name == 'mkl' + blas = dependency('mkl', + modules: ['cblas'] + blas_interface + mkl_opts, + required: false, # may be required, but we need to emit a custom error message + version: mkl_version_req, + ) + # Insert a second try with MKL, because we may be rejecting older versions + # or missing it because no pkg-config installed. If so, we need to retry + # with MKL SDL, and drop the version constraint (this always worked). + if not blas.found() and mkl_may_use_sdl + blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false) + endif else - _openblas_names = ['openblas', 'OpenBLAS'] + if _name == 'flexiblas' and use_ilp64 + _name = 'flexiblas64' + endif + blas = dependency(_name, modules: ['cblas'] + blas_interface, required: false) endif - blas = dependency(_openblas_names, required: false) - endif -elif blas_name.to_lower() == 'accelerate' - # macOS 13.3+ has updated interfaces aligned with BLAS/LAPACK 3.9.1. Use them if available. - if macOS13_3_or_later - accelerate_compile_args = ['-DACCELERATE_NEW_LAPACK'] - if(use_ilp64) - accelerate_compile_args += '-DACCELERATE_LAPACK_ILP64' + if blas.found() + break endif - blas = declare_dependency( - compile_args: accelerate_compile_args, - dependencies: dependency('Accelerate') - ) - else - if(use_ilp64) - error('macOS SDK 13.3+ is required for ILP64 support.') - endif - blas = dependency('Accelerate') - endif + endforeach else - blas = dependency(blas_name, required: false) -endif -have_blas = blas.found() -cblas = [] -if have_blas - # As noted above, at this point the BLAS_SYMBOL_SUFFIX may be injected into - # the CFLAGS directly, so this requires care to use that when it happens: - if blas_symbol_suffix != '' - probe_args = ['-DBLAS_SYMBOL_SUFFIX=' + blas_symbol_suffix] - else - probe_args = [] - endif - - # Netlib BLAS has a separate `libcblas.so` which we use directly in the g77 - # ABI wrappers, so detect it and error out if we cannot find it. OpenBLAS can - # be built without CBLAS too (see gh-23909, done by Arch Linux until - # recently) - # In the future, this should be done automatically for: - # `dependency('blas', modules: cblas)` - # see https://github.com/mesonbuild/meson/pull/10921. - have_cblas = false - if blas_name.to_lower() == 'accelerate' - _cblas_header = '' - elif blas_name.to_lower().startswith('mkl') - _cblas_header = '' - else - _cblas_header = '' - endif - if blas_name == 'scipy-openblas' - have_cblas = true - elif cc.links(f''' - #ifndef BLAS_SYMBOL_SUFFIX - # define BLAS_SYMBOL_SUFFIX - #endif - #define EXPAND(suffix) cblas_ddot ## suffix - #define DDOT(suffix) EXPAND(suffix) - - #include @_cblas_header@ - - int main(int argc, const char *argv[]) - { - double a[4] = {1,2,3,4}; - double b[4] = {5,6,7,8}; - return DDOT(BLAS_SYMBOL_SUFFIX)(4, a, 1, b, 1) > 10; - } - ''', - dependencies: blas, - args: probe_args, - name: 'CBLAS', + if blas_name == 'mkl' + blas = dependency('mkl', + modules: ['cblas'] + blas_interface + mkl_opts, + required: false, + version: mkl_version_req, ) - have_cblas = true - else - cblas = dependency('cblas', required: false) - if cblas.found() - have_cblas = true + # Same deal as above - try again for MKL + if not blas.found() and mkl_may_use_sdl + blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false) endif + else + blas = dependency(blas_name, modules: ['cblas'] + blas_interface, required: false) endif endif -# BLAS and LAPACK are dependencies for NumPy. Since NumPy 2.0, by default the -# build will fail if they are missing; the performance impact is large, so -# using fallback routines must be explicitly opted into by the user. xref -# gh-24200 for a discussion on this. -# -# Note that we can only use a BLAS which provides a CBLAS interface. So disable -# BLAS completely if CBLAS is not found. -allow_noblas = get_option('allow-noblas') +have_blas = blas.found() if have_blas - _args_blas = [] # note: used for C and C++ via `blas_dep` below - if have_cblas - _args_blas += ['-DHAVE_CBLAS'] - elif not allow_noblas - error('No CBLAS interface detected! Install a BLAS library with CBLAS ' + \ - 'support, or use the `allow-noblas` build option (note, this ' + \ - 'may be up to 100x slower for some linear algebra operations).') - endif + _args_blas = ['-DHAVE_CBLAS'] # note: used for C and C++ via `blas_dep` below if use_ilp64 _args_blas += ['-DHAVE_BLAS_ILP64'] + if 'openblas' in blas.name() + _args_blas += ['-DOPENBLAS_ILP64_NAMING_SCHEME'] + endif + endif + if blas_symbol_suffix == 'auto' + if blas_name == 'scipy-openblas' and use_ilp64 + blas_symbol_suffix = '64_' + else + blas_symbol_suffix = blas.get_variable('symbol_suffix', default_value: '') + endif + message(f'BLAS symbol suffix: @blas_symbol_suffix@') endif if blas_symbol_suffix != '' _args_blas += ['-DBLAS_SYMBOL_SUFFIX=' + blas_symbol_suffix] endif blas_dep = declare_dependency( - dependencies: [blas, cblas], + dependencies: [blas], compile_args: _args_blas, ) else @@ -218,37 +172,33 @@ else endif endif -if blas_name == 'scipy-openblas' - lapack_dep = dependency('scipy-openblas', required: false) -elif lapack_name == 'openblas' - lapack_dep = dependency(['openblas', 'OpenBLAS'], required: false) -elif lapack_name.to_lower() == 'accelerate' - # macOS 13.3+ has updated interfaces aligned with BLAS/LAPACK 3.9.1. Use them if available. - if macOS13_3_or_later - accelerate_compile_args = ['-DACCELERATE_NEW_LAPACK'] - if(use_ilp64) - accelerate_compile_args += '-DACCELERATE_LAPACK_ILP64' - endif - lapack_dep = declare_dependency( - compile_args: accelerate_compile_args, - dependencies: dependency('Accelerate') - ) +if 'mkl' in blas.name() or blas.name() == 'accelerate' or blas_name == 'scipy-openblas' + # For these libraries we know that they contain LAPACK, and it's desirable to + # use that - no need to run the full detection twice. + lapack = blas +else + if lapack_name == 'auto' + foreach _name : get_option('lapack-order') + lapack = dependency(_name, modules: ['lapack'] + blas_interface, required: false) + if lapack.found() + break + endif + endforeach else - if(use_ilp64) - error('macOS SDK 13.3+ is required for ILP64 support.') - endif - lapack_dep = dependency('Accelerate') + lapack = dependency(lapack_name, modules: ['lapack'] + blas_interface, required: false) endif -else - lapack_dep = dependency(lapack_name, required: false) endif -have_lapack = lapack_dep.found() + +have_lapack = lapack.found() if not have_lapack and not allow_noblas error('No LAPACK library detected! Install one, or use the ' + \ '`allow-noblas` build option (note, this may be up to 100x slower ' + \ 'for some linear algebra operations).') +else + lapack_dep = declare_dependency(dependencies: [lapack, blas_dep]) endif + # Copy the main __init__.py|pxd files to the build dir (needed for Cython) __init__py = fs.copyfile('__init__.py') __init__pxd = fs.copyfile('__init__.pxd') @@ -395,7 +345,7 @@ conf_data.set('PYTHON_VERSION', py.language_version()) dependency_map = { 'LAPACK': lapack_dep, } -if have_blas and have_cblas +if have_blas dependency_map += {'BLAS': blas} else conf_data.set('BLAS_NAME', blas_name) @@ -409,13 +359,11 @@ foreach name, dep : dependency_map if dep.found() conf_data.set(name + '_VERSION', dep.version()) conf_data.set(name + '_TYPE_NAME', dep.type_name()) - if dep.type_name() == 'pkgconfig' - # CMake detection yields less info, so we need to leave it blank there - conf_data.set(name + '_INCLUDEDIR', dep.get_variable('includedir')) - conf_data.set(name + '_LIBDIR', dep.get_variable('libdir')) - conf_data.set(name + '_OPENBLAS_CONFIG', dep.get_variable('openblas_config')) - conf_data.set(name + '_PCFILEDIR', dep.get_variable('pcfiledir')) - endif + # get_variable() results may be missing for a variety of reasons + conf_data.set(name + '_INCLUDEDIR', dep.get_variable('includedir', default_value: 'unknown')) + conf_data.set(name + '_LIBDIR', dep.get_variable('libdir', default_value: 'unknown')) + conf_data.set(name + '_OPENBLAS_CONFIG', dep.get_variable('openblas_config', default_value: 'unknown')) + conf_data.set(name + '_PCFILEDIR', dep.get_variable('pcfiledir', default_value: 'unknown')) endif endforeach diff --git a/pyproject.toml b/pyproject.toml index bbc7179922bc..2630f5c4a78b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -153,6 +153,7 @@ tracker = "https://github.com/numpy/numpy/issues" skip = "cp36-* cp37-* cp-38* pp37-* *-manylinux_i686 *_ppc64le *_s390x *-musllinux_aarch64" build-verbosity = "3" before-build = "bash {project}/tools/wheels/cibw_before_build.sh {project}" +config-settings = "setup-args=-Duse-ilp64=true setup-args=-Dblas=openblas setup-args=-Dlapack=openblas setup-args=-Dblas-symbol-suffix=64_" # meson has a hard dependency on ninja, and we need meson to build # c-extensions in tests. There is a ninja PyPI package used in # build_requirements.txt for macOS, windows, linux but it cannot be in @@ -165,7 +166,7 @@ test-command = "bash {project}/tools/wheels/cibw_test_command.sh {project}" manylinux-x86_64-image = "manylinux2014" manylinux-aarch64-image = "manylinux2014" musllinux-x86_64-image = "musllinux_1_1" -environment = { CFLAGS="-fno-strict-aliasing -DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", LDFLAGS="-Wl,--strip-debug", CXXFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", NPY_USE_BLAS_ILP64="1", RUNNER_OS="Linux"} +environment = {CFLAGS="-fno-strict-aliasing", LDFLAGS="-Wl,--strip-debug", NPY_USE_BLAS_ILP64="1", RUNNER_OS="Linux"} [tool.cibuildwheel.macos] # For universal2 wheels, we will need to fuse them manually @@ -175,12 +176,13 @@ environment = { CFLAGS="-fno-strict-aliasing -DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLA # for more info archs = "x86_64 arm64" test-skip = "*_universal2:arm64" -# MACOS linker doesn't support stripping symbols -environment = {CFLAGS="-fno-strict-aliasing -DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", CXXFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", NPY_USE_BLAS_ILP64="1", CC="clang", CXX = "clang++", RUNNER_OS="macOS"} +# MACOS linker doesn't support stripping symbols. +# Note that NPY_USE_BLAS_ILP64 is used in `tools/openblas_support.py`. +environment = {CFLAGS="-fno-strict-aliasing", CC="clang", CXX = "clang++", NPY_USE_BLAS_ILP64="1", RUNNER_OS="macOS"} [tool.cibuildwheel.windows] -environment = {NPY_USE_BLAS_ILP64="1", CFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", CXXFLAGS="-DBLAS_SYMBOL_SUFFIX=64_ -DHAVE_BLAS_ILP64", LDFLAGS="", PKG_CONFIG_PATH="C:/opt/64/lib/pkgconfig"} -config-settings = "setup-args=--vsenv" +environment = {NPY_USE_BLAS_ILP64="1", PKG_CONFIG_PATH="C:/opt/64/lib/pkgconfig"} +config-settings = "setup-args=--vsenv setup-args=-Duse-ilp64=true setup-args=-Dblas=openblas setup-args=-Dlapack=openblas" repair-wheel-command = "bash ./tools/wheels/repair_windows.sh {wheel} {dest_dir}" [[tool.cibuildwheel.overrides]] diff --git a/tools/ci/_blis_debian.pc b/tools/ci/_blis_debian.pc new file mode 100644 index 000000000000..b849b50f6b1f --- /dev/null +++ b/tools/ci/_blis_debian.pc @@ -0,0 +1,8 @@ +libdir=/usr/lib/x86_64-linux-gnu/blis-pthread/ +includedir=/usr/include/x86_64-linux-gnu/blis-pthread + +Name: BLIS +Description: BLAS-like Library Instantiation Software Framework - specific to NumPy CI job, needed until Debian ships blis.pc (see .github/workflows/linux_blas.yml) +Version: 0.9.0-numpy-ci +Libs: -L${libdir} -lblis +Cflags: -I${includedir} diff --git a/vendored-meson/meson b/vendored-meson/meson index b7dc7abc4102..66ba7dbbfe28 160000 --- a/vendored-meson/meson +++ b/vendored-meson/meson @@ -1 +1 @@ -Subproject commit b7dc7abc4102ec3db4bb9066cb5e674e7a4b08f4 +Subproject commit 66ba7dbbfe2838983f65ad8fe16da1535ebf5b9d