diff --git a/.github/workflows/linux_meson.yml b/.github/workflows/linux_meson.yml index 7be5cb38bfc2..ebbd52997e42 100644 --- a/.github/workflows/linux_meson.yml +++ b/.github/workflows/linux_meson.yml @@ -1,4 +1,36 @@ -name: Test Meson build (Linux) +name: BLAS tests (Linux) + +# This file is meant for testing different BLAS/LAPACK flavors and build +# options on Linux. All other yml files for Linux will only test without BLAS +# (mostly because that's easier and faster to build) or with the same 64-bit +# OpenBLAS build that is used in the wheel jobs. +# +# Jobs and their purpose: +# +# - openblas32_stable_nightly: +# Uses the 32-bit OpenBLAS builds, both the latest stable release +# and a nightly build. +# - 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: @@ -71,3 +103,253 @@ jobs: export NPY_RUN_MYPY_IN_TESTSUITE=1 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 593549485ba0..5c65a2b2e8b9 100644 --- a/.github/workflows/linux_musl.yml +++ b/.github/workflows/linux_musl.yml @@ -48,20 +48,22 @@ jobs: ln -s /usr/local/bin/python3.10 /usr/local/bin/python - - name: test musllinux_x86_64 + - name: test-musllinux_x86_64 + env: + PKG_CONFIG_PATH: ${{ github.workspace }}/.openblas run: | python -m venv test_env source test_env/bin/activate - # required for figuring out the system tags in openblas_support - pip install packaging - - # install openblas by co-opting the CIBW setup script - RUNNER_OS=Linux sh tools/wheels/cibw_before_build.sh . + pip install scipy-openblas64 - pip install -r build_requirements.txt - pip install pytest pytest-xdist hypothesis typing_extensions + pip install -r build_requirements.txt -r test_requirements.txt # use meson to build and test - spin build + spin build --with-scipy-openblas=64 -- -Duse-ilp64=true spin test -j auto + + - name: Meson Log + shell: bash + run: | + cat build/meson-logs/meson-log.txt diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 29f141b10f9d..b34c86bec901 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/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d83bddafdcfc..76757f6f097d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -118,7 +118,8 @@ jobs: python-version: "3.x" - name: Build wheels - uses: pypa/cibuildwheel@39a63b5912f086dd459cf6fcb13dcdd3fe3bc24d # v2.15.0 + uses: pypa/cibuildwheel@a873dd9cbf9e3c4c73a1fd11ac31cf835f6eb502 # v2.16.0 + #uses: pypa/cibuildwheel@fff9ec32ed25a9c576750c91e06b410ed0c15db7 # v2.16.2 env: CIBW_PRERELEASE_PYTHONS: True CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} diff --git a/.github/workflows/windows_meson.yml b/.github/workflows/windows.yml similarity index 80% rename from .github/workflows/windows_meson.yml rename to .github/workflows/windows.yml index 851284a20fb0..fbde86092b92 100644 --- a/.github/workflows/windows_meson.yml +++ b/.github/workflows/windows.yml @@ -1,4 +1,4 @@ -name: Test Meson build (Windows) +name: Windows tests on: pull_request: @@ -6,9 +6,6 @@ on: - main - maintenance/** -env: - PYTHON_VERSION: 3.11 - concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true @@ -17,10 +14,13 @@ permissions: contents: read # to fetch code (actions/checkout) jobs: - msvc_64bit_python_openblas: - name: MSVC, x86-64, LP64 OpenBLAS + python64bit_openblas: + name: x86-64, LP64 OpenBLAS runs-on: windows-2019 if: "github.repository == 'numpy/numpy'" + strategy: + matrix: + compiler: ["MSVC", "Clang-cl"] steps: - name: Checkout uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 @@ -31,7 +31,7 @@ jobs: - name: Setup Python uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: - python-version: ${{ env.PYTHON_VERSION }} + python-version: '3.11' - name: Install build dependencies from PyPI run: | @@ -48,16 +48,28 @@ jobs: unzip -d c:\opt openblas-v0.3.21-win_amd64-gcc_10_3_0.zip echo "PKG_CONFIG_PATH=c:\opt\64\lib\pkgconfig;" >> $env:GITHUB_ENV - - name: Install NumPy + - name: Install Clang-cl + if: matrix.compiler == 'Clang-cl' + run: | + choco install llvm -y --version=16.0.6 + + - name: Install NumPy (MSVC) + if: matrix.compiler == 'MSVC' run: | spin build -j2 -- --vsenv + - name: Install NumPy (Clang-cl) + if: matrix.compiler == 'Clang-cl' + run: | + "[binaries]","c = 'clang-cl'","cpp = 'clang-cl'","ar = 'llvm-lib'","c_ld = 'lld-link'","cpp_ld = 'lld-link'" | Out-File $PWD/clang-cl-build.ini -Encoding ascii + spin build -j2 -- --vsenv --native-file=$PWD/clang-cl-build.ini + - name: Copy OpenBLAS DLL, write _distributor_init.py run: | # Getting the OpenBLAS DLL to the right place so it loads $installed_path = "$PWD\build-install\usr\Lib\site-packages" $numpy_path = "${installed_path}\numpy" - $libs_path = "${numpy_path}\.libs" + $libs_path = "${installed_path}\numpy.libs" mkdir ${libs_path} $ob_path = "C:/opt/64/bin/" cp $ob_path/*.dll $libs_path diff --git a/.github/workflows/windows_clangcl.yml b/.github/workflows/windows_clangcl.yml deleted file mode 100644 index 3f3201df587b..000000000000 --- a/.github/workflows/windows_clangcl.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: Test Clang-CL Build (Windows) - -on: - pull_request: - branches: - - main - - maintenance/** - -env: - PYTHON_VERSION: 3.11 - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -permissions: - contents: read # to fetch code (actions/checkout) - -jobs: - meson: - name: Meson windows build/test - runs-on: windows-2019 - if: "github.repository == 'numpy/numpy'" - steps: - - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - with: - submodules: recursive - fetch-depth: 0 - - name: Setup Python - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - - name: Install build dependencies from PyPI - run: | - pip install spin Cython - - - name: Install OpenBLAS and Clang-cl - run: | - # Download and install pre-built OpenBLAS library with 32-bit - # interfaces Unpack it in the pkg-config hardcoded path - choco install unzip -y - choco install wget -y - # Install llvm, which contains clang-cl - choco install llvm -y --version=16.0.6 - choco install -y --checksum 6004DF17818F5A6DBF19CB335CC92702 pkgconfiglite - wget https://anaconda.org/multibuild-wheels-staging/openblas-libs/v0.3.21/download/openblas-v0.3.21-win_amd64-gcc_10_3_0.zip - unzip -d c:\opt openblas-v0.3.21-win_amd64-gcc_10_3_0.zip - echo "PKG_CONFIG_PATH=c:\opt\64\lib\pkgconfig;" >> $env:GITHUB_ENV - - - name: Write native file for Clang-cl binaries - run: | - # TODO: this job is identical to the one in `windows_meson.yml` aside - # from installing Clang-cl and usage of this .ini file. So merge the - # two and use a matrix'ed CI job run. - "[binaries]","c = 'clang-cl'","cpp = 'clang-cl'","ar = 'llvm-lib'","c_ld = 'lld-link'","cpp_ld = 'lld-link'" | Out-File $PWD/clang-cl-build.ini -Encoding ascii - - - name: Install NumPy - run: | - spin build -j2 -- --vsenv --native-file=$PWD/clang-cl-build.ini - - - name: Copy OpenBLAS DLL, write _distributor_init.py - run: | - # Getting the OpenBLAS DLL to the right place so it loads - $installed_path = "$PWD\build-install\usr\Lib\site-packages" - $numpy_path = "${installed_path}\numpy" - $libs_path = "${numpy_path}\.libs" - mkdir ${libs_path} - $ob_path = "C:/opt/64/bin/" - cp $ob_path/*.dll $libs_path - # Write _distributor_init.py to load .libs DLLs. - python -c "from tools import openblas_support; openblas_support.make_init(r'${numpy_path}')" - - - name: Install test dependencies - run: | - python -m pip install -r test_requirements.txt - python -m pip install threadpoolctl - - - name: Run test suite - run: | - spin test diff --git a/.mailmap b/.mailmap index 9f83be9356fc..c34bd81bc90a 100644 --- a/.mailmap +++ b/.mailmap @@ -42,7 +42,8 @@ @yan-wyb @yetanothercheer Aaron Baecker -arunkumarkota +Arun Kota +Arun Kota Arun Kota Aarthi Agurusa Adarsh Singh ADARSH SINGH Andrei Batomunkuev @@ -104,6 +105,7 @@ Anne Archibald Anne Bonner <35413198+bonn0062@users.noreply.github.com> Anthony Vo <43098273+anthonyhvo12@users.noreply.github.com> Antoine Pitrou +Anton Prosekin Anže Starič Arfy Slowy Aron Ahmadia @@ -428,6 +430,7 @@ Mitchell Faas <35742861+Mitchell-Faas@users.noreply.gi Muhammad Kasim Mukulika Pahari Mukulika Pahari <60316606+Mukulikaa@users.noreply.github.com> +Munira Alduraibi Namami Shanker Namami Shanker NamamiShanker Nathaniel J. Smith diff --git a/.spin/cmds.py b/.spin/cmds.py index ea994c38311e..09556e67bbce 100644 --- a/.spin/cmds.py +++ b/.spin/cmds.py @@ -37,9 +37,14 @@ "-v", "--verbose", is_flag=True, help="Print all build output, even installation" ) +@click.option( + "--with-scipy-openblas", type=click.Choice(["32", "64"]), + default=None, + help="Build with pre-installed scipy-openblas32 or scipy-openblas64 wheel" +) @click.argument("meson_args", nargs=-1) @click.pass_context -def build(ctx, meson_args, jobs=None, clean=False, verbose=False): +def build(ctx, meson_args, with_scipy_openblas, jobs=None, clean=False, verbose=False, quiet=False): """🔧 Build package with Meson/ninja and install MESON_ARGS are passed through e.g.: @@ -53,6 +58,10 @@ def build(ctx, meson_args, jobs=None, clean=False, verbose=False): CFLAGS="-O0 -g" spin build """ + # XXX keep in sync with upstream build + if with_scipy_openblas: + _config_openblas(with_scipy_openblas) + ctx.params.pop("with_scipy_openblas", None) ctx.forward(meson.build) @@ -187,51 +196,6 @@ def test(ctx, pytest_args, markexpr, n_jobs, tests, verbose): ctx.forward(meson.test) -@click.command() -@click.option('--code', '-c', help='Python program passed in as a string') -@click.argument('gdb_args', nargs=-1) -def gdb(code, gdb_args): - """👾 Execute a Python snippet with GDB - - spin gdb -c 'import numpy as np; print(np.__version__)' - - Or pass arguments to gdb: - - spin gdb -c 'import numpy as np; print(np.__version__)' -- --fullname - - Or run another program, they way you normally would with gdb: - - \b - spin gdb ls - spin gdb -- --args ls -al - - You can also run Python programs: - - \b - spin gdb my_tests.py - spin gdb -- my_tests.py --mytest-flag - """ - meson._set_pythonpath() - gdb_args = list(gdb_args) - - if gdb_args and gdb_args[0].endswith('.py'): - gdb_args = ['--args', sys.executable] + gdb_args - - if sys.version_info[:2] >= (3, 11): - PYTHON_FLAGS = ['-P'] - code_prefix = '' - else: - PYTHON_FLAGS = [] - code_prefix = 'import sys; sys.path.pop(0); ' - - if code: - PYTHON_ARGS = ['-c', code_prefix + code] - gdb_args += ['--args', sys.executable] + PYTHON_FLAGS + PYTHON_ARGS - - gdb_cmd = ['gdb', '-ex', 'set detach-on-fork on'] + gdb_args - util.run(gdb_cmd, replace=True) - - # From scipy: benchmarks/benchmarks/common.py def _set_mem_rlimit(max_mem=None): """ @@ -297,19 +261,7 @@ def _run_asv(cmd): except (ImportError, RuntimeError): pass - try: - util.run(cmd, cwd='benchmarks', env=env, sys_exit=False) - except FileNotFoundError: - click.secho(( - "Cannot find `asv`. " - "Please install Airspeed Velocity:\n\n" - " https://asv.readthedocs.io/en/latest/installing.html\n" - "\n" - "Depending on your system, one of the following should work:\n\n" - " pip install asv\n" - " conda install asv\n" - ), fg="red") - sys.exit(1) + util.run(cmd, cwd='benchmarks', env=env) @click.command() @@ -330,13 +282,17 @@ def _run_asv(cmd): @click.option( '--verbose', '-v', is_flag=True, default=False ) +@click.option( + '--quick', '-q', is_flag=True, default=False, + help="Run each benchmark only once (timings won't be accurate)" +) @click.argument( 'commits', metavar='', required=False, nargs=-1 ) @click.pass_context -def bench(ctx, tests, compare, verbose, commits): +def bench(ctx, tests, compare, verbose, quick, commits): """🏋 Run benchmarks. \b @@ -376,6 +332,9 @@ def bench(ctx, tests, compare, verbose, commits): if verbose: bench_args = ['-v'] + bench_args + if quick: + bench_args = ['--quick'] + bench_args + if not compare: # No comparison requested; we build and benchmark the current version @@ -403,27 +362,21 @@ def bench(ctx, tests, compare, verbose, commits): cmd = [ 'asv', 'run', '--dry-run', '--show-stderr', '--python=same' ] + bench_args - _run_asv(cmd) - else: - # Benchmark comparison - # Ensure that we don't have uncommited changes commit_a, commit_b = [_commit_to_sha(c) for c in commits] - if commit_b == 'HEAD': - if _dirty_git_working_dir(): - click.secho( - "WARNING: you have uncommitted changes --- " - "these will NOT be benchmarked!", - fg="red" - ) + if commit_b == 'HEAD' and _dirty_git_working_dir(): + click.secho( + "WARNING: you have uncommitted changes --- " + "these will NOT be benchmarked!", + fg="red" + ) cmd_compare = [ 'asv', 'continuous', '--factor', '1.05', ] + bench_args + [commit_a, commit_b] - _run_asv(cmd_compare) @@ -441,7 +394,6 @@ def python(ctx, python_args): """ env = os.environ env['PYTHONWARNINGS'] = env.get('PYTHONWARNINGS', 'all') - ctx.invoke(build) ctx.forward(meson.python) @@ -472,29 +424,6 @@ def ipython(ctx, ipython_args): list(ipython_args)) -@click.command(context_settings={"ignore_unknown_options": True}) -@click.argument("args", nargs=-1) -@click.pass_context -def run(ctx, args): - """🏁 Run a shell command with PYTHONPATH set - - \b - spin run make - spin run 'echo $PYTHONPATH' - spin run python -c 'import sys; del sys.path[0]; import mypkg' - - If you'd like to expand shell variables, like `$PYTHONPATH` in the example - above, you need to provide a single, quoted command to `run`: - - spin run 'echo $SHELL && echo $PWD' - - On Windows, all shell commands are run via Bash. - Install Git for Windows if you don't have Bash already. - """ - ctx.invoke(build) - ctx.forward(meson.run) - - @click.command(context_settings={"ignore_unknown_options": True}) @click.pass_context def mypy(ctx): @@ -505,3 +434,39 @@ def mypy(ctx): ctx.params['pytest_args'] = [os.path.join('numpy', 'typing')] ctx.params['markexpr'] = 'full' ctx.forward(test) + +@click.command(context_settings={ + 'ignore_unknown_options': True +}) +@click.option( + "--with-scipy-openblas", type=click.Choice(["32", "64"]), + default=None, required=True, + help="Build with pre-installed scipy-openblas32 or scipy-openblas64 wheel" +) +def config_openblas(with_scipy_openblas): + """🔧 Create .openblas/scipy-openblas.pc file + + Also create _distributor_init_local.py + + Requires a pre-installed scipy-openblas64 or scipy-openblas32 + """ + _config_openblas(with_scipy_openblas) + + +def _config_openblas(blas_variant): + import importlib + basedir = os.getcwd() + openblas_dir = os.path.join(basedir, ".openblas") + pkg_config_fname = os.path.join(openblas_dir, "scipy-openblas.pc") + if blas_variant: + module_name = f"scipy_openblas{blas_variant}" + try: + openblas = importlib.import_module(module_name) + except ModuleNotFoundError: + raise RuntimeError(f"'pip install {module_name} first") + local = os.path.join(basedir, "numpy", "_distributor_init_local.py") + with open(local, "wt", encoding="utf8") as fid: + fid.write(f"import {module_name}\n") + os.makedirs(openblas_dir, exist_ok=True) + with open(pkg_config_fname, "wt", encoding="utf8") as fid: + fid.write(openblas.get_pkg_config().replace("\\", "/")) diff --git a/azure-steps-windows.yml b/azure-steps-windows.yml index e09663cd7fbc..1cae980b4368 100644 --- a/azure-steps-windows.yml +++ b/azure-steps-windows.yml @@ -42,18 +42,21 @@ steps: python -m pip install . -v -Csetup-args="--vsenv" -Csetup-args="-Dblas=none" -Csetup-args="-Dlapack=none" -Csetup-args="-Dallow-noblas=true" } elseif ( Test-Path env:NPY_USE_BLAS_ILP64 ) { - python -m pip install . -v -Csetup-args="--vsenv" -Csetup-args="-Duse-ilp64=true" -Csetup-args="-Dblas-symbol-suffix=64_" + python -m pip install scipy-openblas64 spin + spin config-openblas --with-scipy-openblas=64 + $env:PKG_CONFIG_PATH="$pwd/.openblas" + python -m pip install . -v -Csetup-args="--vsenv" -Csetup-args="-Duse-ilp64=true" } else { python -m pip install . -v -Csetup-args="--vsenv" } displayName: 'Build NumPy' - powershell: | - # copy from c:/opt/openblas/openblas_dll to numpy/.libs to ensure it can + # copy from c:/opt/openblas/openblas_dll to numpy/../numpy.libs to ensure it can # get loaded when numpy is imported (no RPATH on Windows) $target = $(python -c "import sysconfig; print(sysconfig.get_path('platlib'))") - mkdir $target/numpy/.libs - copy C:/opt/openblas/openblas_dll/*.dll $target/numpy/.libs + mkdir $target/numpy.libs + copy C:/opt/openblas/openblas_dll/*.dll $target/numpy.libs displayName: 'Copy OpenBLAS DLL to site-packages' - script: | diff --git a/build_requirements.txt b/build_requirements.txt index 7f598f623252..b1cfe0e68f49 100644 --- a/build_requirements.txt +++ b/build_requirements.txt @@ -2,5 +2,5 @@ meson-python>=0.13.1 Cython>=3.0 wheel==0.38.1 ninja -spin==0.5 +spin==0.7 build diff --git a/doc/changelog/1.26.1-changelog.rst b/doc/changelog/1.26.1-changelog.rst new file mode 100644 index 000000000000..bacc6b4ee0b5 --- /dev/null +++ b/doc/changelog/1.26.1-changelog.rst @@ -0,0 +1,46 @@ + +Contributors +============ + +A total of 13 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Andrew Nelson +* Anton Prosekin + +* Charles Harris +* Chongyun Lee + +* Ivan A. Melnikov + +* Jake Lishman + +* Mahder Gebremedhin + +* Mateusz Sokół +* Matti Picus +* Munira Alduraibi + +* Ralf Gommers +* Rohit Goswami +* Sayed Adel + +Pull requests merged +==================== + +A total of 20 pull requests were merged for this release. + +* `#24742 `__: MAINT: Update cibuildwheel version +* `#24748 `__: MAINT: fix version string in wheels built with setup.py +* `#24771 `__: BLD, BUG: Fix build failure for host flags e.g. ``-march=native``... +* `#24773 `__: DOC: Updated the f2py docs to remove a note on -fimplicit-none +* `#24776 `__: BUG: Fix SIMD f32 trunc test on s390x when baseline is none +* `#24785 `__: BLD: add libquadmath to licences and other tweaks (#24753) +* `#24786 `__: MAINT: Activate ``use-compute-credits`` for Cirrus. +* `#24803 `__: BLD: updated vendored-meson/meson for mips64 fix +* `#24804 `__: MAINT: fix licence path win +* `#24813 `__: BUG: Fix order of Windows OS detection macros. +* `#24831 `__: BUG, SIMD: use scalar cmul on bad Apple clang x86_64 (#24828) +* `#24840 `__: BUG: Fix DATA statements for f2py +* `#24870 `__: API: Add ``NumpyUnpickler`` for backporting +* `#24872 `__: MAINT: Xfail test failing on PyPy. +* `#24879 `__: BLD: fix math func feature checks, fix FreeBSD build, add CI... +* `#24899 `__: ENH: meson: implement BLAS/LAPACK auto-detection and many CI... +* `#24902 `__: DOC: add a 1.26.1 release notes section for BLAS/LAPACK build... +* `#24906 `__: MAINT: Backport ``numpy._core`` stubs. Remove ``NumpyUnpickler`` +* `#24911 `__: MAINT: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2 +* `#24912 `__: BUG: loongarch doesn't use REAL(10) diff --git a/doc/source/f2py/buildtools/meson.rst b/doc/source/f2py/buildtools/meson.rst index 23b454ee5857..e8bfe0ea8e41 100644 --- a/doc/source/f2py/buildtools/meson.rst +++ b/doc/source/f2py/buildtools/meson.rst @@ -110,9 +110,6 @@ Salient points It is worth keeping in mind the following: -* ``meson`` will default to passing ``-fimplicit-none`` under ``gfortran`` by - default, which differs from that of the standard ``np.distutils`` behaviour - * It is not possible to use SCREAMCASE in this context, so either the contents of the ``.f`` file or the generated wrapper ``.c`` needs to be lowered to regular letters; which can be facilitated by the ``--lower`` option of diff --git a/doc/source/release.rst b/doc/source/release.rst index cef3a6d0510c..2c2947ee6685 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -5,6 +5,7 @@ Release notes .. toctree:: :maxdepth: 3 + 1.26.1 1.26.0 1.25.2 1.25.1 diff --git a/doc/source/release/1.26.1-notes.rst b/doc/source/release/1.26.1-notes.rst new file mode 100644 index 000000000000..a508b0cd69ed --- /dev/null +++ b/doc/source/release/1.26.1-notes.rst @@ -0,0 +1,123 @@ +.. currentmodule:: numpy + +========================== +NumPy 1.26.1 Release Notes +========================== + +NumPy 1.26.1 is a maintenance release that fixes bugs and regressions +discovered after the 1.26.0 release. In addition, it adds new functionality for +detecting BLAS and LAPACK when building from source. Highlights are: + +- Improved detection of BLAS and LAPACK libraries for meson builds +- Pickle compatibility with the upcoming NumPy 2.0. + +The 1.26.release series is the last planned minor release series before NumPy +2.0. The Python versions supported by this release are 3.9-3.12. + + +Build system changes +==================== + +Improved BLAS/LAPACK detection and control +------------------------------------------ + +Auto-detection for a number of BLAS and LAPACK is now implemented for Meson. +By default, the build system will try to detect MKL, Accelerate (on macOS +>=13.3), OpenBLAS, FlexiBLAS, BLIS and reference BLAS/LAPACK. Support for MKL +was significantly improved, and support for FlexiBLAS was added. + +New command-line flags are available to further control the selection of the +BLAS and LAPACK libraries to build against. + +To select a specific library, use the config-settings interface via ``pip`` or +``pypa/build``. E.g., to select ``libblas``/``liblapack``, use:: + + $ pip install numpy -Csetup-args=-Dblas=blas -Csetup-args=-Dlapack=lapack + $ # OR + $ python -m build . -Csetup-args=-Dblas=blas -Csetup-args=-Dlapack=lapack + +This works not only for the libraries named above, but for any library that +Meson is able to detect with the given name through ``pkg-config`` or CMake. + +Besides ``-Dblas`` and ``-Dlapack``, a number of other new flags are available +to control BLAS/LAPACK selection and behavior: + +- ``-Dblas-order`` and ``-Dlapack-order``: a list of library names to search + for in order, overriding the default search order. +- ``-Duse-ilp64``: if set to ``true``, use ILP64 (64-bit integer) BLAS and + LAPACK. Note that with this release, ILP64 support has been extended to + include MKL and FlexiBLAS. OpenBLAS and Accelerate were supported in previous + releases. +- ``-Dallow-noblas``: if set to ``true``, allow NumPy to build with its + internal (very slow) fallback routines instead of linking against an external + BLAS/LAPACK library. *The default for this flag may be changed to ``true`` + in a future 1.26.x release, however for 1.26.1 we'd prefer to keep it as + ``false`` because if failures to detect an installed library are happening, + we'd like a bug report for that, so we can quickly assess whether the new + auto-detection machinery needs further improvements.* +- ``-Dmkl-threading``: to select the threading layer for MKL. There are four + options: ``seq``, ``iomp``, ``gomp`` and ``tbb``. The default is ``auto``, + which selects from those four as appropriate given the version of MKL + selected. +- ``-Dblas-symbol-suffix``: manually select the symbol suffix to use for the + library - should only be needed for linking against libraries built in a + non-standard way. + + +New features +============ + +``numpy._core`` submodule stubs +------------------------------- + +``numpy._core`` submodule stubs were added to provide compatibility with +pickled arrays created using NumPy 2.0 when running Numpy 1.26. + + +Contributors +============ + +A total of 13 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Andrew Nelson +* Anton Prosekin + +* Charles Harris +* Chongyun Lee + +* Ivan A. Melnikov + +* Jake Lishman + +* Mahder Gebremedhin + +* Mateusz Sokół +* Matti Picus +* Munira Alduraibi + +* Ralf Gommers +* Rohit Goswami +* Sayed Adel + + +Pull requests merged +==================== + +A total of 20 pull requests were merged for this release. + +* `#24742 `__: MAINT: Update cibuildwheel version +* `#24748 `__: MAINT: fix version string in wheels built with setup.py +* `#24771 `__: BLD, BUG: Fix build failure for host flags e.g. ``-march=native``... +* `#24773 `__: DOC: Updated the f2py docs to remove a note on -fimplicit-none +* `#24776 `__: BUG: Fix SIMD f32 trunc test on s390x when baseline is none +* `#24785 `__: BLD: add libquadmath to licences and other tweaks (#24753) +* `#24786 `__: MAINT: Activate ``use-compute-credits`` for Cirrus. +* `#24803 `__: BLD: updated vendored-meson/meson for mips64 fix +* `#24804 `__: MAINT: fix licence path win +* `#24813 `__: BUG: Fix order of Windows OS detection macros. +* `#24831 `__: BUG, SIMD: use scalar cmul on bad Apple clang x86_64 (#24828) +* `#24840 `__: BUG: Fix DATA statements for f2py +* `#24870 `__: API: Add ``NumpyUnpickler`` for backporting +* `#24872 `__: MAINT: Xfail test failing on PyPy. +* `#24879 `__: BLD: fix math func feature checks, fix FreeBSD build, add CI... +* `#24899 `__: ENH: meson: implement BLAS/LAPACK auto-detection and many CI... +* `#24902 `__: DOC: add a 1.26.1 release notes section for BLAS/LAPACK build... +* `#24906 `__: MAINT: Backport ``numpy._core`` stubs. Remove ``NumpyUnpickler`` +* `#24911 `__: MAINT: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2 +* `#24912 `__: BUG: loongarch doesn't use REAL(10) + diff --git a/doc/source/user/how-to-io.rst b/doc/source/user/how-to-io.rst index 6a4127e8f00a..8d8bdd7d4f5b 100644 --- a/doc/source/user/how-to-io.rst +++ b/doc/source/user/how-to-io.rst @@ -319,6 +319,9 @@ Use :func:`numpy.save` and :func:`numpy.load`. Set ``allow_pickle=False``, unless the array dtype includes Python objects, in which case pickling is required. +NumPy 1.26 also supports unpickling files created with NumPy 2.0, either +via :func:`numpy.load` or the pickle module directly. + Convert from a pandas DataFrame to a NumPy array ================================================ 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_cpu/meson.build b/meson_cpu/meson.build index 97b33c461b95..ed2313bc6a62 100644 --- a/meson_cpu/meson.build +++ b/meson_cpu/meson.build @@ -98,7 +98,7 @@ if host_machine.endian() == 'little' and cpu_family == 'ppc64' min_features = [VSX2] endif -# Used by build option 'max' +# Used by build option 'max/native/detect' max_features_dict = { 'x86': X86_FEATURES, 'x86_64': X86_FEATURES, @@ -111,6 +111,11 @@ max_features = [] foreach fet_name, fet_obj : max_features_dict max_features += [fet_obj] endforeach +if max_features.length() == 0 + message('Disabling CPU feature detection due to unsupported architecture: "' + cpu_family + '"') + CPU_CONF_BASELINE = 'none' + CPU_CONF_DISPATCH = 'none' +endif parse_options = { 'cpu-baseline': CPU_CONF_BASELINE, diff --git a/meson_options.txt b/meson_options.txt index 8b1fad6c4041..05e9e733578e 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/__init__.py b/numpy/_core/__init__.py new file mode 100644 index 000000000000..a2f096f3f174 --- /dev/null +++ b/numpy/_core/__init__.py @@ -0,0 +1,4 @@ +""" +This private module only contains stubs for interoperability with +NumPy 2.0 pickled arrays. It may not be used by the end user. +""" diff --git a/numpy/_core/__init__.pyi b/numpy/_core/__init__.pyi new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/numpy/_core/_dtype.py b/numpy/_core/_dtype.py new file mode 100644 index 000000000000..974d93d98cbb --- /dev/null +++ b/numpy/_core/_dtype.py @@ -0,0 +1,6 @@ +from numpy.core import _dtype + +_globals = globals() + +for item in _dtype.__dir__(): + _globals[item] = getattr(_dtype, item) diff --git a/numpy/_core/_dtype_ctypes.py b/numpy/_core/_dtype_ctypes.py new file mode 100644 index 000000000000..bfa16aabf423 --- /dev/null +++ b/numpy/_core/_dtype_ctypes.py @@ -0,0 +1,6 @@ +from numpy.core import _dtype_ctypes + +_globals = globals() + +for item in _dtype_ctypes.__dir__(): + _globals[item] = getattr(_dtype_ctypes, item) diff --git a/numpy/_core/_internal.py b/numpy/_core/_internal.py new file mode 100644 index 000000000000..52a8e907292e --- /dev/null +++ b/numpy/_core/_internal.py @@ -0,0 +1,6 @@ +from numpy.core import _internal + +_globals = globals() + +for item in _internal.__dir__(): + _globals[item] = getattr(_internal, item) diff --git a/numpy/_core/_multiarray_umath.py b/numpy/_core/_multiarray_umath.py new file mode 100644 index 000000000000..7ce48fcb258d --- /dev/null +++ b/numpy/_core/_multiarray_umath.py @@ -0,0 +1,6 @@ +from numpy.core import _multiarray_umath + +_globals = globals() + +for item in _multiarray_umath.__dir__(): + _globals[item] = getattr(_multiarray_umath, item) diff --git a/numpy/_core/multiarray.py b/numpy/_core/multiarray.py new file mode 100644 index 000000000000..6c37d1da9fe7 --- /dev/null +++ b/numpy/_core/multiarray.py @@ -0,0 +1,6 @@ +from numpy.core import multiarray + +_globals = globals() + +for item in multiarray.__dir__(): + _globals[item] = getattr(multiarray, item) diff --git a/numpy/_core/umath.py b/numpy/_core/umath.py new file mode 100644 index 000000000000..3d08c90332a3 --- /dev/null +++ b/numpy/_core/umath.py @@ -0,0 +1,6 @@ +from numpy.core import umath + +_globals = globals() + +for item in umath.__dir__(): + _globals[item] = getattr(umath, item) diff --git a/numpy/_distributor_init.py b/numpy/_distributor_init.py index d893ba37719b..25b0eed79fca 100644 --- a/numpy/_distributor_init.py +++ b/numpy/_distributor_init.py @@ -3,8 +3,13 @@ Distributors: you can add custom code here to support particular distributions of numpy. -For example, this is a good place to put any checks for hardware requirements. +For example, this is a good place to put any BLAS/LAPACK initialization code. The numpy standard source distribution will not put code in this file, so you can safely replace this file with your own version. """ + +try: + from . import _distributor_init_local +except ImportError: + pass diff --git a/numpy/core/include/numpy/npy_os.h b/numpy/core/include/numpy/npy_os.h index 6d8317d0667c..0ce5d78b42c0 100644 --- a/numpy/core/include/numpy/npy_os.h +++ b/numpy/core/include/numpy/npy_os.h @@ -19,12 +19,18 @@ #define NPY_OS_SOLARIS #elif defined(__CYGWIN__) #define NPY_OS_CYGWIN -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - #define NPY_OS_WIN32 -#elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64) - #define NPY_OS_WIN64 -#elif defined(__MINGW32__) || defined(__MINGW64__) +/* We are on Windows.*/ +#elif defined(_WIN32) + /* We are using MinGW (64-bit or 32-bit)*/ + #if defined(__MINGW32__) || defined(__MINGW64__) #define NPY_OS_MINGW + /* Otherwise, if _WIN64 is defined, we are targeting 64-bit Windows*/ + #elif defined(_WIN64) + #define NPY_OS_WIN64 + /* Otherwise assume we are targeting 32-bit Windows*/ + #else + #define NPY_OS_WIN32 + #endif #elif defined(__APPLE__) #define NPY_OS_DARWIN #elif defined(__HAIKU__) diff --git a/numpy/core/meson.build b/numpy/core/meson.build index 473362f1b7e9..a1fc7e9d8a84 100644 --- a/numpy/core/meson.build +++ b/numpy/core/meson.build @@ -149,20 +149,32 @@ endif # Mandatory functions: if not found, fail the build # Some of these can still be blocklisted if the C99 implementation # is buggy, see numpy/core/src/common/npy_config.h -mandatory_funcs = [ +mandatory_math_funcs = [ 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'fabs', 'floor', 'ceil', 'sqrt', 'log10', 'log', 'exp', 'asin', 'acos', 'atan', 'fmod', 'modf', 'frexp', 'ldexp', 'expm1', 'log1p', 'acosh', 'asinh', 'atanh', - 'rint', 'trunc', 'exp2', - 'copysign', 'nextafter', 'strtoll', 'strtoull', 'cbrt', + 'rint', 'trunc', 'exp2', 'copysign', 'nextafter', 'cbrt', 'log2', 'pow', 'hypot', 'atan2', - 'csin', 'csinh', 'ccos', 'ccosh', 'ctan', 'ctanh', - 'creal', 'cimag', 'conj' ] -foreach func: mandatory_funcs - if not cc.has_function(func) - error('Function `{func}` not found') +foreach func: mandatory_math_funcs + if not cc.has_function(func, prefix: '#include ', dependencies: m_dep) + error(f'Function `@func@` not found') + endif +endforeach + +mandatory_complex_math_funcs = [ + 'csin', 'csinh', 'ccos', 'ccosh', 'ctan', 'ctanh', 'creal', 'cimag', 'conj' +] +foreach func: mandatory_complex_math_funcs + if not cc.has_function(func, prefix: '#include ', dependencies: m_dep) + error(f'Function `@func@` not found') + endif +endforeach + +foreach func: ['strtoll', 'strtoull'] + if not cc.has_function(func, prefix: '#include ') + error(f'Function `@func@` not found') endif endforeach @@ -177,13 +189,13 @@ c99_complex_funcs = [ foreach func: c99_complex_funcs func_single = func + 'f' func_longdouble = func + 'l' - if cc.has_function(func) + if cc.has_function(func, prefix: '#include ', dependencies: m_dep) cdata.set10('HAVE_' + func.to_upper(), true) endif - if cc.has_function(func_single) + if cc.has_function(func_single, prefix: '#include ', dependencies: m_dep) cdata.set10('HAVE_' + func_single.to_upper(), true) endif - if cc.has_function(func_longdouble) + if cc.has_function(func_longdouble, prefix: '#include ', dependencies: m_dep) cdata.set10('HAVE_' + func_longdouble.to_upper(), true) endif endforeach @@ -192,7 +204,7 @@ endforeach # libnpymath as a C99 compat layer, these may still be relevant. c99_macros = ['isfinite', 'isinf', 'isnan', 'signbit'] foreach macro: c99_macros - if cc.has_function(macro) + if cc.has_function(macro, prefix: '#include ', dependencies: m_dep) cdata.set10('NPY_HAVE_DECL_' + macro.to_upper(), true) if not cc.has_header_symbol('Python.h', macro, dependencies: py_dep) # Add in config.h as well, except if it will clash with Python's config.h content 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/core/src/npymath/npy_math_complex.c.src b/numpy/core/src/npymath/npy_math_complex.c.src index eb9d810b7d82..8e1decbfd9d5 100644 --- a/numpy/core/src/npymath/npy_math_complex.c.src +++ b/numpy/core/src/npymath/npy_math_complex.c.src @@ -158,7 +158,9 @@ npy_carg@c@(@ctype@ z) #define SCALED_CEXP_LOWERL 11357.216553474703895L #define SCALED_CEXP_UPPERL 22756.021937783004509L -#if !defined(HAVE_CEXP@C@) +#if !defined(HAVE_CSINH@C@) || \ + !defined(HAVE_CCOSH@C@) || \ + !defined(HAVE_CEXP@C@) static @ctype@ diff --git a/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src b/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src index c8bcedb6bbdc..30111258d646 100644 --- a/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src +++ b/numpy/core/src/umath/loops_arithm_fp.dispatch.c.src @@ -367,6 +367,16 @@ NPY_NO_EXPORT void NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@) } #endif #if @VECTOR@ + // Certain versions of Apple clang (commonly used in CI images) produce + // non-deterministic output in the mul path with AVX2 enabled on x86_64. + // Work around by scalarising. + #if @is_mul@ \ + && defined(NPY_CPU_AMD64) && defined(__clang__) \ + && defined(__apple_build_version__) \ + && __apple_build_version__ >= 14000000 \ + && __apple_build_version__ < 14030000 + goto loop_scalar; + #endif // end affected Apple clang. if (is_mem_overlap(b_src0, b_ssrc0, b_dst, b_sdst, len) || is_mem_overlap(b_src1, b_ssrc1, b_dst, b_sdst, len) || b_sdst % sizeof(@ftype@) != 0 || b_sdst == 0 || diff --git a/numpy/core/tests/data/numpy_2_0_array.pkl b/numpy/core/tests/data/numpy_2_0_array.pkl new file mode 100644 index 000000000000..958eee50c9a6 Binary files /dev/null and b/numpy/core/tests/data/numpy_2_0_array.pkl differ diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index b9021ccb24cf..ace40049fd83 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -3726,6 +3726,7 @@ def test_inplace(self): # - defer if other has __array_ufunc__ and it is None # or other is not a subclass and has higher array priority # - else, call ufunc + @pytest.mark.xfail(IS_PYPY, reason="Bug in pypy3.{9, 10}-v7.3.13, #24862") def test_ufunc_binop_interaction(self): # Python method name (without underscores) # -> (numpy ufunc, has_in_place_version, preferred_dtype) @@ -9722,9 +9723,12 @@ def test_ragged_comparison_fails(op): def test_npymath_complex(fun, npfun, x, y, test_dtype): # Smoketest npymath functions z = test_dtype(complex(x, y)) - got = fun(z) - expected = npfun(z) - assert_allclose(got, expected) + with np.errstate(invalid='ignore'): + # Fallback implementations may emit a warning for +-inf (see gh-24876): + # RuntimeWarning: invalid value encountered in absolute + got = fun(z) + expected = npfun(z) + assert_allclose(got, expected) def test_npymath_real(): diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 832a47c926cf..d2d041f71ef2 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -645,6 +645,11 @@ def assert_op_raises_fpe(self, fpeerr, flop, sc1, sc2): @pytest.mark.skipif(IS_WASM, reason="no wasm fp exception support") @pytest.mark.parametrize("typecode", np.typecodes["AllFloat"]) def test_floating_exceptions(self, typecode): + if 'bsd' in sys.platform and typecode in 'gG': + pytest.skip(reason="Fallback impl for (c)longdouble may not raise " + "FPE errors as expected on BSD OSes, " + "see gh-24876, gh-23379") + # Test basic arithmetic function errors with np.errstate(all='raise'): ftype = np.obj2sctype(typecode) diff --git a/numpy/core/tests/test_numpy_2_0_compat.py b/numpy/core/tests/test_numpy_2_0_compat.py new file mode 100644 index 000000000000..5224261fd29a --- /dev/null +++ b/numpy/core/tests/test_numpy_2_0_compat.py @@ -0,0 +1,48 @@ +from os import path +import pickle + +import numpy as np + + +class TestNumPy2Compatibility: + + data_dir = path.join(path.dirname(__file__), "data") + filename = path.join(data_dir, "numpy_2_0_array.pkl") + + def test_importable__core_stubs(self): + """ + Checks if stubs for `numpy._core` are importable. + """ + from numpy._core.multiarray import _reconstruct + from numpy._core.umath import cos + from numpy._core._multiarray_umath import exp + from numpy._core._internal import ndarray + from numpy._core._dtype import _construction_repr + from numpy._core._dtype_ctypes import dtype_from_ctypes_type + + def test_unpickle_numpy_2_0_file(self): + """ + Checks that NumPy 1.26 and pickle is able to load pickles + created with NumPy 2.0 without errors/warnings. + """ + with open(self.filename, mode="rb") as file: + content = file.read() + + # Let's make sure that the pickle object we're loading + # was built with NumPy 2.0. + assert b"numpy._core.multiarray" in content + + arr = pickle.loads(content, encoding="latin1") + + assert isinstance(arr, np.ndarray) + assert arr.shape == (73,) and arr.dtype == np.float64 + + def test_numpy_load_numpy_2_0_file(self): + """ + Checks that `numpy.load` for NumPy 1.26 is able to load pickles + created with NumPy 2.0 without errors/warnings. + """ + arr = np.load(self.filename, encoding="latin1", allow_pickle=True) + + assert isinstance(arr, np.ndarray) + assert arr.shape == (73,) and arr.dtype == np.float64 diff --git a/numpy/core/tests/test_simd_module.py b/numpy/core/tests/test_simd_module.py index 44dc58dac098..4fbaa9f3008b 100644 --- a/numpy/core/tests/test_simd_module.py +++ b/numpy/core/tests/test_simd_module.py @@ -86,6 +86,8 @@ def test_signed_overflow(self, sfx): assert lanes == [0] * nlanes def test_truncate_f32(self): + if not npyv.simd_f32: + pytest.skip("F32 isn't support by the SIMD extension") f32 = npyv.setall_f32(0.1)[0] assert f32 != 0.1 assert round(f32, 1) == 0.1 diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 0e07a6cb937b..5567244d14a9 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -1646,6 +1646,8 @@ def test_sinh(self): np.array(1200.0, dtype='d')) @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm") + @pytest.mark.skipif('bsd' in sys.platform, + reason="fallback implementation may not raise, see gh-2487") def test_cosh(self): in_ = [np.nan, -np.nan, np.inf, -np.inf] out = [np.nan, np.nan, np.inf, np.inf] diff --git a/numpy/core/tests/test_umath_complex.py b/numpy/core/tests/test_umath_complex.py index 8aa9a28ff48d..e54300589094 100644 --- a/numpy/core/tests/test_umath_complex.py +++ b/numpy/core/tests/test_umath_complex.py @@ -576,8 +576,8 @@ def test_array(self, stride, astype): complex(0., 0.), complex(np.nan, np.nan), complex(np.nan, np.nan)], dtype=astype) - assert_equal(np.abs(arr[::stride]), abs_true[::stride]) with np.errstate(invalid='ignore'): + assert_equal(np.abs(arr[::stride]), abs_true[::stride]) assert_equal(np.square(arr[::stride]), sq_true[::stride]) class TestComplexAbsoluteAVX: diff --git a/numpy/distutils/core.py b/numpy/distutils/core.py index c4a14e59901f..1cdc739731bf 100644 --- a/numpy/distutils/core.py +++ b/numpy/distutils/core.py @@ -65,7 +65,8 @@ def _dict_append(d, **kws): elif isinstance(dv, dict): _dict_append(dv, **v) elif is_string(dv): - d[k] = dv + v + assert is_string(v) + d[k] = v else: raise TypeError(repr(type(dv))) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index edf56909ab5d..feb28f61cf07 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -2357,7 +2357,10 @@ def _calc_info(self): if self.symbol_prefix: info['define_macros'] += [('BLAS_SYMBOL_PREFIX', self.symbol_prefix)] if self.symbol_suffix: - info['define_macros'] += [('BLAS_SYMBOL_SUFFIX', self.symbol_suffix)] + info['define_macros'] += [ + ('BLAS_SYMBOL_SUFFIX', self.symbol_suffix), + ('OPENBLAS_ILP64_NAMING_SCHEME', None), + ] return info diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index cc041ec56e6e..f352bbaa2720 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1425,53 +1425,61 @@ def analyzeline(m, case, line): if dl.startswith(','): dl = dl[1:].strip() ll.append([dl, il]) - vars = {} - if 'vars' in groupcache[groupcounter]: - vars = groupcache[groupcounter]['vars'] + vars = groupcache[groupcounter].get('vars', {}) last_name = None for l in ll: - l = [x.strip() for x in l] - if l[0][0] == ',': + l[0], l[1] = l[0].strip(), l[1].strip() + if l[0].startswith(','): l[0] = l[0][1:] - if l[0][0] == '(': - outmess( - 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % l[0]) + if l[0].startswith('('): + outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % l[0]) continue - llen = len(l[1]) - for idx, v in enumerate(rmbadname( - [x.strip() for x in markoutercomma(l[0]).split('@,@')]) - ): - if v[0] == '(': - outmess( - 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % v) + for idx, v in enumerate(rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')])): + if v.startswith('('): + outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % v) # XXX: subsequent init expressions may get wrong values. # Ignoring since data statements are irrelevant for # wrapping. continue - fc = 0 + if '!' in l[1]: + # Fixes gh-24746 pyf generation + # XXX: This essentially ignores the value for generating the pyf which is fine: + # integer dimension(3) :: mytab + # common /mycom/ mytab + # Since in any case it is initialized in the Fortran code + outmess('Comment line in declaration "%s" is not supported. Skipping.\n' % l[1]) + continue + vars.setdefault(v, {}) vtype = vars[v].get('typespec') vdim = getdimension(vars[v]) - - if (vtype == 'complex'): - cmplxpat = r"\(.*?\)" - matches = re.findall(cmplxpat, l[1]) - else: - matches = l[1].split(',') - - if v not in vars: - vars[v] = {} - if '=' in vars[v] and not vars[v]['='] == matches[idx]: - outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % ( - v, vars[v]['='], matches[idx])) - - if vdim is not None: - # Need to assign multiple values to one variable - vars[v]['='] = "(/{}/)".format(", ".join(matches)) - else: - vars[v]['='] = matches[idx] + matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',') + try: + new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] + except IndexError: + # gh-24746 + # Runs only if above code fails. Fixes the line + # DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /4*0,0.0D0/ + # by expanding to ['0', '0', '0', '0', '0.0d0'] + if any("*" in m for m in matches): + expanded_list = [] + for match in matches: + if "*" in match: + try: + multiplier, value = match.split("*") + expanded_list.extend([value.strip()] * int(multiplier)) + except ValueError: # if int(multiplier) fails + expanded_list.append(match.strip()) + else: + expanded_list.append(match.strip()) + matches = expanded_list + new_val = "(/{}/)".format(", ".join(matches)) if vdim else matches[idx] + current_val = vars[v].get('=') + if current_val and (current_val != new_val): + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % (v, current_val, new_val)) + vars[v]['='] = new_val last_name = v groupcache[groupcounter]['vars'] = vars - if last_name is not None: + if last_name: previous_context = ('variable', last_name, groupcounter) elif case == 'common': line = m.group('after').strip() @@ -2444,7 +2452,7 @@ def _selected_real_kind_func(p, r=0, radix=0): if p < 16: return 8 machine = platform.machine().lower() - if machine.startswith(('aarch64', 'arm64', 'power', 'ppc', 'riscv', 's390x', 'sparc')): + if machine.startswith(('aarch64', 'arm64', 'loongarch', 'power', 'ppc', 'riscv', 's390x', 'sparc')): if p <= 33: return 16 else: diff --git a/numpy/f2py/tests/src/crackfortran/data_common.f b/numpy/f2py/tests/src/crackfortran/data_common.f new file mode 100644 index 000000000000..5ffd865c8379 --- /dev/null +++ b/numpy/f2py/tests/src/crackfortran/data_common.f @@ -0,0 +1,8 @@ + BLOCK DATA PARAM_INI + COMMON /MYCOM/ MYDATA + DATA MYDATA /0/ + END + SUBROUTINE SUB1 + COMMON /MYCOM/ MYDATA + MYDATA = MYDATA + 1 + END diff --git a/numpy/f2py/tests/src/crackfortran/data_multiplier.f b/numpy/f2py/tests/src/crackfortran/data_multiplier.f new file mode 100644 index 000000000000..19ff8a83e97b --- /dev/null +++ b/numpy/f2py/tests/src/crackfortran/data_multiplier.f @@ -0,0 +1,5 @@ + BLOCK DATA MYBLK + IMPLICIT DOUBLE PRECISION (A-H,O-Z) + COMMON /MYCOM/ IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 + DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /2*3,2*2,0.0D0/ + END diff --git a/numpy/f2py/tests/src/crackfortran/data_stmts.f90 b/numpy/f2py/tests/src/crackfortran/data_stmts.f90 index 0eb97a563899..576c5e485baf 100644 --- a/numpy/f2py/tests/src/crackfortran/data_stmts.f90 +++ b/numpy/f2py/tests/src/crackfortran/data_stmts.f90 @@ -4,6 +4,7 @@ module cmplxdat integer :: i, j real :: x, y real, dimension(2) :: z + real(kind=8) :: pi complex(kind=8), target :: medium_ref_index complex(kind=8), target :: ref_index_one, ref_index_two complex(kind=8), dimension(2) :: my_array @@ -15,4 +16,5 @@ module cmplxdat data medium_ref_index / (1.d0, 0.d0) / data ref_index_one, ref_index_two / (13.0d0, 21.0d0), (-30.0d0, 43.0d0) / data my_array / (1.0d0, 2.0d0), (-3.0d0, 4.0d0) / + data pi / 3.1415926535897932384626433832795028841971693993751058209749445923078164062d0 / end module cmplxdat diff --git a/numpy/f2py/tests/src/crackfortran/data_with_comments.f b/numpy/f2py/tests/src/crackfortran/data_with_comments.f new file mode 100644 index 000000000000..4128f004e840 --- /dev/null +++ b/numpy/f2py/tests/src/crackfortran/data_with_comments.f @@ -0,0 +1,8 @@ + BLOCK DATA PARAM_INI + COMMON /MYCOM/ MYTAB + INTEGER MYTAB(3) + DATA MYTAB/ + * 0, ! 1 and more commenty stuff + * 4, ! 2 + * 0 / + END diff --git a/numpy/f2py/tests/test_data.py b/numpy/f2py/tests/test_data.py index 3b8ca544ec74..4e5604c006b1 100644 --- a/numpy/f2py/tests/test_data.py +++ b/numpy/f2py/tests/test_data.py @@ -15,6 +15,7 @@ def test_data_stmts(self): assert self.module.cmplxdat.j == 3 assert self.module.cmplxdat.x == 1.5 assert self.module.cmplxdat.y == 2.0 + assert self.module.cmplxdat.pi == 3.1415926535897932384626433832795028841971693993751058209749445923078164062 assert self.module.cmplxdat.medium_ref_index == np.array(1.+0.j) assert np.all(self.module.cmplxdat.z == np.array([3.5, 7.0])) assert np.all(self.module.cmplxdat.my_array == np.array([ 1.+2.j, -3.+4.j])) @@ -26,8 +27,44 @@ def test_crackedlines(self): mod = crackfortran(self.sources) assert mod[0]['vars']['x']['='] == '1.5' assert mod[0]['vars']['y']['='] == '2.0' + assert mod[0]['vars']['pi']['='] == '3.1415926535897932384626433832795028841971693993751058209749445923078164062d0' assert mod[0]['vars']['my_real_array']['='] == '(/1.0d0, 2.0d0, 3.0d0/)' assert mod[0]['vars']['ref_index_one']['='] == '(13.0d0, 21.0d0)' assert mod[0]['vars']['ref_index_two']['='] == '(-30.0d0, 43.0d0)' assert mod[0]['vars']['my_array']['='] == '(/(1.0d0, 2.0d0), (-3.0d0, 4.0d0)/)' assert mod[0]['vars']['z']['='] == '(/3.5, 7.0/)' + +class TestDataF77(util.F2PyTest): + sources = [util.getpath("tests", "src", "crackfortran", "data_common.f")] + + # For gh-23276 + def test_data_stmts(self): + assert self.module.mycom.mydata == 0 + + def test_crackedlines(self): + mod = crackfortran(str(self.sources[0])) + print(mod[0]['vars']) + assert mod[0]['vars']['mydata']['='] == '0' + + +class TestDataMultiplierF77(util.F2PyTest): + sources = [util.getpath("tests", "src", "crackfortran", "data_multiplier.f")] + + # For gh-23276 + def test_data_stmts(self): + assert self.module.mycom.ivar1 == 3 + assert self.module.mycom.ivar2 == 3 + assert self.module.mycom.ivar3 == 2 + assert self.module.mycom.ivar4 == 2 + assert self.module.mycom.evar5 == 0 + + +class TestDataWithCommentsF77(util.F2PyTest): + sources = [util.getpath("tests", "src", "crackfortran", "data_with_comments.f")] + + # For gh-23276 + def test_data_stmts(self): + assert len(self.module.mycom.mytab) == 3 + assert self.module.mycom.mytab[0] == 0 + assert self.module.mycom.mytab[1] == 4 + assert self.module.mycom.mytab[2] == 0 diff --git a/numpy/linalg/setup.py b/numpy/linalg/setup.py index 6f72635ab67f..e357e294f797 100644 --- a/numpy/linalg/setup.py +++ b/numpy/linalg/setup.py @@ -51,7 +51,8 @@ def calc_info(self): # but use the "64_" convention here. info['define_macros'] = [ ('HAVE_BLAS_ILP64', None), - ('BLAS_SYMBOL_SUFFIX', '64_') + ('BLAS_SYMBOL_SUFFIX', '64_'), + ('OPENBLAS_ILP64_NAMING_SCHEME', None), ] self.set_info(**info) diff --git a/numpy/meson.build b/numpy/meson.build index 150257d5b8b3..8da83ce61643 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,130 +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'] -# 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' - if use_ilp64 - _openblas_names = ['openblas64', 'openblas', 'OpenBLAS'] - else - _openblas_names = ['openblas', 'OpenBLAS'] +# Note that we can only use a BLAS which provides a CBLAS interface. So disable +# BLAS completely if CBLAS is not found. + +# 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' endif - blas = dependency(_openblas_names, required: false) -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' +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 + if _name == 'flexiblas' and use_ilp64 + _name = 'flexiblas64' + endif + blas = dependency(_name, modules: ['cblas'] + blas_interface, required: false) 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.') + if blas.found() + break 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 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 @@ -210,35 +172,33 @@ else endif endif -if 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') @@ -265,6 +225,10 @@ python_sources = [ 'py.typed' ] +if blas_name == 'scipy-openblas' + python_sources += ['_distributor_init_local.py'] +endif + py.install_sources( python_sources, subdir: 'numpy' @@ -282,6 +246,7 @@ pure_subdirs = [ '_pyinstaller', '_typing', '_utils', + '_core', 'array_api', 'compat', 'doc', @@ -377,7 +342,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) @@ -391,13 +356,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/numpy/setup.py b/numpy/setup.py index b6f879bcca85..536224a81192 100644 --- a/numpy/setup.py +++ b/numpy/setup.py @@ -7,6 +7,7 @@ def configuration(parent_package='',top_path=None): config.add_subpackage('array_api') config.add_subpackage('compat') config.add_subpackage('core') + config.add_subpackage('_core') config.add_subpackage('distutils') config.add_subpackage('doc') config.add_subpackage('f2py') diff --git a/pavement.py b/pavement.py index 585194f39647..70a5e7657dde 100644 --- a/pavement.py +++ b/pavement.py @@ -38,7 +38,7 @@ #----------------------------------- # Path to the release notes -RELEASE_NOTES = 'doc/source/release/1.26.0-notes.rst' +RELEASE_NOTES = 'doc/source/release/1.26.1-notes.rst' #------------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index c8620c90f4e7..ec8da79d3963 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ requires = [ [project] name = "numpy" -version = "1.26.0" +version = "1.26.1" # TODO: add `license-files` once PEP 639 is accepted (see meson-python#88) license = {file = "LICENSE.txt"} @@ -66,6 +66,7 @@ documentation = "https://numpy.org/doc/" source = "https://github.com/numpy/numpy" download = "https://pypi.org/project/numpy/#files" tracker = "https://github.com/numpy/numpy/issues" +"release notes" = "https://numpy.org/doc/stable/release" [tool.towncrier] # Do no set this since it is hard to import numpy inside the source directory @@ -152,6 +153,7 @@ tracker = "https://github.com/numpy/numpy/issues" skip = "cp36-* cp37-* cp-38* pp37-* pp38-* *-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 @@ -164,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 @@ -174,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]] @@ -199,10 +202,11 @@ cli = 'vendored-meson/meson/meson.py' ".spin/cmds.py:build", ".spin/cmds.py:test", ".spin/cmds.py:mypy", + ".spin/cmds.py:config_openblas", ] "Environments" = [ - ".spin/cmds.py:run", ".spin/cmds.py:ipython", - ".spin/cmds.py:python", ".spin/cmds.py:gdb" + "spin.cmds.meson.run", ".spin/cmds.py:ipython", + ".spin/cmds.py:python", "spin.cmds.meson.gdb" ] "Documentation" = [".spin/cmds.py:docs"] "Metrics" = [".spin/cmds.py:bench"] diff --git a/pyproject.toml.setuppy b/pyproject.toml.setuppy index 0925099ed523..bfb093ba7648 100644 --- a/pyproject.toml.setuppy +++ b/pyproject.toml.setuppy @@ -3,7 +3,7 @@ # to avoid building with Meson (e.g., in the Emscripten/Pyodide CI job) [project] name = "numpy" -version = "1.26.0" +version = "1.26.1" [build-system] requires = [ 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/tools/ci/cirrus_arm.yml b/tools/ci/cirrus_arm.yml index e4e127d2af4e..a28f182ae8ba 100644 --- a/tools/ci/cirrus_arm.yml +++ b/tools/ci/cirrus_arm.yml @@ -22,6 +22,7 @@ modified_clone: &MODIFIED_CLONE linux_aarch64_test_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' compute_engine_instance: image_project: cirrus-images image: family/docker-builder-arm64 @@ -66,6 +67,7 @@ linux_aarch64_test_task: macos_arm64_test_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' depends_on: - linux_aarch64_test macos_instance: @@ -94,7 +96,7 @@ macos_arm64_test_task: RUNNER_OS="macOS" SDKROOT=/Applications/Xcode-14.0.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk - + # NOTE: OpenBLAS is not used in this job; if that's done in the future, ensure # PKG_CONFIG_PATH points to the directory containing the openblas.pc file # that's installed with the cibw_before_build.sh command. @@ -108,8 +110,50 @@ macos_arm64_test_task: pip install -r build_requirements.txt pip install pytest pytest-xdist hypothesis typing_extensions - + spin build -- -Dallow-noblas=true spin test -j auto ccache -s + + +freebsd_test_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' + compute_engine_instance: + image_project: freebsd-org-cloud-dev + image: family/freebsd-13-2 + platform: freebsd + cpu: 1 + memory: 4G + + install_devtools_script: | + pkg install -y git bash ninja ccache + + <<: *MODIFIED_CLONE + + ccache_cache: + folder: .ccache + populate_script: + - mkdir -p .ccache + fingerprint_key: ccache-freebsd + + prepare_env_script: | + # Create a venv (the `source` command needs bash, not the default sh shell) + chsh -s /usr/local/bin/bash + python -m venv .venv + source .venv/bin/activate + # Minimal build and test requirements + python -m pip install -U pip + python -m pip install meson-python Cython pytest hypothesis + + build_script: | + chsh -s /usr/local/bin/bash + source .venv/bin/activate + python -m pip install . --no-build-isolation -v -Csetup-args="-Dallow-noblas=true" + + test_script: | + chsh -s /usr/local/bin/bash + source .venv/bin/activate + cd tools + python -m pytest --pyargs numpy -m "not slow" + ccache -s diff --git a/tools/ci/cirrus_wheels.yml b/tools/ci/cirrus_wheels.yml index 8cb566bc5a33..ea290a8b23c8 100644 --- a/tools/ci/cirrus_wheels.yml +++ b/tools/ci/cirrus_wheels.yml @@ -1,6 +1,6 @@ build_and_store_wheels: &BUILD_AND_STORE_WHEELS install_cibuildwheel_script: - - python -m pip install cibuildwheel==2.15.0 + - python -m pip install cibuildwheel cibuildwheel_script: - cibuildwheel wheels_artifacts: @@ -11,6 +11,7 @@ build_and_store_wheels: &BUILD_AND_STORE_WHEELS ###################################################################### linux_aarch64_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' compute_engine_instance: image_project: cirrus-images image: family/docker-builder-arm64 @@ -41,7 +42,7 @@ linux_aarch64_task: apt update apt install -y python3-venv python-is-python3 gfortran libatlas-base-dev libgfortran5 eatmydata git fetch origin - ./tools/travis-before-install.sh + bash ./tools/wheels/cibw_before_build.sh ${PWD} which python echo $CIRRUS_CHANGE_MESSAGE <<: *BUILD_AND_STORE_WHEELS @@ -52,6 +53,7 @@ linux_aarch64_task: ###################################################################### macosx_arm64_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' macos_instance: image: ghcr.io/cirruslabs/macos-monterey-xcode:14 matrix: @@ -101,6 +103,7 @@ macosx_arm64_task: ###################################################################### wheels_upload_task: + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' # Artifacts don't seem to be persistent from task to task. # Rather than upload wheels at the end of each cibuildwheel run we do a # final upload here. This is because a run may be on different OS for diff --git a/tools/openblas_support.py b/tools/openblas_support.py index 5fe0d662cdcd..170c1948d3be 100644 --- a/tools/openblas_support.py +++ b/tools/openblas_support.py @@ -238,6 +238,9 @@ def get_members(): def make_init(dirname): ''' Create a _distributor_init.py file for OpenBlas + + Obsoleted by the use of delvewheel in wheel building, which + adds an equivalent snippet to numpy/__init__.py, but still useful in CI ''' with open(os.path.join(dirname, '_distributor_init.py'), 'w') as fid: fid.write(textwrap.dedent(""" @@ -246,19 +249,20 @@ def make_init(dirname): Once a DLL is preloaded, its namespace is made available to any subsequent DLL. This file originated in the numpy-wheels repo, and is created as part of the scripts that build the wheel. + ''' import os import glob if os.name == 'nt': - # convention for storing / loading the DLL from - # numpy/.libs/, if present + # load any DLL from numpy/../numpy.libs/, if present try: from ctypes import WinDLL - basedir = os.path.dirname(__file__) except: pass else: - libs_dir = os.path.abspath(os.path.join(basedir, '.libs')) + basedir = os.path.dirname(__file__) + libs_dir = os.path.join(basedir, os.pardir, 'numpy.libs') + libs_dir = os.path.abspath(libs_dir) DLL_filenames = [] if os.path.isdir(libs_dir): for filename in glob.glob(os.path.join(libs_dir, diff --git a/tools/wheels/LICENSE_linux.txt b/tools/wheels/LICENSE_linux.txt index 9ea808afce50..97596fe61f28 100644 --- a/tools/wheels/LICENSE_linux.txt +++ b/tools/wheels/LICENSE_linux.txt @@ -5,10 +5,10 @@ This binary distribution of NumPy also bundles the following software: Name: OpenBLAS -Files: .libs/libopenb*.so +Files: numpy.libs/libopenblas*.so Description: bundled as a dynamically linked library -Availability: https://github.com/xianyi/OpenBLAS/ -License: 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 2011-2014, The OpenBLAS Project All rights reserved. @@ -41,10 +41,10 @@ License: 3-clause BSD Name: LAPACK -Files: .libs/libopenb*.so +Files: numpy.libs/libopenblas*.so Description: bundled in OpenBLAS -Availability: https://github.com/xianyi/OpenBLAS/ -License 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 1992-2013 The University of Tennessee and The University of Tennessee Research Foundation. All rights reserved. @@ -96,10 +96,10 @@ License 3-clause BSD Name: GCC runtime library -Files: .libs/libgfortran*.so +Files: numpy.libs/libgfortran*.so Description: dynamically linked to files compiled with gcc -Availability: https://gcc.gnu.org/viewcvs/gcc/ -License: GPLv3 + runtime exception +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran +License: GPL-3.0-with-GCC-exception Copyright (C) 2002-2017 Free Software Foundation, Inc. Libgfortran is free software; you can redistribute it and/or modify @@ -878,3 +878,25 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . + +Name: libquadmath +Files: numpy.libs/libquadmath*.so +Description: dynamically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath +License: LGPL-2.1-or-later + + GCC Quad-Precision Math Library + Copyright (C) 2010-2019 Free Software Foundation, Inc. + Written by Francois-Xavier Coudert + + This file is part of the libquadmath library. + Libquadmath is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Libquadmath is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html diff --git a/tools/wheels/LICENSE_osx.txt b/tools/wheels/LICENSE_osx.txt index 9a687c3b6b05..dd221a34d49f 100644 --- a/tools/wheels/LICENSE_osx.txt +++ b/tools/wheels/LICENSE_osx.txt @@ -3,12 +3,102 @@ This binary distribution of NumPy also bundles the following software: +Name: OpenBLAS +Files: numpy/.dylibs/libopenblas*.so +Description: bundled as a dynamically linked library +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution + Copyright (c) 2011-2014, The OpenBLAS Project + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. Neither the name of the OpenBLAS project nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Name: LAPACK +Files: numpy/.dylibs/libopenblas*.so +Description: bundled in OpenBLAS +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution + Copyright (c) 1992-2013 The University of Tennessee and The University + of Tennessee Research Foundation. All rights + reserved. + Copyright (c) 2000-2013 The University of California Berkeley. All + rights reserved. + Copyright (c) 2006-2013 The University of Colorado Denver. All rights + reserved. + + $COPYRIGHT$ + + Additional copyrights may follow + + $HEADER$ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer listed + in this license in the documentation and/or other materials + provided with the distribution. + + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + The copyright holders provide no reassurances that the source code + provided does not infringe any patent, copyright, or any other + intellectual property rights of third parties. The copyright holders + disclaim any liability to any recipient for claims brought against + recipient by any third party for infringement of that parties + intellectual property rights. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Name: GCC runtime library -Files: .dylibs/* +Files: numpy/.dylibs/libgfortran*, numpy/.dylibs/libgcc* Description: dynamically linked to files compiled with gcc -Availability: https://gcc.gnu.org/viewcvs/gcc/ -License: GPLv3 + runtime exception +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran +License: GPL-3.0-with-GCC-exception Copyright (C) 2002-2017 Free Software Foundation, Inc. Libgfortran is free software; you can redistribute it and/or modify @@ -787,3 +877,25 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . + +Name: libquadmath +Files: numpy/.dylibs/libquadmath*.so +Description: dynamically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath +License: LGPL-2.1-or-later + + GCC Quad-Precision Math Library + Copyright (C) 2010-2019 Free Software Foundation, Inc. + Written by Francois-Xavier Coudert + + This file is part of the libquadmath library. + Libquadmath is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Libquadmath is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html diff --git a/tools/wheels/LICENSE_win32.txt b/tools/wheels/LICENSE_win32.txt index 1014d77cd3ed..ef954a6ea781 100644 --- a/tools/wheels/LICENSE_win32.txt +++ b/tools/wheels/LICENSE_win32.txt @@ -5,10 +5,10 @@ This binary distribution of NumPy also bundles the following software: Name: OpenBLAS -Files: extra-dll\libopenb*.dll +Files: numpy.libs\libopenblas*.dll Description: bundled as a dynamically linked library -Availability: https://github.com/xianyi/OpenBLAS/ -License: 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 2011-2014, The OpenBLAS Project All rights reserved. @@ -41,10 +41,10 @@ License: 3-clause BSD Name: LAPACK -Files: extra-dll\libopenb*.dll +Files: numpy.libs\libopenblas*.dll Description: bundled in OpenBLAS -Availability: https://github.com/xianyi/OpenBLAS/ -License 3-clause BSD +Availability: https://github.com/OpenMathLib/OpenBLAS/ +License: BSD-3-Clause-Attribution Copyright (c) 1992-2013 The University of Tennessee and The University of Tennessee Research Foundation. All rights reserved. @@ -96,10 +96,10 @@ License 3-clause BSD Name: GCC runtime library -Files: extra-dll\*.dll -Description: statically linked, in DLL files compiled with gfortran only -Availability: https://gcc.gnu.org/viewcvs/gcc/ -License: GPLv3 + runtime exception +Files: numpy.libs\libopenblas*.dll +Description: statically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran +License: GPL-3.0-with-GCC-exception Copyright (C) 2002-2017 Free Software Foundation, Inc. Libgfortran is free software; you can redistribute it and/or modify @@ -121,64 +121,6 @@ License: GPLv3 + runtime exception see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . - -Name: Microsoft Visual C++ Runtime Files -Files: extra-dll\msvcp140.dll -License: MSVC - https://www.visualstudio.com/license-terms/distributable-code-microsoft-visual-studio-2015-rc-microsoft-visual-studio-2015-sdk-rc-includes-utilities-buildserver-files/#visual-c-runtime - - Subject to the License Terms for the software, you may copy and - distribute with your program any of the files within the followng - folder and its subfolders except as noted below. You may not modify - these files. - - C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist - - You may not distribute the contents of the following folders: - - C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\debug_nonredist - C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\onecore\debug_nonredist - - Subject to the License Terms for the software, you may copy and - distribute the following files with your program in your program’s - application local folder or by deploying them into the Global - Assembly Cache (GAC): - - VC\atlmfc\lib\mfcmifc80.dll - VC\atlmfc\lib\amd64\mfcmifc80.dll - - -Name: Microsoft Visual C++ Runtime Files -Files: extra-dll\msvc*90.dll, extra-dll\Microsoft.VC90.CRT.manifest -License: MSVC - For your convenience, we have provided the following folders for - use when redistributing VC++ runtime files. Subject to the license - terms for the software, you may redistribute the folder - (unmodified) in the application local folder as a sub-folder with - no change to the folder name. You may also redistribute all the - files (*.dll and *.manifest) within a folder, listed below the - folder for your convenience, as an entire set. - - \VC\redist\x86\Microsoft.VC90.ATL\ - atl90.dll - Microsoft.VC90.ATL.manifest - \VC\redist\ia64\Microsoft.VC90.ATL\ - atl90.dll - Microsoft.VC90.ATL.manifest - \VC\redist\amd64\Microsoft.VC90.ATL\ - atl90.dll - Microsoft.VC90.ATL.manifest - \VC\redist\x86\Microsoft.VC90.CRT\ - msvcm90.dll - msvcp90.dll - msvcr90.dll - Microsoft.VC90.CRT.manifest - \VC\redist\ia64\Microsoft.VC90.CRT\ - msvcm90.dll - msvcp90.dll - msvcr90.dll - Microsoft.VC90.CRT.manifest - ---- Full text of license texts referred to above follows (that they are @@ -935,4 +877,26 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. + +Name: libquadmath +Files: numpy.libs\libopenb*.dll +Description: statically linked to files compiled with gcc +Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath +License: LGPL-2.1-or-later + + GCC Quad-Precision Math Library + Copyright (C) 2010-2019 Free Software Foundation, Inc. + Written by Francois-Xavier Coudert + + This file is part of the libquadmath library. + Libquadmath is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Libquadmath is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html diff --git a/tools/wheels/cibw_before_build.sh b/tools/wheels/cibw_before_build.sh index 372b25af09b8..23471a43285e 100644 --- a/tools/wheels/cibw_before_build.sh +++ b/tools/wheels/cibw_before_build.sh @@ -4,6 +4,7 @@ PROJECT_DIR="$1" PLATFORM=$(PYTHONPATH=tools python -c "import openblas_support; print(openblas_support.get_plat())") # Update license +cat $PROJECT_DIR/LICENSES_bundled.txt >> $PROJECT_DIR/LICENSE.txt if [[ $RUNNER_OS == "Linux" ]] ; then cat $PROJECT_DIR/tools/wheels/LICENSE_linux.txt >> $PROJECT_DIR/LICENSE.txt elif [[ $RUNNER_OS == "macOS" ]]; then @@ -36,7 +37,6 @@ elif [[ $RUNNER_OS == "Windows" ]]; then # this location you need to alter that script. mkdir -p /c/opt/openblas/openblas_dll - PYTHONPATH=tools python -c "import openblas_support; openblas_support.make_init('numpy')" mkdir -p /c/opt/32/lib/pkgconfig mkdir -p /c/opt/64/lib/pkgconfig target=$(python -c "import tools.openblas_support as obs; plat=obs.get_plat(); ilp64=obs.get_ilp64(); target=f'openblas_{plat}.zip'; obs.download_openblas(target, plat, ilp64);print(target)") diff --git a/vendored-meson/meson b/vendored-meson/meson index 82d41db3d4b5..66ba7dbbfe28 160000 --- a/vendored-meson/meson +++ b/vendored-meson/meson @@ -1 +1 @@ -Subproject commit 82d41db3d4b51124c5f138078c079b8eb62ecdeb +Subproject commit 66ba7dbbfe2838983f65ad8fe16da1535ebf5b9d