summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf Gommers <ralf.gommers@gmail.com>2022-11-23 23:40:23 +0100
committerRalf Gommers <ralf.gommers@gmail.com>2022-11-25 12:37:46 +0100
commit4002a7d421ff10780c28a3643683af7a9754f87f (patch)
treea06d4c10642d1c93d552f80f1e90f393c9953c18
parent632f573f12c641990bfac24cf4df435804340a7f (diff)
downloadnumpy-4002a7d421ff10780c28a3643683af7a9754f87f.tar.gz
BLD: enable building NumPy with Meson
This enables building with NumPy on Linux and macOS. Windows support should be complete to, but is untested as of now and may need a few tweaks. This contains: - A set of `meson.build` files and related code generation script tweaks, header templates, etc. - One CI job on Linux - Basic docs on using Meson to build NumPy (not yet integrated in the html docs, it's too early for that - this is for early adopters right now). The build should be complete, with the major exception of SIMD support. The full test suite passes. See gh-22546 for the tracking issue with detailed notes on the plan for switching NumPy to Meson as its build system. Co-authored-by: Stefan van der Walt <stefanv@berkeley.edu>
-rw-r--r--.github/workflows/linux_meson.yml60
-rw-r--r--.gitignore5
-rw-r--r--build_requirements.txt5
-rw-r--r--building_with_meson.md65
-rwxr-xr-xdev.py19
-rw-r--r--doc/source/f2py/buildtools/meson.rst6
-rw-r--r--doc/source/f2py/code/meson.build32
-rw-r--r--doc/source/f2py/code/meson_upd.build37
-rw-r--r--environment.yml4
-rw-r--r--generate_version.py40
-rw-r--r--meson.build64
-rw-r--r--meson_options.txt13
-rw-r--r--numpy/__config__.py.in134
-rw-r--r--numpy/_build_utils/__init__.py22
-rw-r--r--numpy/_build_utils/gcc_build_bitness.py21
-rw-r--r--numpy/_build_utils/process_src_template.py67
-rw-r--r--numpy/_build_utils/setup.py12
-rwxr-xr-xnumpy/_build_utils/tempita.py62
-rw-r--r--numpy/core/check_longdouble.c15
-rw-r--r--numpy/core/code_generators/genapi.py22
-rw-r--r--numpy/core/code_generators/generate_numpy_api.py30
-rw-r--r--numpy/core/code_generators/generate_ufunc_api.py25
-rw-r--r--numpy/core/code_generators/generate_umath.py28
-rw-r--r--numpy/core/code_generators/generate_umath_doc.py19
-rw-r--r--numpy/core/code_generators/numpy_api.py18
-rw-r--r--numpy/core/code_generators/verify_c_api_version.py66
-rw-r--r--numpy/core/config.h.in118
-rw-r--r--numpy/core/include/meson.build51
-rw-r--r--numpy/core/include/numpy/_numpyconfig.h.in36
-rw-r--r--numpy/core/meson.build929
-rw-r--r--numpy/core/setup.py6
-rw-r--r--numpy/fft/meson.build33
-rw-r--r--numpy/linalg/meson.build56
-rw-r--r--numpy/meson.build154
-rw-r--r--numpy/random/meson.build164
-rw-r--r--numpy/tests/test_public_api.py1
-rw-r--r--numpy/version.py12
-rw-r--r--pyproject.toml62
-rw-r--r--tools/check_installed_files.py86
39 files changed, 2549 insertions, 50 deletions
diff --git a/.github/workflows/linux_meson.yml b/.github/workflows/linux_meson.yml
new file mode 100644
index 000000000..9b21820fb
--- /dev/null
+++ b/.github/workflows/linux_meson.yml
@@ -0,0 +1,60 @@
+name: Test Meson build (Linux)
+
+on:
+ push:
+ branches:
+ - main
+ - maintenance/**
+ pull_request:
+ branches:
+ - main
+ - maintenance/**
+
+defaults:
+ run:
+ shell: bash
+
+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_devpy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: recursive
+ fetch-depth: 0
+ - uses: actions/setup-python@v4
+ with:
+ python-version: ${{ env.PYTHON_VERSION }}
+ - name: Install dependencies
+ run: |
+ pip install -r build_requirements.txt
+ sudo apt-get install -y libopenblas-serial-dev
+ - name: Build
+ shell: 'script -q -e -c "bash --noprofile --norc -eo pipefail {0}"'
+ env:
+ TERM: xterm-256color
+ run:
+ ./dev.py build -- --werror
+ - name: Check build-internal dependencies
+ run:
+ ninja -C build -t missingdeps
+ - name: Check installed test and stub files
+ run:
+ python tools/check_installed_files.py $(find ./build-install -path '*/site-packages/numpy')
+ - name: Test
+ shell: 'script -q -e -c "bash --noprofile --norc -eo pipefail {0}"'
+ env:
+ TERM: xterm-256color
+ run: |
+ pip install pytest hypothesis typing_extensions
+ ./dev.py test
diff --git a/.gitignore b/.gitignore
index e2ee6a013..f2a0980a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,8 +61,11 @@ GTAGS
# Python files #
################
-# setup.py working directory
+# meson build/installation directories
build
+build-install
+# meson python output
+.mesonpy-native-file.ini
# sphinx build directory
_build
# setup.py dist directory
diff --git a/build_requirements.txt b/build_requirements.txt
new file mode 100644
index 000000000..fccc2e4fa
--- /dev/null
+++ b/build_requirements.txt
@@ -0,0 +1,5 @@
+meson-python>=0.10.0
+Cython>=0.29.30,<3.0
+wheel==0.37.0
+ninja
+git+https://github.com/scientific-python/devpy
diff --git a/building_with_meson.md b/building_with_meson.md
new file mode 100644
index 000000000..dd1ca1d94
--- /dev/null
+++ b/building_with_meson.md
@@ -0,0 +1,65 @@
+# Building with Meson
+
+_Note: this is for early adopters. It has been tested on Linux and macOS, and
+with Python 3.9-3.12. Windows will be tested soon. There is one CI job to keep
+the build stable. This may have rough edges, please open an issue if you run
+into a problem._
+
+### Developer build
+
+**Install build tools:** Use one of:
+
+- `mamba create -f environment.yml
+- `pip install -r build_requirements.txt # also make sure you have pkg-config and the usual system dependencies for NumPy`
+
+**Compile and install:** `./dev.py build`
+
+This builds in the `build/` directory, and installs into the `build-install` directory.
+
+Then run the test suite or a shell via `dev.py`:
+```
+./dev.py test
+./dev.py ipython
+```
+
+Alternatively, to use the package, add it to your `PYTHONPATH`:
+```
+export PYTHONPATH=${PWD}/build/lib64/python3.10/site-packages # may vary
+pytest --pyargs numpy
+```
+
+
+### pip install
+
+Note that `pip` will use the default build system, which is (as of now) still
+`numpy.distutils`. In order to switch that default to Meson, uncomment the
+`build-backend = "mesonpy"` line at the top of `pyproject.toml`.
+
+After that is done, `pip install .` or `pip install --no-build-isolation .`
+will work as expected. As does building an sdist or wheel with `python -m build`.
+Note, however, that `pip install -e .` (in-place developer install) does not!
+Use `dev.py` instead (see above).
+
+
+
+### Workaround for a hiccup on Fedora
+
+- Fedora does not distribute `openblas.pc`. Install the following file in `~/lib/pkgconfig/openblas.pc`:
+
+```
+prefix=/usr
+includedir=${prefix}/include
+libdir=${prefix}/lib64
+
+Name: openblas
+Description: OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version
+Version: 0.3.19
+Cflags: -I${includedir}/openblas
+Libs: -L${libdir} -lopenblas
+```
+
+Then build with:
+
+```
+./dev.py build -- -Dpkg_config_path=${HOME}/lib/pkgconfig
+```
diff --git a/dev.py b/dev.py
new file mode 100755
index 000000000..205014938
--- /dev/null
+++ b/dev.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+#
+# Example stub for running `python -m dev.py`
+#
+# Copy this into your project root.
+
+import os
+import sys
+import runpy
+
+sys.path.remove(os.path.abspath(os.path.dirname(sys.argv[0])))
+try:
+ runpy.run_module("devpy", run_name="__main__")
+except ImportError:
+ print("Cannot import devpy; please install it using")
+ print()
+ print(" pip install git+https://github.com/scientific-python/devpy")
+ print()
+ sys.exit(1)
diff --git a/doc/source/f2py/buildtools/meson.rst b/doc/source/f2py/buildtools/meson.rst
index 7edc6722f..6b4392880 100644
--- a/doc/source/f2py/buildtools/meson.rst
+++ b/doc/source/f2py/buildtools/meson.rst
@@ -28,8 +28,7 @@ build system like ``meson``. We will acquire this by:
Now, consider the following ``meson.build`` file for the ``fib`` and ``scalar``
examples from :ref:`f2py-getting-started` section:
-.. literalinclude:: ./../code/meson.build
- :language: meson
+.. literalinclude:: ../code/meson.build
At this point the build will complete, but the import will fail:
@@ -93,8 +92,7 @@ for reasons discussed in :ref:`f2py-bldsys`.
However, we can augment our workflow in a straightforward to take into account
files for which the outputs are known when the build system is set up.
-.. literalinclude:: ./../code/meson_upd.build
- :language: meson
+.. literalinclude:: ../code/meson_upd.build
This can be compiled and run as before.
diff --git a/doc/source/f2py/code/meson.build b/doc/source/f2py/code/meson.build
index 04276a176..1d409f2fb 100644
--- a/doc/source/f2py/code/meson.build
+++ b/doc/source/f2py/code/meson.build
@@ -1,31 +1,35 @@
project('f2py_examples', 'c',
version : '0.1',
- default_options : ['warning_level=2'])
+ license: 'BSD-3',
+ meson_version: '>=0.64.0',
+ default_options : ['warning_level=2'],
+)
add_languages('fortran')
py_mod = import('python')
-py3 = py_mod.find_installation('python3')
-py3_dep = py3.dependency()
-message(py3.path())
-message(py3.get_install_dir())
+py = py_mod.find_installation(pure: false)
+py_dep = py.dependency()
-incdir_numpy = run_command(py3,
+incdir_numpy = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'],
check : true
).stdout().strip()
-incdir_f2py = run_command(py3,
+incdir_f2py = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy.f2py; print(numpy.f2py.get_include())'],
check : true
).stdout().strip()
inc_np = include_directories(incdir_numpy, incdir_f2py)
-py3.extension_module('fib2',
- 'fib1.f',
- 'fib2module.c',
- incdir_f2py+'/fortranobject.c',
- include_directories: inc_np,
- dependencies : py3_dep,
- install : true) \ No newline at end of file
+py.extension_module('fib2',
+ [
+ 'fib1.f',
+ 'fib2module.c', # note: this assumes f2py was manually run before!
+ ],
+ incdir_f2py / 'fortranobject.c',
+ include_directories: inc_np,
+ dependencies : py_dep,
+ install : true
+)
diff --git a/doc/source/f2py/code/meson_upd.build b/doc/source/f2py/code/meson_upd.build
index 44d69d182..5e4b13bae 100644
--- a/doc/source/f2py/code/meson_upd.build
+++ b/doc/source/f2py/code/meson_upd.build
@@ -1,37 +1,38 @@
project('f2py_examples', 'c',
version : '0.1',
- default_options : ['warning_level=2'])
+ license: 'BSD-3',
+ meson_version: '>=0.64.0',
+ default_options : ['warning_level=2'],
+)
add_languages('fortran')
py_mod = import('python')
-py3 = py_mod.find_installation('python3')
-py3_dep = py3.dependency()
-message(py3.path())
-message(py3.get_install_dir())
+py = py_mod.find_installation(pure: false)
+py_dep = py.dependency()
-incdir_numpy = run_command(py3,
+incdir_numpy = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'],
check : true
).stdout().strip()
-incdir_f2py = run_command(py3,
+incdir_f2py = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy.f2py; print(numpy.f2py.get_include())'],
check : true
).stdout().strip()
fibby_source = custom_target('fibbymodule.c',
- input : ['fib1.f'], # .f so no F90 wrappers
- output : ['fibbymodule.c', 'fibby-f2pywrappers.f'],
- command : [ py3, '-m', 'numpy.f2py', '@INPUT@',
- '-m', 'fibby', '--lower'])
+ input : ['fib1.f'], # .f so no F90 wrappers
+ output : ['fibbymodule.c', 'fibby-f2pywrappers.f'],
+ command : [py, '-m', 'numpy.f2py', '@INPUT@', '-m', 'fibby', '--lower']
+)
inc_np = include_directories(incdir_numpy, incdir_f2py)
-py3.extension_module('fibby',
- 'fib1.f',
- fibby_source,
- incdir_f2py+'/fortranobject.c',
- include_directories: inc_np,
- dependencies : py3_dep,
- install : true)
+py.extension_module('fibby',
+ ['fib1.f', fibby_source],
+ incdir_f2py / 'fortranobject.c',
+ include_directories: inc_np,
+ dependencies : py_dep,
+ install : true
+)
diff --git a/environment.yml b/environment.yml
index b99fa1256..8dbb1f80d 100644
--- a/environment.yml
+++ b/environment.yml
@@ -13,6 +13,10 @@ dependencies:
- openblas
- nomkl
- setuptools=59.2.0
+ - meson >= 0.64.0
+ - ninja
+ - pkg-config # note: not available on Windows, comment out this line
+ - meson-python
# For testing
- pytest
- pytest-cov
diff --git a/generate_version.py b/generate_version.py
new file mode 100644
index 000000000..b3c8a3978
--- /dev/null
+++ b/generate_version.py
@@ -0,0 +1,40 @@
+# Note: This file has to live next to versioneer.py or it will not work
+import argparse
+import os
+
+import versioneer
+
+
+def write_version_info(path):
+ vinfo = versioneer.get_versions()
+ full_version = vinfo['version']
+ git_revision = vinfo['full-revisionid']
+
+ if os.environ.get("MESON_DIST_ROOT"):
+ path = os.path.join(os.environ.get("MESON_DIST_ROOT"), path)
+
+ with open(path, "w") as f:
+ f.write("def get_versions():\n")
+ f.write(" return {\n")
+ f.write(f" 'full-revisionid': '{git_revision}',\n")
+ f.write(f" 'version': '{full_version}'\n")
+ f.write("}")
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-o", "--outfile", type=str, help="Path to write version info to"
+ )
+ args = parser.parse_args()
+
+ if not args.outfile.endswith(".py"):
+ raise ValueError(
+ f"Output file must be a Python file. "
+ f"Got: {args.outfile} as filename instead"
+ )
+
+ write_version_info(args.outfile)
+
+
+main()
diff --git a/meson.build b/meson.build
new file mode 100644
index 000000000..2a1a40384
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,64 @@
+project(
+ 'NumPy',
+ 'c', 'cpp', 'cython',
+ # Note that the git commit hash cannot be added dynamically here
+ # It is dynamically added upon import by versioneer
+ # See `numpy/__init__.py`
+ version: '1.24.0.dev0',
+ license: 'BSD-3',
+ meson_version: '>= 0.64.0',
+ default_options: [
+ 'buildtype=debugoptimized',
+ 'c_std=c99',
+ 'cpp_std=c++14',
+ 'blas=openblas',
+ 'lapack=openblas',
+ 'pkgconfig.relocatable=true',
+ ],
+)
+
+fs = import('fs')
+
+cc = meson.get_compiler('c')
+cpp = meson.get_compiler('cpp')
+
+# Check compiler is recent enough (see the SciPy Toolchain Roadmap for details)
+if cc.get_id() == 'gcc'
+ if not cc.version().version_compare('>=8.4')
+ error('NumPy requires GCC >= 8.4')
+ endif
+elif cc.get_id() == 'msvc'
+ if not cc.version().version_compare('>=19.20')
+ error('NumPy requires at least vc142 (default with Visual Studio 2019) ' + \
+ 'when building with MSVC')
+ endif
+endif
+
+# https://mesonbuild.com/Python-module.html
+py_mod = import('python')
+py = py_mod.find_installation(pure: false)
+py_dep = py.dependency()
+
+if not cc.has_header('Python.h', dependencies: py_dep)
+ error('Cannot compile `Python.h`. Perhaps you need to install python-dev|python-devel')
+endif
+
+# Generate version number. Note that this will not (yet) update the version
+# number seen by pip or reflected in wheel filenames. See
+# https://github.com/mesonbuild/meson-python/issues/159 for that.
+versioneer = files('generate_version.py')
+if fs.exists('_version_meson.py')
+ py.install_sources('_version_meson.py', subdir: 'numpy')
+else
+ custom_target('write_version_file',
+ output: '_version_meson.py',
+ command: [py, versioneer, '-o', '@OUTPUT@'],
+ build_by_default: true,
+ build_always_stale: true,
+ install: true,
+ install_dir: py.get_install_dir() / 'numpy'
+ )
+ meson.add_dist_script(py, versioneer, '-o', '_version_meson.py')
+endif
+
+subdir('numpy')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 000000000..f53432def
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,13 @@
+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('disable-svml', type: 'boolean', value: 'false',
+ description: 'Disable building against SVML')
+option('disable-threading', type: 'boolean', value: 'false',
+ description: 'Disable threading support (see `NPY_ALLOW_THREADS` docs)')
+# TODO: flip value to 'false' once we have `npy_cpu_dispatch_config.h` & co.
+option('disable-simd-optimizations', type: 'boolean', value: 'true',
+ description: 'Disable SIMD features beyond the baseline ones')
+option('relaxed-strides-debug', type: 'boolean', value: 'false',
+ description: 'Enable relaxed strides debug mode (see `NPY_RELAXED_STRIDES_DEBUG` docs)')
diff --git a/numpy/__config__.py.in b/numpy/__config__.py.in
new file mode 100644
index 000000000..cda615904
--- /dev/null
+++ b/numpy/__config__.py.in
@@ -0,0 +1,134 @@
+# This file is generated by numpy's build process
+# It contains system_info results at the time of building this package.
+__all__ = ["get_info", "show"]
+
+import os
+import sys
+
+extra_dll_dir = os.path.join(os.path.dirname(__file__), '.libs')
+
+if sys.platform == 'win32' and os.path.isdir(extra_dll_dir):
+ os.add_dll_directory(extra_dll_dir)
+
+blas_armpl_info={}
+blas_mkl_info={}
+blis_info={}
+openblas_info={}
+accelerate_info={}
+atlas_3_10_blas_threads_info={}
+atlas_3_10_blas_info={}
+atlas_blas_threads_info={}
+atlas_blas_info={}
+blas_info={}
+blas_src_info={}
+blas_opt_info={}
+lapack_armpl_info={}
+lapack_mkl_info={}
+openblas_lapack_info={}
+openblas_clapack_info={}
+flame_info={}
+atlas_3_10_threads_info={}
+atlas_3_10_info={}
+atlas_threads_info={}
+atlas_info={}
+lapack_info={}
+lapack_src_info={}
+lapack_opt_info={}
+numpy_linalg_lapack_lite={}
+
+def get_info(name):
+ g = globals()
+ return g.get(name, g.get(name + "_info", {}))
+
+def show():
+ """
+ Show libraries in the system on which NumPy was built.
+
+ Print information about various resources (libraries, library
+ directories, include directories, etc.) in the system on which
+ NumPy was built.
+
+ See Also
+ --------
+ get_include : Returns the directory containing NumPy C
+ header files.
+
+ Notes
+ -----
+ 1. Classes specifying the information to be printed are defined
+ in the `numpy.distutils.system_info` module.
+
+ Information may include:
+
+ * ``language``: language used to write the libraries (mostly
+ C or f77)
+ * ``libraries``: names of libraries found in the system
+ * ``library_dirs``: directories containing the libraries
+ * ``include_dirs``: directories containing library header files
+ * ``src_dirs``: directories containing library source files
+ * ``define_macros``: preprocessor macros used by
+ ``distutils.setup``
+ * ``baseline``: minimum CPU features required
+ * ``found``: dispatched features supported in the system
+ * ``not found``: dispatched features that are not supported
+ in the system
+
+ 2. NumPy BLAS/LAPACK Installation Notes
+
+ Installing a numpy wheel (``pip install numpy`` or force it
+ via ``pip install numpy --only-binary :numpy: numpy``) includes
+ an OpenBLAS implementation of the BLAS and LAPACK linear algebra
+ APIs. In this case, ``library_dirs`` reports the original build
+ time configuration as compiled with gcc/gfortran; at run time
+ the OpenBLAS library is in
+ ``site-packages/numpy.libs/`` (linux), or
+ ``site-packages/numpy/.dylibs/`` (macOS), or
+ ``site-packages/numpy/.libs/`` (windows).
+
+ Installing numpy from source
+ (``pip install numpy --no-binary numpy``) searches for BLAS and
+ LAPACK dynamic link libraries at build time as influenced by
+ environment variables NPY_BLAS_LIBS, NPY_CBLAS_LIBS, and
+ NPY_LAPACK_LIBS; or NPY_BLAS_ORDER and NPY_LAPACK_ORDER;
+ or the optional file ``~/.numpy-site.cfg``.
+ NumPy remembers those locations and expects to load the same
+ libraries at run-time.
+ In NumPy 1.21+ on macOS, 'accelerate' (Apple's Accelerate BLAS
+ library) is in the default build-time search order after
+ 'openblas'.
+
+ Examples
+ --------
+ >>> import numpy as np
+ >>> np.show_config()
+ blas_opt_info:
+ language = c
+ define_macros = [('HAVE_CBLAS', None)]
+ libraries = ['openblas', 'openblas']
+ library_dirs = ['/usr/local/lib']
+ """
+ from numpy.core._multiarray_umath import (
+ __cpu_features__, __cpu_baseline__, __cpu_dispatch__
+ )
+ for name,info_dict in globals().items():
+ if name[0] == "_" or type(info_dict) is not type({}): continue
+ print(name + ":")
+ if not info_dict:
+ print(" NOT AVAILABLE")
+ for k,v in info_dict.items():
+ v = str(v)
+ if k == "sources" and len(v) > 200:
+ v = v[:60] + " ...\n... " + v[-60:]
+ print(" %s = %s" % (k,v))
+
+ features_found, features_not_found = [], []
+ for feature in __cpu_dispatch__:
+ if __cpu_features__[feature]:
+ features_found.append(feature)
+ else:
+ features_not_found.append(feature)
+
+ print("Supported SIMD extensions in this NumPy install:")
+ print(" baseline = %s" % (','.join(__cpu_baseline__)))
+ print(" found = %s" % (','.join(features_found)))
+ print(" not found = %s" % (','.join(features_not_found)))
diff --git a/numpy/_build_utils/__init__.py b/numpy/_build_utils/__init__.py
new file mode 100644
index 000000000..ac4908957
--- /dev/null
+++ b/numpy/_build_utils/__init__.py
@@ -0,0 +1,22 @@
+# Don't use the deprecated NumPy C API. Define this to a fixed version
+# instead of NPY_API_VERSION in order not to break compilation for
+# released SciPy versions when NumPy introduces a new deprecation. Use
+# in setup.py::
+#
+# config.add_extension('_name', sources=['source_fname'], **numpy_nodepr_api)
+#
+numpy_nodepr_api = dict(
+ define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_9_API_VERSION")]
+)
+
+
+def import_file(folder, module_name):
+ """Import a file directly, avoiding importing scipy"""
+ import importlib
+ import pathlib
+
+ fname = pathlib.Path(folder) / f'{module_name}.py'
+ spec = importlib.util.spec_from_file_location(module_name, str(fname))
+ module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(module)
+ return module
diff --git a/numpy/_build_utils/gcc_build_bitness.py b/numpy/_build_utils/gcc_build_bitness.py
new file mode 100644
index 000000000..fcad237e9
--- /dev/null
+++ b/numpy/_build_utils/gcc_build_bitness.py
@@ -0,0 +1,21 @@
+#!python
+""" Detect bitness (32 or 64) of Mingw-w64 gcc build target on Windows.
+"""
+
+import re
+from subprocess import run, PIPE
+
+
+def main():
+ res = run(['gcc', '-v'], check=True, text=True, capture_output=True)
+ target = re.search(r'^Target: (.*)$', res.stderr, flags=re.M).groups()[0]
+ if target.startswith('i686'):
+ print('32')
+ elif target.startswith('x86_64'):
+ print('64')
+ else:
+ raise RuntimeError('Could not detect Mingw-w64 bitness')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/numpy/_build_utils/process_src_template.py b/numpy/_build_utils/process_src_template.py
new file mode 100644
index 000000000..4a0915e25
--- /dev/null
+++ b/numpy/_build_utils/process_src_template.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+import sys
+import os
+import argparse
+import importlib.util
+
+
+def get_processor():
+ # Convoluted because we can't import from numpy.distutils
+ # (numpy is not yet built)
+ conv_template_path = os.path.join(
+ os.path.dirname(__file__),
+ '..', 'distutils', 'conv_template.py'
+ )
+ spec = importlib.util.spec_from_file_location(
+ 'conv_template', conv_template_path
+ )
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ return mod.process_file
+
+
+def process_and_write_file(fromfile, outfile):
+ """Process tempita templated file and write out the result.
+
+ The template file is expected to end in `.src`
+ (e.g., `.c.src` or `.h.src`).
+ Processing `npy_somefile.c.src` generates `npy_somefile.c`.
+
+ """
+ process_file = get_processor()
+ content = process_file(fromfile)
+ with open(outfile, 'w') as f:
+ f.write(content)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "infile",
+ type=str,
+ help="Path to the input file"
+ )
+ parser.add_argument(
+ "-o",
+ "--outfile",
+ type=str,
+ help="Path to the output file"
+ )
+ parser.add_argument(
+ "-i",
+ "--ignore",
+ type=str,
+ help="An ignored input - may be useful to add a "
+ "dependency between custom targets",
+ )
+ args = parser.parse_args()
+
+ if not args.infile.endswith('.src'):
+ raise ValueError(f"Unexpected extension: {args.infile}")
+
+ outfile_abs = os.path.join(os.getcwd(), args.outfile)
+ process_and_write_file(args.infile, outfile_abs)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/numpy/_build_utils/setup.py b/numpy/_build_utils/setup.py
new file mode 100644
index 000000000..73a8f2fff
--- /dev/null
+++ b/numpy/_build_utils/setup.py
@@ -0,0 +1,12 @@
+def configuration(parent_package='', top_path=None):
+ from numpy.distutils.misc_util import Configuration
+
+ config = Configuration('_build_utils', parent_package, top_path)
+ config.add_data_dir('tests')
+ return config
+
+
+if __name__ == '__main__':
+ from numpy.distutils.core import setup
+
+ setup(**configuration(top_path='').todict())
diff --git a/numpy/_build_utils/tempita.py b/numpy/_build_utils/tempita.py
new file mode 100755
index 000000000..3bcc789c5
--- /dev/null
+++ b/numpy/_build_utils/tempita.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+import sys
+import os
+import argparse
+
+from Cython import Tempita as tempita
+
+# XXX: If this import ever fails (does it really?), vendor either
+# cython.tempita or numpy/npy_tempita.
+
+
+def process_tempita(fromfile, outfile=None):
+ """Process tempita templated file and write out the result.
+
+ The template file is expected to end in `.c.in` or `.pyx.in`:
+ E.g. processing `template.c.in` generates `template.c`.
+
+ """
+ if outfile is None:
+ # We're dealing with a distutils build here, write in-place
+ outfile = os.path.splitext(fromfile)[0]
+
+ from_filename = tempita.Template.from_filename
+ template = from_filename(fromfile, encoding=sys.getdefaultencoding())
+
+ content = template.substitute()
+
+ with open(outfile, 'w') as f:
+ f.write(content)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "infile",
+ type=str,
+ help="Path to the input file"
+ )
+ parser.add_argument(
+ "-o",
+ "--outfile",
+ type=str,
+ help="Path to the output file"
+ )
+ parser.add_argument(
+ "-i",
+ "--ignore",
+ type=str,
+ help="An ignored input - may be useful to add a "
+ "dependency between custom targets",
+ )
+ args = parser.parse_args()
+
+ if not args.infile.endswith('.in'):
+ raise ValueError(f"Unexpected extension: {args.infile}")
+
+ outfile_abs = os.path.join(os.getcwd(), args.outfile)
+ process_tempita(args.infile, outfile_abs)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/numpy/core/check_longdouble.c b/numpy/core/check_longdouble.c
new file mode 100644
index 000000000..756ef3fc6
--- /dev/null
+++ b/numpy/core/check_longdouble.c
@@ -0,0 +1,15 @@
+/* "before" is 16 bytes to ensure there's no padding between it and "x".
+ * We're not expecting any "long double" bigger than 16 bytes or with
+ * alignment requirements stricter than 16 bytes. */
+typedef long double test_type;
+
+struct {
+ char before[16];
+ test_type x;
+ char after[8];
+} foo = {
+ { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\001', '\043', '\105', '\147', '\211', '\253', '\315', '\357' },
+ -123456789.0,
+ { '\376', '\334', '\272', '\230', '\166', '\124', '\062', '\020' }
+};
diff --git a/numpy/core/code_generators/genapi.py b/numpy/core/code_generators/genapi.py
index 68ae30d5b..c23fd6c72 100644
--- a/numpy/core/code_generators/genapi.py
+++ b/numpy/core/code_generators/genapi.py
@@ -6,17 +6,35 @@ See ``find_function`` for how functions should be formatted, and
specified.
"""
-from numpy.distutils.conv_template import process_file as process_c_file
-
import hashlib
import io
import os
import re
import sys
import textwrap
+import importlib.util
from os.path import join
+
+def get_processor():
+ # Convoluted because we can't import from numpy.distutils
+ # (numpy is not yet built)
+ conv_template_path = os.path.join(
+ os.path.dirname(__file__),
+ '..', '..', 'distutils', 'conv_template.py'
+ )
+ spec = importlib.util.spec_from_file_location(
+ 'conv_template', conv_template_path
+ )
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ return mod.process_file
+
+
+process_c_file = get_processor()
+
+
__docformat__ = 'restructuredtext'
# The files under src/ that are scanned for API functions
diff --git a/numpy/core/code_generators/generate_numpy_api.py b/numpy/core/code_generators/generate_numpy_api.py
index a57a36a78..bdfd635e4 100644
--- a/numpy/core/code_generators/generate_numpy_api.py
+++ b/numpy/core/code_generators/generate_numpy_api.py
@@ -1,6 +1,8 @@
+#!/usr/bin/env python3
import os
-import genapi
+import argparse
+import genapi
from genapi import \
TypeApi, GlobalVarApi, FunctionApi, BoolValuesApi
@@ -242,3 +244,29 @@ def do_generate_api(targets, sources):
genapi.write_file(doc_file, s)
return targets
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-o",
+ "--outdir",
+ type=str,
+ help="Path to the output directory"
+ )
+ parser.add_argument(
+ "-i",
+ "--ignore",
+ type=str,
+ help="An ignored input - may be useful to add a "
+ "dependency between custom targets"
+ )
+ args = parser.parse_args()
+
+ outdir_abs = os.path.join(os.getcwd(), args.outdir)
+
+ generate_api(outdir_abs)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/numpy/core/code_generators/generate_ufunc_api.py b/numpy/core/code_generators/generate_ufunc_api.py
index 04c023675..5b64c8217 100644
--- a/numpy/core/code_generators/generate_ufunc_api.py
+++ b/numpy/core/code_generators/generate_ufunc_api.py
@@ -1,9 +1,9 @@
import os
-import genapi
-
-import numpy_api
+import argparse
+import genapi
from genapi import TypeApi, FunctionApi
+import numpy_api
h_template = r"""
#ifdef _UMATHMODULE
@@ -191,3 +191,22 @@ NumPy Ufunc C-API
genapi.write_file(doc_file, s)
return targets
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-o",
+ "--outdir",
+ type=str,
+ help="Path to the output directory"
+ )
+ args = parser.parse_args()
+
+ outdir_abs = os.path.join(os.getcwd(), args.outdir)
+
+ generate_api(outdir_abs)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py
index 39d4497b5..40382b8ae 100644
--- a/numpy/core/code_generators/generate_umath.py
+++ b/numpy/core/code_generators/generate_umath.py
@@ -3,6 +3,7 @@ import re
import struct
import sys
import textwrap
+import argparse
Zero = "PyLong_FromLong(0)"
One = "PyLong_FromLong(1)"
@@ -1224,8 +1225,29 @@ def make_code(funcdict, filename):
return code
-if __name__ == "__main__":
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-o",
+ "--outfile",
+ type=str,
+ help="Path to the output directory"
+ )
+ args = parser.parse_args()
+
+ # used to insert the name of this file into the generated file
filename = __file__
code = make_code(defdict, filename)
- with open('__umath_generated.c', 'w') as fid:
- fid.write(code)
+
+ if not args.outfile:
+ # This is the distutils-based build
+ outfile = '__umath_generated.c'
+ else:
+ outfile = os.path.join(os.getcwd(), args.outfile)
+
+ with open(outfile, 'w') as f:
+ f.write(code)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/numpy/core/code_generators/generate_umath_doc.py b/numpy/core/code_generators/generate_umath_doc.py
index 9888730fd..fc0c2a138 100644
--- a/numpy/core/code_generators/generate_umath_doc.py
+++ b/numpy/core/code_generators/generate_umath_doc.py
@@ -1,6 +1,7 @@
import sys
import os
import textwrap
+import argparse
sys.path.insert(0, os.path.dirname(__file__))
import ufunc_docstrings as docstrings
@@ -28,3 +29,21 @@ def write_code(target):
cdef_str = normalize_doc(string)
fid.write(f"#define {cdef_name} \"{cdef_str}\"\n")
fid.write("#endif //NUMPY_CORE_INCLUDE__UMATH_DOC_GENERATED_H\n")
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-o",
+ "--outfile",
+ type=str,
+ help="Path to the output directory"
+ )
+ args = parser.parse_args()
+
+ outfile = os.path.join(os.getcwd(), args.outfile)
+ write_code(outfile)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py
index fa28f92b7..6b9080403 100644
--- a/numpy/core/code_generators/numpy_api.py
+++ b/numpy/core/code_generators/numpy_api.py
@@ -13,7 +13,23 @@ When adding a function, make sure to use the next integer not used as an index
exception, so it should hopefully not get unnoticed).
"""
-from code_generators.genapi import StealRef
+
+import os
+import importlib.util
+
+
+def get_StealRef():
+ # Convoluted because we can't import from numpy.distutils
+ # (numpy is not yet built)
+ genapi_py = os.path.join(os.path.dirname(__file__), 'genapi.py')
+ spec = importlib.util.spec_from_file_location('conv_template', genapi_py)
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ return mod.StealRef
+
+
+StealRef = get_StealRef()
+#from code_generators.genapi import StealRef
# index, type
multiarray_global_vars = {
diff --git a/numpy/core/code_generators/verify_c_api_version.py b/numpy/core/code_generators/verify_c_api_version.py
new file mode 100644
index 000000000..282e5e7d3
--- /dev/null
+++ b/numpy/core/code_generators/verify_c_api_version.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+import os
+import sys
+import argparse
+
+
+class MismatchCAPIError(ValueError):
+ pass
+
+
+def get_api_versions(apiversion):
+ """
+ Return current C API checksum and the recorded checksum.
+
+ Return current C API checksum and the recorded checksum for the given
+ version of the C API version.
+
+ """
+ # Compute the hash of the current API as defined in the .txt files in
+ # code_generators
+ sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+ try:
+ m = __import__('genapi')
+ numpy_api = __import__('numpy_api')
+ curapi_hash = m.fullapi_hash(numpy_api.full_api)
+ apis_hash = m.get_versions_hash()
+ finally:
+ del sys.path[0]
+
+ return curapi_hash, apis_hash[apiversion]
+
+
+def check_api_version(apiversion):
+ """Emits a MismatchCAPIWarning if the C API version needs updating."""
+ curapi_hash, api_hash = get_api_versions(apiversion)
+
+ # If different hash, it means that the api .txt files in
+ # codegen_dir have been updated without the API version being
+ # updated. Any modification in those .txt files should be reflected
+ # in the api and eventually abi versions.
+ # To compute the checksum of the current API, use numpy/core/cversions.py
+ if not curapi_hash == api_hash:
+ msg = ("API mismatch detected, the C API version "
+ "numbers have to be updated. Current C api version is "
+ f"{apiversion}, with checksum {curapi_hash}, but recorded "
+ f"checksum in core/codegen_dir/cversions.txt is {api_hash}. If "
+ "functions were added in the C API, you have to update "
+ f"C_API_VERSION in {__file__}."
+ )
+ raise MismatchCAPIError(msg)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--api-version",
+ type=str,
+ help="C API version to verify (as a hex string)"
+ )
+ args = parser.parse_args()
+
+ check_api_version(int(args.api_version, base=16))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/numpy/core/config.h.in b/numpy/core/config.h.in
new file mode 100644
index 000000000..f4ccdcd94
--- /dev/null
+++ b/numpy/core/config.h.in
@@ -0,0 +1,118 @@
+#mesondefine SIZEOF_PY_INTPTR_T
+#mesondefine SIZEOF_OFF_T
+#mesondefine SIZEOF_PY_LONG_LONG
+
+#mesondefine HAVE_BACKTRACE
+#mesondefine HAVE_MADVISE
+#mesondefine HAVE_FTELLO
+#mesondefine HAVE_FSEEKO
+#mesondefine HAVE_FALLOCATE
+#mesondefine HAVE_STRTOLD_L
+#mesondefine HAVE__THREAD
+#mesondefine HAVE___DECLSPEC_THREAD_
+
+/* Optional headers */
+#mesondefine HAVE_XLOCALE_H
+#mesondefine HAVE_DLFCN_H
+#mesondefine HAVE_EXECINFO_H
+#mesondefine HAVE_LIBUNWIND_H
+#mesondefine HAVE_SYS_MMAN_H
+#mesondefine HAVE_XMMINTRIN_H
+#mesondefine HAVE_EMMINTRIN_H
+#mesondefine HAVE_IMMINTRIN_H
+
+/* Optional intrinsics */
+#mesondefine HAVE___BUILTIN_ISNAN
+#mesondefine HAVE___BUILTIN_ISINF
+#mesondefine HAVE___BUILTIN_ISFINITE
+#mesondefine HAVE___BUILTIN_BSWAP32
+#mesondefine HAVE___BUILTIN_BSWAP64
+#mesondefine HAVE___BUILTIN_EXPECT
+#mesondefine HAVE___BUILTIN_MUL_OVERFLOW
+#mesondefine HAVE__M_FROM_INT64
+#mesondefine HAVE__MM_LOAD_PS
+#mesondefine HAVE__MM_PREFETCH
+#mesondefine HAVE__MM_LOAD_PD
+#mesondefine HAVE___BUILTIN_PREFETCH
+#mesondefine HAVE_LINK_AVX
+#mesondefine HAVE_LINK_AVX2
+#mesondefine HAVE_LINK_AVX512F
+#mesondefine HAVE_LINK_AVX512_SKX
+#mesondefine HAVE_XGETBV
+
+#mesondefine HAVE_ATTRIBUTE_OPTIMIZE_UNROLL_LOOPS
+#mesondefine HAVE_ATTRIBUTE_OPTIMIZE_OPT_3
+#mesondefine HAVE_ATTRIBUTE_OPTIMIZE_OPT_2
+#mesondefine HAVE_ATTRIBUTE_NONNULL
+#mesondefine HAVE_ATTRIBUTE_TARGET_AVX
+#mesondefine HAVE_ATTRIBUTE_TARGET_AVX2
+#mesondefine HAVE_ATTRIBUTE_TARGET_AVX512F
+#mesondefine HAVE_ATTRIBUTE_TARGET_AVX512_SKX
+#mesondefine HAVE_ATTRIBUTE_TARGET_AVX2_WITH_INTRINSICS
+#mesondefine HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS
+#mesondefine HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS
+
+#mesondefine HAVE_DECL_ISNAN
+#mesondefine HAVE_DECL_ISINF
+#mesondefine HAVE_DECL_ISFINITE
+#mesondefine HAVE_DECL_SIGNBIT
+
+/* C99 complex support and complex.h are not universal */
+#mesondefine HAVE_COMPLEX_H
+#mesondefine HAVE_CABS
+#mesondefine HAVE_CACOS
+#mesondefine HAVE_CACOSH
+#mesondefine HAVE_CARG
+#mesondefine HAVE_CASIN
+#mesondefine HAVE_CASINH
+#mesondefine HAVE_CATAN
+#mesondefine HAVE_CATANH
+#mesondefine HAVE_CEXP
+#mesondefine HAVE_CLOG
+#mesondefine HAVE_CPOW
+#mesondefine HAVE_CSQRT
+#mesondefine HAVE_CABSF
+#mesondefine HAVE_CACOSF
+#mesondefine HAVE_CACOSHF
+#mesondefine HAVE_CARGF
+#mesondefine HAVE_CASINF
+#mesondefine HAVE_CASINHF
+#mesondefine HAVE_CATANF
+#mesondefine HAVE_CATANHF
+#mesondefine HAVE_CEXPF
+#mesondefine HAVE_CLOGF
+#mesondefine HAVE_CPOWF
+#mesondefine HAVE_CSQRTF
+#mesondefine HAVE_CABSL
+#mesondefine HAVE_CACOSL
+#mesondefine HAVE_CACOSHL
+#mesondefine HAVE_CARGL
+#mesondefine HAVE_CASINL
+#mesondefine HAVE_CASINHL
+#mesondefine HAVE_CATANL
+#mesondefine HAVE_CATANHL
+#mesondefine HAVE_CEXPL
+#mesondefine HAVE_CLOGL
+#mesondefine HAVE_CPOWL
+#mesondefine HAVE_CSQRTL
+
+#mesondefine NPY_CAN_LINK_SVML
+#mesondefine NPY_RELAXED_STRIDES_DEBUG
+
+#mesondefine HAVE_LDOUBLE_INTEL_EXTENDED_16_BYTES_LE
+#mesondefine HAVE_LDOUBLE_INTEL_EXTENDED_12_BYTES_LE
+#mesondefine HAVE_LDOUBLE_MOTOROLA_EXTENDED_12_BYTES_BE
+#mesondefine HAVE_LDOUBLE_IEEE_DOUBLE_LE
+#mesondefine HAVE_LDOUBLE_IEEE_DOUBLE_BE
+#mesondefine HAVE_LDOUBLE_IEEE_QUAD_LE
+#mesondefine HAVE_LDOUBLE_IEEE_QUAD_BE
+#mesondefine HAVE_LDOUBLE_IBM_DOUBLE_DOUBLE_LE
+#mesondefine HAVE_LDOUBLE_IBM_DOUBLE_DOUBLE_BE
+
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+#ifndef NUMPY_CORE_SRC_COMMON_NPY_CONFIG_H_
+#error config.h should never be included directly, include npy_config.h instead
+#endif
diff --git a/numpy/core/include/meson.build b/numpy/core/include/meson.build
new file mode 100644
index 000000000..0f9fbe76b
--- /dev/null
+++ b/numpy/core/include/meson.build
@@ -0,0 +1,51 @@
+installed_headers = [
+ 'numpy/_neighborhood_iterator_imp.h',
+ 'numpy/arrayobject.h',
+ 'numpy/arrayscalars.h',
+ 'numpy/experimental_dtype_api.h',
+ 'numpy/halffloat.h',
+ 'numpy/ndarrayobject.h',
+ 'numpy/ndarraytypes.h',
+ 'numpy/noprefix.h',
+ 'numpy/npy_1_7_deprecated_api.h',
+ 'numpy/npy_3kcompat.h',
+ 'numpy/npy_common.h',
+ 'numpy/npy_cpu.h',
+ 'numpy/npy_endian.h',
+ 'numpy/npy_interrupt.h',
+ 'numpy/npy_math.h',
+ 'numpy/npy_no_deprecated_api.h',
+ 'numpy/npy_os.h',
+ 'numpy/numpyconfig.h',
+ 'numpy/old_defines.h',
+ 'numpy/ufuncobject.h',
+ 'numpy/utils.h',
+]
+
+# Note that oldnumeric.h is not installed on purpose. After investigation,
+# there are only two active repos left which use it, and those got a heads up
+# about removal of this header in numpy 1.25.0:
+# https://github.com/enthought/enable/issues/1005
+# https://github.com/fhs/pyhdf/issues/63
+
+py.install_sources(
+ installed_headers,
+ subdir: 'numpy/core/include/numpy'
+)
+
+py.install_sources(
+ [
+ 'numpy/random/bitgen.h',
+ 'numpy/random/distributions.h',
+ ],
+ subdir: 'numpy/core/include/numpy/random'
+)
+
+
+py.install_sources(
+ [
+ 'numpy/libdivide/libdivide.h',
+ 'numpy/libdivide/LICENSE.txt',
+ ],
+ subdir: 'numpy/core/include/numpy/random'
+)
diff --git a/numpy/core/include/numpy/_numpyconfig.h.in b/numpy/core/include/numpy/_numpyconfig.h.in
new file mode 100644
index 000000000..8e799971a
--- /dev/null
+++ b/numpy/core/include/numpy/_numpyconfig.h.in
@@ -0,0 +1,36 @@
+#mesondefine NPY_HAVE_ENDIAN_H
+
+#mesondefine NPY_SIZEOF_SHORT
+#mesondefine NPY_SIZEOF_INT
+#mesondefine NPY_SIZEOF_LONG
+#mesondefine NPY_SIZEOF_FLOAT
+#mesondefine NPY_SIZEOF_COMPLEX_FLOAT
+#mesondefine NPY_SIZEOF_DOUBLE
+#mesondefine NPY_SIZEOF_COMPLEX_DOUBLE
+#mesondefine NPY_SIZEOF_LONGDOUBLE
+#mesondefine NPY_SIZEOF_COMPLEX_LONGDOUBLE
+#mesondefine NPY_SIZEOF_PY_INTPTR_T
+#mesondefine NPY_SIZEOF_OFF_T
+#mesondefine NPY_SIZEOF_PY_LONG_LONG
+#mesondefine NPY_SIZEOF_LONGLONG
+
+#mesondefine NPY_HAVE_DECL_ISNAN
+#mesondefine NPY_HAVE_DECL_ISINF
+#mesondefine NPY_HAVE_DECL_ISFINITE
+#mesondefine NPY_HAVE_DECL_SIGNBIT
+#mesondefine NPY_USE_C99_COMPLEX
+#mesondefine NPY_HAVE_COMPLEX_DOUBLE
+#mesondefine NPY_HAVE_COMPLEX_FLOAT
+#mesondefine NPY_HAVE_COMPLEX_LONG_DOUBLE
+#mesondefine NPY_USE_C99_FORMATS
+
+#mesondefine NPY_NO_SIGNAL
+#mesondefine NPY_NO_SMP
+
+#mesondefine NPY_VISIBILITY_HIDDEN
+#mesondefine NPY_ABI_VERSION
+#mesondefine NPY_API_VERSION
+
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
diff --git a/numpy/core/meson.build b/numpy/core/meson.build
new file mode 100644
index 000000000..507d0868d
--- /dev/null
+++ b/numpy/core/meson.build
@@ -0,0 +1,929 @@
+# This file should contain what setup.py + setup_common.py do (WIP)
+#
+# Potential issues to address or keep track of:
+# - sincos detection incorrect on NetBSD: https://github.com/mesonbuild/meson/issues/10641
+
+# Versioning support
+#-------------------
+#
+# How to change C_API_VERSION ?
+# - increase C_API_VERSION value
+# - record the hash for the new C API with the cversions.py script
+# and add the hash to cversions.txt
+# The hash values are used to remind developers when the C API number was not
+# updated - generates a MismatchCAPIWarning warning which is turned into an
+# exception for released version.
+
+# Binary compatibility version number. This number is increased whenever the
+# C-API is changed such that binary compatibility is broken, i.e. whenever a
+# recompile of extension modules is needed.
+C_ABI_VERSION = '0x01000009'
+
+# Minor API version. This number is increased whenever a change is made to the
+# C-API -- whether it breaks binary compatibility or not. Some changes, such
+# as adding a function pointer to the end of the function table, can be made
+# without breaking binary compatibility. In this case, only the C_API_VERSION
+# (*not* C_ABI_VERSION) would be increased. Whenever binary compatibility is
+# broken, both C_API_VERSION and C_ABI_VERSION should be increased.
+#
+# The version needs to be kept in sync with that in cversions.txt.
+#
+# 0x00000008 - 1.7.x
+# 0x00000009 - 1.8.x
+# 0x00000009 - 1.9.x
+# 0x0000000a - 1.10.x
+# 0x0000000a - 1.11.x
+# 0x0000000a - 1.12.x
+# 0x0000000b - 1.13.x
+# 0x0000000c - 1.14.x
+# 0x0000000c - 1.15.x
+# 0x0000000d - 1.16.x
+# 0x0000000d - 1.19.x
+# 0x0000000e - 1.20.x
+# 0x0000000e - 1.21.x
+# 0x0000000f - 1.22.x
+# 0x00000010 - 1.23.x
+# 0x00000010 - 1.24.x
+C_API_VERSION = '0x00000010'
+
+# Check whether we have a mismatch between the set C API VERSION and the
+# actual C API VERSION. Will raise a MismatchCAPIError if so.
+run_command('code_generators/verify_c_api_version.py', '--api-version', C_API_VERSION, check: true)
+
+
+# Generate config.h and _numpyconfig.h
+# ------------------------------------
+#
+# There are two generated headers:
+# - config.h: a private header, which is not installed and used only at
+# build time, mostly to determine whether or not optional
+# headers, compiler attributes, etc. are available
+# - _numpyconfig.h: a header with public `NPY_` symbols which get made
+# available via numpyconfig.h
+#
+# Note that `HAVE_*` symbols indicate the presence or absence of a checked
+# property of the build environment. When available, these symbols get defined
+# to `1`; when not available they must not be defined at all. This is
+# important, because code in NumPy typically does not check the value but only
+# whether the symbol is defined. So `#define HAVE_SOMETHING 0` is wrong.
+
+cdata = configuration_data()
+
+cdata.set('NPY_ABI_VERSION', C_ABI_VERSION)
+cdata.set('NPY_API_VERSION', C_API_VERSION)
+
+use_svml = (
+ host_machine.system() == 'linux' and
+ host_machine.cpu_family() == 'x86_64' and
+ not get_option('disable-svml')
+)
+if use_svml
+ cdata.set10('NPY_CAN_LINK_SVML', true)
+ if not fs.exists('src/umath/svml')
+ error('Missing the `SVML` git submodule! Run `git submodule update --init` to fix this.')
+ endif
+endif
+
+# Check sizes of types. Note, some of these landed in config.h before, but were
+# unused. So clean that up and only define the NPY_SIZEOF flavors rather than
+# the SIZEOF ones
+types_to_check = [
+ ['NPY_SIZEOF_SHORT', 'short'],
+ ['NPY_SIZEOF_INT', 'int'],
+ ['NPY_SIZEOF_LONG', 'long'],
+ ['NPY_SIZEOF_LONGLONG', 'long long'],
+ ['NPY_SIZEOF_FLOAT', 'float'],
+ ['NPY_SIZEOF_DOUBLE', 'double'],
+ ['NPY_SIZEOF_LONGDOUBLE', 'long double'],
+]
+foreach symbol_type: types_to_check
+ cdata.set(symbol_type[0], cc.sizeof(symbol_type[1]))
+endforeach
+cdata.set('NPY_SIZEOF_OFF_T', cc.sizeof('off_t', prefix: '#include <sys/types.h>'))
+cdata.set('NPY_SIZEOF_PY_INTPTR_T',
+ cc.sizeof('Py_intptr_t', dependencies: py_dep, prefix: '#include <Python.h>'))
+cdata.set('NPY_SIZEOF_PY_LONG_LONG',
+ cc.sizeof('PY_LONG_LONG', dependencies: py_dep, prefix: '#include <Python.h>'))
+
+# Check for complex support
+if cc.has_header('complex.h')
+ cdata.set10('HAVE_COMPLEX_H', true)
+ cdata.set10('NPY_USE_C99_COMPLEX', true)
+ complex_types_to_check = [
+ ['NPY_HAVE_COMPLEX_FLOAT', 'NPY_SIZEOF_COMPLEX_FLOAT', 'complex float', 'float'],
+ ['NPY_HAVE_COMPLEX_DOUBLE', 'NPY_SIZEOF_COMPLEX_DOUBLE', 'complex double', 'double'],
+ ['NPY_HAVE_COMPLEX_LONG_DOUBLE', 'NPY_SIZEOF_COMPLEX_LONGDOUBLE', 'complex long double', 'long double'],
+ ]
+ foreach symbol_type: complex_types_to_check
+ if cc.has_type(symbol_type[2], prefix: '#include <complex.h>')
+ cdata.set10(symbol_type[0], true)
+ # Determine size of NumPy's own, struct-based, complex types. Binary
+ # compatibility with C99 complex types is checked at build time in `npy_common.h`.
+ ftype = symbol_type[3]
+ cdata.set(symbol_type[1], cc.sizeof(f'struct {@ftype@ __x; @ftype@ __y;}'))
+ endif
+ endforeach
+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 = [
+ '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',
+ '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')
+ endif
+endforeach
+
+c99_complex_funcs = [
+ 'cabs', 'cacos', 'cacosh', 'carg', 'casin', 'casinh', 'catan',
+ 'catanh', 'cexp', 'clog', 'cpow', 'csqrt'
+]
+foreach func: c99_complex_funcs
+ func_single = func + 'f'
+ func_longdouble = func + 'l'
+ if cc.has_function(func)
+ cdata.set10('HAVE_' + func.to_upper(), true)
+ endif
+ if cc.has_function(func_single)
+ cdata.set10('HAVE_' + func_single.to_upper(), true)
+ endif
+ if cc.has_function(func_longdouble)
+ cdata.set10('HAVE_' + func_longdouble.to_upper(), true)
+ endif
+endforeach
+
+# We require C99 so these should always be found at build time. But for
+# 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)
+ 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
+ cdata.set10('HAVE_DECL_' + macro.to_upper(), true)
+ endif
+ endif
+endforeach
+
+# variable attributes tested via "int %s a" % attribute
+optional_variable_attributes = [
+ ['__thread', 'HAVE__THREAD'],
+ ['__declspec(thread)', 'HAVE___DECLSPEC_THREAD_']
+]
+foreach optional_attr: optional_variable_attributes
+ attr = optional_attr[0]
+ code = f'''
+ #pragma GCC diagnostic error "-Wattributes"
+ #pragma clang diagnostic error "-Wattributes"
+
+ int @attr@ foo;
+ '''
+ code += '''
+ int
+ main()
+ {
+ return 0;
+ }
+ '''
+ if cc.compiles(code)
+ cdata.set10(optional_attr[1], true)
+ endif
+endforeach
+
+inc_curdir = include_directories('.')
+optional_file_funcs = ['fallocate', 'ftello', 'fseeko']
+foreach filefunc_maybe: optional_file_funcs
+ config_value = 'HAVE_' + filefunc_maybe.to_upper()
+ # Some functions may already have HAVE_* defined by `Python.h`. Python puts
+ # its config.h in the public Python.h namespace, so we have a possible clash
+ # for the common functions we test. Hence we skip those checks.
+ if (filefunc_maybe == 'fallocate' or
+ not cc.has_header_symbol('Python.h', config_value, dependencies: py_dep)
+ )
+ if cc.has_function(filefunc_maybe,
+ include_directories: inc_curdir,
+ prefix: '#include "feature_detection_stdio.h"'
+ )
+ cdata.set10(config_value, true)
+ endif
+ endif
+endforeach
+
+# Optional locale function
+have_strtold_l = cc.has_function('strtold_l', include_directories: inc_curdir,
+ prefix:'''
+ #include <stdlib.h>
+ #include <xlocale.h>
+ #include "feature_detection_locale.h"
+''')
+if not have_strtold_l
+ # Retry with locale.h, seems to vary across Linux distros
+ have_strtold_l = cc.has_function('strtold_l', include_directories: inc_curdir,
+ prefix:'''
+ #include <stdlib.h>
+ #include <locale.h>
+ #include "feature_detection_locale.h"
+ ''')
+endif
+if have_strtold_l
+ cdata.set10('HAVE_STRTOLD_L', true)
+else
+ # FIXME: this is wrong! the HAVE_ define should not exist, or it'll be
+ # interpreted as the function being available (true/false does nothing, see
+ # note on HAVE_ defines higher up). This is necessary though in order to make
+ # the Linux CI job pass. So either the check is wrong somehow, or this
+ # function is not available in CI. For the latter there is a fallback path,
+ # but that is broken because we don't have the exact long double
+ # representation checks.
+ cdata.set10('HAVE_STRTOLD_L', false)
+endif
+
+# Other optional functions
+optional_misc_funcs = [
+ 'backtrace',
+ 'madvise',
+]
+foreach func: optional_misc_funcs
+ if cc.has_function(func,
+ include_directories: inc_curdir,
+ prefix: '#include "feature_detection_misc.h"'
+ )
+ cdata.set10('HAVE_' + func.to_upper(), true)
+ endif
+endforeach
+
+# SSE headers only enabled automatically on amd64/x32 builds
+optional_headers = [
+ 'xmmintrin.h', # SSE
+ 'emmintrin.h', # SSE2
+ 'immintrin.h', # AVX
+ 'features.h', # for glibc version linux
+ 'xlocale.h', # see GH#8367
+ 'dlfcn.h', # dladdr
+ 'execinfo.h', # backtrace
+ 'libunwind.h', # backtrace for LLVM/Clang using libunwind
+ 'sys/mman.h', # madvise
+]
+foreach header: optional_headers
+ if cc.has_header(header)
+ cdata.set10('HAVE_' + header.to_upper().replace('.', '_').replace('/', '_'), true)
+ endif
+endforeach
+
+# Optional compiler attributes
+# TODO: this doesn't work with cc.has_function_attribute, see
+# https://github.com/mesonbuild/meson/issues/10732
+optional_function_attributes = [
+ ['optimize("unroll-loops")', 'OPTIMIZE_UNROLL_LOOPS'],
+ ['optimize("O3")', 'OPTIMIZE_OPT_3'],
+ ['optimize("O2")', 'OPTIMIZE_OPT_2'],
+ ['optimize("nonnull (1)")', 'NONNULL'],
+ ]
+if host_machine.cpu_family() in ['x86', 'x86_64']
+ optional_function_attributes += [
+ ['target("avx")', 'TARGET_AVX'],
+ ['target("avx2")', 'TARGET_AVX2'],
+ ['target("avx512f")', 'TARGET_AVX512F'],
+ ['target("avx512f,avx512dq,avx512bw,avx512vl,avx512cd")', 'TARGET_AVX512_SKX'],
+ ]
+ # TODO: add the _WITH_INTRINSICS_AVX list
+endif
+#foreach attr: optional_function_attributes
+# if cc.has_function_attribute(attr[0])
+# cdata.set10('HAVE_ATTRIBUTE_' + attr[1], true)
+# endif
+#endforeach
+
+# Optional GCC compiler builtins and their call arguments.
+# If given, a required header and definition name (HAVE_ prepended)
+# Call arguments are required as the compiler will do strict signature checking
+optional_intrinsics = [
+ ['__builtin_isnan', '5.', [], []],
+ ['__builtin_isinf', '5.', [], []],
+ ['__builtin_isfinite', '5.', [], []],
+ ['__builtin_bswap32', '5u', [], []],
+ ['__builtin_bswap64', '5u', [], []],
+ ['__builtin_expect', '5, 0', [], []],
+ ['__builtin_mul_overflow', '5, 5, (int*)5', [], []],
+]
+if host_machine.cpu_family() in ['x86', 'x86_64']
+ optional_intrinsics += [
+ # MMX only needed for icc, but some clang's don't have it
+ ['_m_from_int64', '0', ['emmintrin.h'], []],
+ ['_mm_load_ps', '(float*)0', ['xmmintrin.h'], []], # SSE
+ ['_mm_prefetch', '(float*)0, _MM_HINT_NTA', ['xmmintrin.h'], []], # SSE
+ ['_mm_load_pd', '(double*)0', ['emmintrin.h'], []], # SSE2
+ ['__builtin_prefetch', '(float*)0, 0, 3', [], []],
+ # Check that the linker can handle AVX
+ ['__asm__ volatile', '"vpand %xmm1, %xmm2, %xmm3"', ['stdio.h'], ['HAVE_LINK_AVX']],
+ ['__asm__ volatile', '"vpand %ymm1, %ymm2, %ymm3"', ['stdio.h'], ['HAVE_LINK_AVX2']],
+ ['__asm__ volatile', '"vpaddd %zmm1, %zmm2, %zmm3"', ['stdio.h'], ['HAVE_LINK_AVX512F']],
+ ['__asm__ volatile',
+ '"vfpclasspd $0x40, %zmm15, %k6\\n vmovdqu8 %xmm0, %xmm1\\n vpbroadcastmb2q %k0, %xmm0"',
+ ['stdio.h'], ['HAVE_LINK_AVX512_SKX']
+ ],
+ ['__asm__ volatile', '"xgetbv"', ['stdio.h'], ['HAVE_XGETBV']],
+ ]
+endif
+foreach intrin: optional_intrinsics
+ func = intrin[0]
+ func_args = intrin[1]
+ header = intrin[2]
+ define = intrin[3]
+ code = ''
+ if header.length() == 1
+ header_name = header[0]
+ code += f'#include <@header_name@>'
+ endif
+ code += f'''
+ #ifdef _MSC_VER
+ #pragma function(@func@)
+ #endif
+ int main(void) {
+ @func@(@func_args@);
+ return 0;
+ };
+ '''
+ if define.length() == 1
+ define_name = define[0]
+ else
+ define_name = 'HAVE_' + func.to_upper()
+ endif
+ if cc.links(code)
+ cdata.set10(define_name, true)
+ endif
+endforeach
+
+# long double representation detection (see setup_common.py)
+# TODO: this is still incomplete, and different from how it's done in the
+# numpy.distutils based build, see https://github.com/mesonbuild/meson/issues/11068
+longdouble_size = cc.sizeof('long double')
+if longdouble_size == 8
+ if host_machine.endian() == 'little'
+ longdouble_format = 'IEEE_DOUBLE_LE'
+ else
+ longdouble_format = 'IEEE_DOUBLE_BE'
+ endif
+elif longdouble_size == 12
+ error('This should not be possible, 12 bits of "content" should still result in sizeof() being 16. Please report this error!'
+ )
+elif longdouble_size == 16
+ if host_machine.endian() == 'little'
+ # FIXME: this varies, there's multiple formats here! Not yet implemented.
+ # TBD how we deal with the mess of old long double formats.
+ longdouble_format = 'INTEL_EXTENDED_16_BYTES_LE'
+ else
+ error('No idea what this is ....')
+ endif
+else
+ error('Unknown long double size: ' + londouble_size)
+endif
+cdata.set10('HAVE_LDOUBLE_' + longdouble_format, true)
+
+if cc.has_header('endian.h')
+ cdata.set10('NPY_HAVE_ENDIAN_H', true)
+endif
+if cc.has_header('sys/endian.h')
+ cdata.set10('NPY_HAVE_SYS_ENDIAN_H', true)
+endif
+if is_windows
+ cdata.set10('NPY_NO_SIGNAL', true)
+endif
+# Command-line switch; distutils build checked for `NPY_NOSMP` env var instead
+# TODO: document this (search for NPY_NOSMP in C API docs)
+cdata.set10('NPY_NO_SMP', get_option('disable-threading'))
+
+# Use bogus stride debug aid to flush out bugs where users use strides of
+# dimensions with length 1 to index a full contiguous array.
+cdata.set10('NPY_RELAXED_STRIDES_DEBUG', get_option('relaxed-strides-debug'))
+
+# Check whether we can use inttypes (C99) formats
+if cc.has_header_symbol('inttypes.h', 'PRIdPTR')
+ cdata.set10('NPY_USE_C99_FORMATS', true)
+endif
+
+visibility_hidden = ''
+if cc.has_function_attribute('visibility:hidden')
+ visibility_hidden = '__attribute__((visibility("hidden")))'
+endif
+cdata.set('NPY_VISIBILITY_HIDDEN', visibility_hidden)
+
+
+config_h = configure_file(
+ input: 'config.h.in',
+ output: 'config.h',
+ configuration: cdata,
+ install: false
+)
+
+_numpyconfig_h = configure_file(
+ input: 'include/numpy/_numpyconfig.h.in',
+ output: '_numpyconfig.h',
+ configuration: cdata,
+ install: true,
+ install_dir: np_dir / 'core/include/numpy'
+)
+
+# Build npymath static library
+# ----------------------------
+
+staticlib_cflags = []
+if cc.get_id() == 'msvc'
+ # Disable voltbl section for vc142 to allow link using mingw-w64; see:
+ # https://github.com/matthew-brett/dll_investigation/issues/1#issuecomment-1100468171
+ # Needs to be added to static libraries that are shipped for reuse (i.e.,
+ # libnpymath and libnpyrandom)
+ if cc.has_argument('-d2VolatileMetadata-')
+ staticlib_cflags += '-d2VolatileMetadata-'
+ endif
+endif
+
+npy_math_internal_h = custom_target(
+ output: 'npy_math_internal.h',
+ input: 'src/npymath/npy_math_internal.h.src',
+ command: [src_file_cli, '@INPUT@', '-o', '@OUTPUT@'],
+)
+
+npymath_sources = [
+ src_file.process('src/npymath/ieee754.c.src'),
+ src_file.process('src/npymath/npy_math_complex.c.src'),
+ npy_math_internal_h,
+ 'src/npymath/_signbit.c',
+ 'src/npymath/halffloat.c',
+ 'src/npymath/npy_math.c',
+]
+npymath_lib = static_library('npymath',
+ npymath_sources,
+ c_args: staticlib_cflags,
+ include_directories: ['include', 'src/npymath', 'src/common'],
+ dependencies: py_dep,
+ install: true,
+ install_dir: np_dir / 'core/lib',
+)
+
+dir_separator = '/'
+if build_machine.system() == 'windows'
+ dir_separator = '\\'
+endif
+configure_file(
+ input: 'npymath.ini.in',
+ output: 'npymath.ini',
+ configuration: configuration_data({
+ 'pkgname' : 'numpy.core',
+ 'sep' : dir_separator,
+ }),
+ install: true,
+ install_dir: np_dir / 'core/lib/npy-pkg-config'
+)
+configure_file(
+ input: 'mlib.ini.in',
+ output: 'mlib.ini',
+ configuration: configuration_data({
+ 'posix_mathlib' : mlib_linkflag,
+ 'msvc_mathlib' : 'm.lib',
+ }),
+ install: true,
+ install_dir: np_dir / 'core/lib/npy-pkg-config'
+)
+
+if false
+ # This doesn't quite work (yet), it assumes we'll install headers under
+ # include/, and trying to add the correct path with `extra_cflags` runs into
+ # not being able to get a path relative to the prefix.
+ # Note that installing numpy headers under include/ would be a good idea, but
+ # that needs work (and may run into trouble with wheels perhaps, not quite
+ # clear if they allow this).
+ pkg = import('pkgconfig')
+ pkg.generate(npymath_lib,
+ name: 'npymath',
+ description: 'Portable, core math library implementing C99 standard',
+ url: 'https://github.com/numpy/numpy',
+ requires: 'numpy',
+ install_dir: np_dir / 'core/lib/npy-pkg-config',
+ extra_cflags: '-I${includedir}' + np_dir / 'core' / 'include',
+ )
+endif
+
+# Generate NumPy C API sources
+# ----------------------------
+
+# This is a single C file. It needs to be built before _multiarray_umath starts
+# building, but we can't add it to the sources of that extension (this C file
+# doesn't compile, it's only included in another r file. Hence use the slightly
+# hacky --ignore argument to the next custom_target().
+src_umath_api_c = custom_target('__umath_generated',
+ output : '__umath_generated.c',
+ input : 'code_generators/generate_umath.py',
+ command: [py, '@INPUT@', '-o', '@OUTPUT@'],
+)
+
+src_umath_doc_h = custom_target('_umath_doc_generated',
+ output : '_umath_doc_generated.h',
+ input : 'code_generators/generate_umath_doc.py',
+ command: [py, '@INPUT@', '-o', '@OUTPUT@'],
+)
+
+src_numpy_api = custom_target('__multiarray_api',
+ output : ['__multiarray_api.c', '__multiarray_api.h', 'multiarray_api.txt'],
+ input : 'code_generators/generate_numpy_api.py',
+ command: [py, '@INPUT@', '-o', '@OUTDIR@', '--ignore', src_umath_api_c],
+ install: true, # NOTE: setup.py build installs all, but just need .h?
+ install_dir: np_dir / 'core/include/numpy'
+)
+
+src_ufunc_api = custom_target('__ufunc_api',
+ output : ['__ufunc_api.c', '__ufunc_api.h', 'ufunc_api.txt'],
+ input : 'code_generators/generate_ufunc_api.py',
+ command: [py, '@INPUT@', '-o', '@OUTDIR@'],
+ install: true, # NOTE: setup.py build installs all, but just need .h?
+ install_dir: np_dir / 'core/include/numpy'
+)
+
+
+# Set common build flags for C and C++ code
+# -----------------------------------------
+
+# TODO: change to "feature" option in meson_options.txt? See
+# https://mesonbuild.com/Build-options.html#build-options
+disable_simd_optimizations = []
+if get_option('disable-simd-optimizations')
+ disable_simd_optimizations = '-DNPY_DISABLE_OPTIMIZATION'
+endif
+
+# Common build flags
+c_args_common = [
+ '-DNPY_INTERNAL_BUILD',
+ '-DHAVE_NPY_CONFIG_H',
+ disable_simd_optimizations,
+ cflags_large_file_support,
+]
+
+# Same as NPY_CXX_FLAGS (TODO: extend for what ccompiler_opt adds)
+cpp_args_common = c_args_common + [
+ '-D__STDC_VERSION__=0', # for compatibility with C headers
+ '-fno-exceptions', # no exception support
+ '-fno-rtti', # no runtime type information
+]
+
+# Other submodules depend on generated headers and include directories from
+# core, wrap those up into a reusable dependency. Also useful for some test
+# modules in this build file.
+np_core_dep = declare_dependency(
+ sources: [
+ _numpyconfig_h,
+ npy_math_internal_h,
+ src_numpy_api[1], # __multiarray_api.h
+ src_ufunc_api[1], # __ufunc_api.h
+ ],
+ include_directories: [
+ '.',
+ 'include',
+ 'src/common',
+ ]
+)
+
+
+# Build multiarray_tests module
+# -----------------------------
+py.extension_module('_multiarray_tests',
+ [
+ src_file.process('src/multiarray/_multiarray_tests.c.src'),
+ 'src/common/mem_overlap.c',
+ 'src/common/npy_argparse.c',
+ 'src/common/npy_hashtable.c',
+ src_file.process('src/common/templ_common.h.src')
+ ],
+ c_args: c_args_common,
+ include_directories: ['src/multiarray', 'src/npymath'],
+ dependencies: np_core_dep,
+ link_with: npymath_lib,
+ gnu_symbol_visibility: 'default',
+ install: true,
+ subdir: 'numpy/core',
+)
+
+test_modules_src = [
+ ['_umath_tests', [
+ src_file.process('src/umath/_umath_tests.c.src'),
+ 'src/umath/_umath_tests.dispatch.c',
+ 'src/common/npy_cpu_features.c',
+ ]],
+ ['_rational_tests', 'src/umath/_rational_tests.c'],
+ ['_struct_ufunc_tests', 'src/umath/_struct_ufunc_tests.c'],
+ ['_operand_flag_tests', 'src/umath/_operand_flag_tests.c'],
+]
+foreach gen: test_modules_src
+ py.extension_module(gen[0],
+ gen[1],
+ c_args: c_args_common,
+ include_directories: ['src/multiarray', 'src/npymath'],
+ dependencies: np_core_dep,
+ install: true,
+ subdir: 'numpy/core',
+ )
+endforeach
+
+# Build _multiarray_umath module
+# ------------------------------
+src_multiarray_umath_common = [
+ 'src/common/array_assign.c',
+ 'src/common/mem_overlap.c',
+ 'src/common/npy_argparse.c',
+ 'src/common/npy_hashtable.c',
+ 'src/common/npy_longdouble.c',
+ 'src/common/ucsnarrow.c',
+ 'src/common/ufunc_override.c',
+ 'src/common/numpyos.c',
+ 'src/common/npy_cpu_features.c',
+ src_file.process('src/common/templ_common.h.src')
+]
+if have_blas
+ src_multiarray_umath_common += [
+ 'src/common/cblasfuncs.c',
+ 'src/common/python_xerbla.c',
+ ]
+endif
+
+src_multiarray = [
+ 'src/multiarray/abstractdtypes.c',
+ 'src/multiarray/alloc.c',
+ src_file.process('src/multiarray/argfunc.dispatch.c.src'),
+ 'src/multiarray/arrayobject.c',
+ src_file.process('src/multiarray/arraytypes.h.src'),
+ 'src/multiarray/array_coercion.c',
+ 'src/multiarray/array_method.c',
+ 'src/multiarray/array_assign_scalar.c',
+ 'src/multiarray/array_assign_array.c',
+ 'src/multiarray/arrayfunction_override.c',
+ src_file.process('src/multiarray/arraytypes.c.src'),
+ 'src/multiarray/buffer.c',
+ 'src/multiarray/calculation.c',
+ 'src/multiarray/compiled_base.c',
+ 'src/multiarray/common.c',
+ 'src/multiarray/common_dtype.c',
+ 'src/multiarray/convert.c',
+ 'src/multiarray/convert_datatype.c',
+ 'src/multiarray/conversion_utils.c',
+ 'src/multiarray/ctors.c',
+ 'src/multiarray/datetime.c',
+ 'src/multiarray/datetime_strings.c',
+ 'src/multiarray/datetime_busday.c',
+ 'src/multiarray/datetime_busdaycal.c',
+ 'src/multiarray/descriptor.c',
+ 'src/multiarray/dlpack.c',
+ 'src/multiarray/dtypemeta.c',
+ 'src/multiarray/dragon4.c',
+ 'src/multiarray/dtype_transfer.c',
+ src_file.process('src/multiarray/einsum.c.src'),
+ src_file.process('src/multiarray/einsum_sumprod.c.src'),
+ 'src/multiarray/experimental_public_dtype_api.c',
+ 'src/multiarray/flagsobject.c',
+ 'src/multiarray/getset.c',
+ 'src/multiarray/hashdescr.c',
+ 'src/multiarray/item_selection.c',
+ 'src/multiarray/iterators.c',
+ 'src/multiarray/legacy_dtype_implementation.c',
+ src_file.process('src/multiarray/lowlevel_strided_loops.c.src'),
+ 'src/multiarray/mapping.c',
+ 'src/multiarray/methods.c',
+ 'src/multiarray/multiarraymodule.c',
+ 'src/multiarray/nditer_api.c',
+ 'src/multiarray/nditer_constr.c',
+ 'src/multiarray/nditer_pywrap.c',
+ src_file.process('src/multiarray/nditer_templ.c.src'),
+ 'src/multiarray/number.c',
+ 'src/multiarray/refcount.c',
+ src_file.process('src/multiarray/scalartypes.c.src'),
+ 'src/multiarray/sequence.c',
+ 'src/multiarray/shape.c',
+ 'src/multiarray/scalarapi.c',
+ 'src/multiarray/strfuncs.c',
+ 'src/multiarray/temp_elide.c',
+ 'src/multiarray/typeinfo.c',
+ 'src/multiarray/usertypes.c',
+ 'src/multiarray/vdot.c',
+ src_file.process('src/common/npy_sort.h.src'),
+ 'src/npysort/x86-qsort.dispatch.cpp',
+ 'src/npysort/quicksort.cpp',
+ 'src/npysort/mergesort.cpp',
+ 'src/npysort/timsort.cpp',
+ 'src/npysort/heapsort.cpp',
+ 'src/npysort/radixsort.cpp',
+ 'src/common/npy_partition.h',
+ 'src/npysort/selection.cpp',
+ 'src/common/npy_binsearch.h',
+ 'src/npysort/binsearch.cpp',
+ 'src/multiarray/textreading/conversions.c',
+ 'src/multiarray/textreading/field_types.c',
+ 'src/multiarray/textreading/growth.c',
+ 'src/multiarray/textreading/readtext.c',
+ 'src/multiarray/textreading/rows.c',
+ 'src/multiarray/textreading/stream_pyobject.c',
+ 'src/multiarray/textreading/str_to_int.c',
+ 'src/multiarray/textreading/tokenize.cpp',
+]
+
+src_umath = [
+ src_file.process('src/umath/funcs.inc.src'),
+ src_file.process('src/umath/loops.h.src'),
+ src_file.process('src/umath/loops_utils.h.src'),
+ src_file.process('src/umath/loops.c.src'),
+ src_file.process('src/umath/loops_arithm_fp.dispatch.c.src'),
+ src_file.process('src/umath/loops_arithmetic.dispatch.c.src'),
+ src_file.process('src/umath/loops_comparison.dispatch.c.src'),
+ src_file.process('src/umath/loops_exponent_log.dispatch.c.src'),
+ src_file.process('src/umath/loops_hyperbolic.dispatch.c.src'),
+ src_file.process('src/umath/loops_minmax.dispatch.c.src'),
+ src_file.process('src/umath/loops_modulo.dispatch.c.src'),
+ src_file.process('src/umath/loops_trigonometric.dispatch.c.src'),
+ src_file.process('src/umath/loops_umath_fp.dispatch.c.src'),
+ src_file.process('src/umath/loops_unary_fp.dispatch.c.src'),
+ src_file.process('src/umath/matmul.c.src'),
+ src_file.process('src/umath/matmul.h.src'),
+ src_file.process('src/umath/simd.inc.src'),
+ 'src/umath/ufunc_type_resolution.c',
+ 'src/umath/clip.cpp',
+ 'src/umath/clip.h',
+ 'src/umath/dispatching.c',
+ 'src/umath/extobj.c',
+ 'src/umath/legacy_array_method.c',
+ 'src/umath/override.c',
+ 'src/umath/reduction.c',
+ src_file.process('src/umath/scalarmath.c.src'),
+ 'src/umath/ufunc_object.c',
+ 'src/umath/umathmodule.c',
+ 'src/umath/string_ufuncs.cpp',
+ 'src/umath/wrapping_array_method.c',
+ # For testing. Eventually, should use public API and be separate:
+ 'src/umath/_scaled_float_dtype.c',
+]
+
+# SVML object files. If functionality is migrated to universal intrinsics and
+# the object files are no longer needed, comment out the relevant object files
+# here. Note that this migration is desirable; we then get the performance
+# benefits for all platforms rather than only for AVX512 on 64-bit Linux, and
+# may be able to avoid the accuracy regressions in SVML.
+svml_objects = []
+if use_svml
+ svml_objects += [
+ 'src/umath/svml/linux/avx512/svml_z0_acos_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_acos_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_acosh_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_acosh_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_asin_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_asin_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_asinh_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_asinh_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_atan2_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_atan2_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_atan_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_atan_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_atanh_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_atanh_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_cbrt_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_cbrt_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_cos_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_cos_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_cosh_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_cosh_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_exp2_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_exp2_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_exp_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_exp_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_expm1_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_expm1_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log10_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log10_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log1p_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log1p_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log2_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log2_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_log_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_pow_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_pow_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_sin_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_sin_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_sinh_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_sinh_s_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_tan_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_tan_s_la.s',
+ # 'src/umath/svml/linux/avx512/svml_z0_tanh_d_la.s',
+ 'src/umath/svml/linux/avx512/svml_z0_tanh_s_la.s',
+ ]
+endif
+
+py.extension_module('_multiarray_umath',
+ [
+ config_h,
+ _numpyconfig_h,
+ src_multiarray,
+ src_multiarray_umath_common,
+ src_umath,
+ src_ufunc_api[1], # __ufunc_api.h
+ src_numpy_api[1], # __multiarray_api.h
+ src_umath_doc_h,
+ npy_math_internal_h,
+ ],
+ objects: svml_objects,
+ c_args: c_args_common,
+ cpp_args: cpp_args_common,
+ include_directories: [
+ 'include',
+ 'src/common',
+ 'src/multiarray',
+ 'src/npymath',
+ 'src/umath',
+ ],
+ dependencies: blas,
+ link_with: npymath_lib,
+ install: true,
+ subdir: 'numpy/core',
+)
+
+# Build SIMD module
+# -----------------
+
+py.extension_module('_simd',
+ [
+ 'src/common/npy_cpu_features.c',
+ 'src/_simd/_simd.c',
+ src_file.process('src/_simd/_simd_inc.h.src'),
+ src_file.process('src/_simd/_simd_data.inc.src'),
+ src_file.process('src/_simd/_simd.dispatch.c.src'),
+ ],
+ c_args: c_args_common,
+ #include_directories: ['src/multiarray', 'src/npymath'],
+ include_directories: ['src/_simd'],
+ dependencies: np_core_dep,
+ install: true,
+ subdir: 'numpy/core',
+)
+
+python_sources = [
+ '__init__.py',
+ '__init__.pyi',
+ '_add_newdocs.py',
+ '_add_newdocs_scalars.py',
+ '_asarray.py',
+ '_asarray.pyi',
+ '_dtype.py',
+ '_dtype_ctypes.py',
+ '_exceptions.py',
+ '_internal.py',
+ '_internal.pyi',
+ '_machar.py',
+ '_methods.py',
+ '_string_helpers.py',
+ '_type_aliases.py',
+ '_type_aliases.pyi',
+ '_ufunc_config.py',
+ '_ufunc_config.pyi',
+ 'arrayprint.py',
+ 'arrayprint.pyi',
+ 'cversions.py',
+ 'defchararray.py',
+ 'defchararray.pyi',
+ 'einsumfunc.py',
+ 'einsumfunc.pyi',
+ 'fromnumeric.py',
+ 'fromnumeric.pyi',
+ 'function_base.py',
+ 'function_base.pyi',
+ 'getlimits.py',
+ 'getlimits.pyi',
+ 'memmap.py',
+ 'memmap.pyi',
+ 'multiarray.py',
+ 'multiarray.pyi',
+ 'numeric.py',
+ 'numeric.pyi',
+ 'numerictypes.py',
+ 'numerictypes.pyi',
+ 'overrides.py',
+ 'records.py',
+ 'records.pyi',
+ 'shape_base.py',
+ 'shape_base.pyi',
+ 'umath.py',
+ 'umath_tests.py',
+]
+
+py.install_sources(
+ python_sources,
+ subdir: 'numpy/core'
+)
+
+subdir('include')
+install_subdir('tests', install_dir: np_dir / 'core')
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index 10b8c093e..6f0a4417a 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -45,6 +45,8 @@ NPY_DISABLE_SVML = (os.environ.get('NPY_DISABLE_SVML', "0") == "1")
# in time is only in build. -- Charles Harris, 2013-03-30
class CallOnceOnly:
+ # NOTE: we don't need any of this in the Meson build,
+ # it takes care of caching
def __init__(self):
self._check_types = None
self._check_ieee_macros = None
@@ -177,6 +179,8 @@ def check_math_capabilities(config, ext, moredefs, mathlibs):
else:
return 1
+ # NOTE: not needed in Meson build, we set the minimum
+ # compiler version to 8.4 to avoid this bug
# GH-14787: Work around GCC<8.4 bug when compiling with AVX512
# support on Windows-based platforms
def check_gh14787(fn):
@@ -427,6 +431,8 @@ def check_types(config_cmd, ext, build_dir):
return private_defines, public_defines
+# NOTE: this isn't needed in the Meson build,
+# and we won't support a MATHLIB env var
def check_mathlib(config_cmd):
# Testing the C math library
mathlibs = []
diff --git a/numpy/fft/meson.build b/numpy/fft/meson.build
new file mode 100644
index 000000000..fedbf6349
--- /dev/null
+++ b/numpy/fft/meson.build
@@ -0,0 +1,33 @@
+largefile_define = []
+if host_machine.system() == 'aix' or host_machine.system() == 'AIX'
+ largefile_define += '-D_LARGE_FILES'
+endif
+
+py.extension_module('_pocketfft_internal',
+ '_pocketfft.c',
+ c_args: largefile_define,
+ dependencies: np_core_dep,
+ install: true,
+ subdir: 'numpy/fft',
+)
+
+py.install_sources(
+ [
+ '__init__.py',
+ '__init__.pyi',
+ '_pocketfft.py',
+ '_pocketfft.pyi',
+ 'helper.py',
+ 'helper.pyi',
+ ],
+ subdir: 'numpy/fft'
+)
+
+py.install_sources(
+ [
+ 'tests/__init__.py',
+ 'tests/test_helper.py',
+ 'tests/test_pocketfft.py',
+ ],
+ subdir: 'numpy/fft/tests'
+)
diff --git a/numpy/linalg/meson.build b/numpy/linalg/meson.build
new file mode 100644
index 000000000..083692913
--- /dev/null
+++ b/numpy/linalg/meson.build
@@ -0,0 +1,56 @@
+lapack_lite_sources = [
+ 'lapack_lite/f2c.c',
+ 'lapack_lite/f2c_c_lapack.c',
+ 'lapack_lite/f2c_d_lapack.c',
+ 'lapack_lite/f2c_s_lapack.c',
+ 'lapack_lite/f2c_z_lapack.c',
+ 'lapack_lite/f2c_blas.c',
+ 'lapack_lite/f2c_config.c',
+ 'lapack_lite/f2c_lapack.c',
+ 'lapack_lite/python_xerbla.c',
+]
+
+# TODO: ILP64 support
+
+lapack_lite_module_src = ['lapack_litemodule.c']
+if not have_lapack
+ warning('LAPACK was not found, NumPy is using an unoptimized, naive build from sources!')
+ lapack_lite_module_src += lapack_lite_sources
+endif
+
+py.extension_module('lapack_lite',
+ lapack_lite_module_src,
+ dependencies: [np_core_dep, lapack],
+ install: true,
+ subdir: 'numpy/linalg',
+)
+
+_umath_linalg_src = ['umath_linalg.cpp'] + lapack_lite_sources
+
+py.extension_module('_umath_linalg',
+ _umath_linalg_src,
+ dependencies: np_core_dep,
+ link_with: npymath_lib,
+ install: true,
+ subdir: 'numpy/linalg',
+)
+
+py.install_sources(
+ [
+ '__init__.py',
+ '__init__.pyi',
+ 'linalg.py',
+ 'linalg.pyi',
+ ],
+ subdir: 'numpy/linalg'
+)
+
+py.install_sources(
+ [
+ 'tests/__init__.py',
+ 'tests/test_deprecations.py',
+ 'tests/test_linalg.py',
+ 'tests/test_regression.py',
+ ],
+ subdir: 'numpy/linalg/tests'
+)
diff --git a/numpy/meson.build b/numpy/meson.build
new file mode 100644
index 000000000..8b20769d0
--- /dev/null
+++ b/numpy/meson.build
@@ -0,0 +1,154 @@
+# We need -lm for all C code (assuming it uses math functions, which is safe to
+# assume for numpy).
+m_dep = cc.find_library('m', required : false)
+mlib_linkflag = ''
+if m_dep.found()
+ mlib_linkflag = '-lm'
+ add_project_link_arguments(mlib_linkflag, language : 'c')
+endif
+
+# Platform detection
+is_windows = host_machine.system() == 'windows'
+is_mingw = is_windows and cc.get_id() == 'gcc'
+
+if is_windows
+ # For mingw-w64, link statically against the UCRT.
+ gcc_link_args = ['-lucrt', '-static']
+ if is_mingw
+ add_project_link_arguments(gcc_link_args, language: ['c', 'cpp'])
+ # Force gcc to float64 long doubles for compatibility with MSVC
+ # builds, for C only.
+ add_project_arguments('-mlong-double-64', language: 'c')
+ # Make fprintf("%zd") work (see https://github.com/rgommers/scipy/issues/118)
+ add_project_arguments('-D__USE_MINGW_ANSI_STDIO=1', language: ['c', 'cpp'])
+ # Manual add of MS_WIN64 macro when not using MSVC.
+ # https://bugs.python.org/issue28267
+ bitness = run_command('_build_utils/gcc_build_bitness.py').stdout().strip()
+ if bitness == '64'
+ add_project_arguments('-DMS_WIN64', language: ['c', 'cpp'])
+ endif
+ endif
+endif
+
+# Enable UNIX large file support on 32-bit systems (64 bit off_t,
+# lseek -> lseek64, etc.)
+cflags_large_file_support = []
+if host_machine.system() == 'aix'
+ cflags_large_file_support += '-D_LARGE_FILES'
+else
+ cflags_large_file_support += [
+ '-D_FILE_OFFSET_BITS=64',
+ '-D_LARGEFILE_SOURCE=1',
+ '-D_LARGEFILE64_SOURCE=1',
+ ]
+endif
+
+
+# TODO: 64-bit BLAS and LAPACK
+#
+# 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')
+# 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'
+ blas_name = ['openblas', 'OpenBLAS']
+endif
+if lapack_name == 'openblas'
+ lapack_name = ['openblas', 'OpenBLAS']
+endif
+blas = dependency(blas_name, required: false)
+lapack = dependency(lapack_name, required: false)
+
+# BLAS and LAPACK are optional dependencies for NumPy. We can only use a BLAS
+# which provides a CBLAS interface.
+# TODO: add ILP64 support
+have_blas = blas.found() # TODO: and blas.has_cblas()
+have_lapack = lapack.found()
+
+
+# TODO: generate __config__.py (see scipy/meson.build)
+
+# 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')
+__init__pxd30 = fs.copyfile('__init__.cython-30.pxd')
+_cython_tree = [__init__py, __init__pxd, __init__pxd30]
+
+python_sources = [
+ '__init__.cython-30.pxd',
+ '__init__.pxd',
+ '__init__.py',
+ '__init__.pyi',
+ '_distributor_init.py',
+ '_globals.py',
+ '_pytesttester.py',
+ '_pytesttester.pyi',
+ '_version.py',
+ 'conftest.py',
+ 'ctypeslib.py',
+ 'ctypeslib.pyi',
+ 'dual.py',
+ 'matlib.py',
+ 'py.typed',
+ 'version.py'
+]
+
+py.install_sources(
+ python_sources,
+ subdir: 'numpy'
+)
+
+src_file_cli = find_program('_build_utils/process_src_template.py')
+src_file = generator(src_file_cli,
+ arguments : ['@INPUT@', '--outfile', '@OUTPUT@'],
+ output : '@BASENAME@'
+)
+
+tempita_cli = find_program('_build_utils/tempita.py')
+tempita = generator(tempita_cli,
+ arguments : ['@INPUT@', '--outfile', '@OUTPUT@'],
+ output : '@BASENAME@'
+)
+
+pure_subdirs = [
+ '_pyinstaller',
+ '_typing',
+ 'array_api',
+ 'compat',
+ 'distutils',
+ 'doc',
+ 'f2py',
+ 'lib',
+ 'ma',
+ 'matrixlib',
+ 'polynomial',
+ 'testing',
+ 'tests',
+ 'typing',
+]
+
+np_dir = py.get_install_dir() / 'numpy'
+
+foreach subdir: pure_subdirs
+ install_subdir(subdir, install_dir: np_dir)
+endforeach
+
+custom_target('__config__.py',
+ output: '__config__.py',
+ input: '__config__.py.in',
+ command: [tempita_cli, '@INPUT@', '-o', '@OUTPUT@'],
+ install: true,
+ install_dir: np_dir
+)
+
+subdir('core')
+subdir('fft')
+subdir('linalg')
+subdir('random')
diff --git a/numpy/random/meson.build b/numpy/random/meson.build
new file mode 100644
index 000000000..cc61c66dd
--- /dev/null
+++ b/numpy/random/meson.build
@@ -0,0 +1,164 @@
+# Build npyrandom library
+# -----------------------
+npyrandom_sources = [
+ 'src/distributions/logfactorial.c',
+ 'src/distributions/distributions.c',
+ 'src/distributions/random_mvhg_count.c',
+ 'src/distributions/random_mvhg_marginals.c',
+ 'src/distributions/random_hypergeometric.c',
+]
+
+npyrandom_lib = static_library('npyrandom',
+ npyrandom_sources,
+ c_args: staticlib_cflags,
+ # include_directories: '../core/include',
+ dependencies: [py_dep, np_core_dep],
+ install: true,
+ install_dir: np_dir / 'random/lib',
+)
+
+# Build Cython extensions for numpy.random
+# ----------------------------------------
+# pyx -> c transpile output depends on copied __init__.py and pxd files
+_cython_tree_random = [
+ fs.copyfile('__init__.py'),
+ fs.copyfile('__init__.pxd'),
+ fs.copyfile('_common.pxd'),
+ fs.copyfile('bit_generator.pxd'),
+ fs.copyfile('c_distributions.pxd'),
+]
+# Need to use `custom_target` because we need to install this .pxd file
+_cython_tree_random += custom_target('_bounded_integer_pxd',
+ output: '_bounded_integers.pxd',
+ input: '_bounded_integers.pxd.in',
+ command: [tempita_cli, '@INPUT@', '-o', '@OUTPUT@'],
+ install: true,
+ install_dir: np_dir / 'random'
+)
+
+_bounded_integers_pyx = custom_target('_bounded_integer_pyx',
+ output: '_bounded_integers.pyx',
+ input: '_bounded_integers.pyx.in',
+ command: [tempita_cli, '@INPUT@', '-o', '@OUTPUT@'],
+)
+
+c_args_random = [
+ cflags_large_file_support,
+ '-DNPY_NO_DEPRECATED_API=0', # Cython still uses old NumPy C API
+]
+if host_machine.system() == 'cygwin'
+ c_args_random += ['-Wl,--export-all-symbols']
+endif
+
+# name, sources, extra link libs, extra c_args
+random_pyx_sources = [
+ ['_bounded_integers', _bounded_integers_pyx, [], npymath_lib],
+ ['_common', '_common.pyx', [], []],
+ ['_mt19937', ['_mt19937.pyx', 'src/mt19937/mt19937.c', 'src/mt19937/mt19937-jump.c'], [], []],
+ ['_philox', ['_philox.pyx', 'src/philox/philox.c'], [], []],
+ ['_pcg64', ['_pcg64.pyx', 'src/pcg64/pcg64.c'], ['-U__GNUC_GNU_INLINE__'], []],
+ ['_sfc64', ['_sfc64.pyx', 'src/sfc64/sfc64.c'], [], []],
+ ['bit_generator', 'bit_generator.pyx', [], []],
+ # The `fs.copyfile` usage here is needed because these two .pyx files import
+ # from _bounded_integers,and its pxd file is only present in the build directory
+ ['_generator', fs.copyfile('_generator.pyx'), [], npymath_lib],
+ ['mtrand', [
+ fs.copyfile('mtrand.pyx'),
+ 'src/distributions/distributions.c',
+ 'src/legacy/legacy-distributions.c'
+ ], ['-DNPY_RANDOM_LEGACY=1'], npymath_lib,
+ ],
+]
+foreach gen: random_pyx_sources
+ py.extension_module(gen[0],
+ [gen[1], _cython_tree, _cython_tree_random],
+ c_args: [c_args_random, gen[2]],
+ include_directories: 'src',
+ dependencies: np_core_dep,
+ link_with: [npyrandom_lib, gen[3]],
+ install: true,
+ subdir: 'numpy/random',
+ )
+endforeach
+
+# Install Python sources, stub files, tests, examples and license
+# ---------------------------------------------------------------
+py.install_sources(
+ [
+ '__init__.pxd',
+ '__init__.py',
+ '__init__.pyi',
+ '_common.pxd',
+ '_generator.pyi',
+ '_mt19937.pyi',
+ '_pcg64.pyi',
+ '_pickle.py',
+ '_philox.pyi',
+ '_sfc64.pyi',
+ 'bit_generator.pxd',
+ 'bit_generator.pyi',
+ 'c_distributions.pxd',
+ 'LICENSE.md',
+ 'mtrand.pyi',
+ ],
+ subdir: 'numpy/random'
+)
+
+py.install_sources(
+ [
+ 'tests/__init__.py',
+ 'tests/test_direct.py',
+ 'tests/test_extending.py',
+ 'tests/test_generator_mt19937.py',
+ 'tests/test_generator_mt19937_regressions.py',
+ 'tests/test_random.py',
+ 'tests/test_randomstate.py',
+ 'tests/test_randomstate_regression.py',
+ 'tests/test_regression.py',
+ 'tests/test_seed_sequence.py',
+ 'tests/test_smoke.py',
+ ],
+ subdir: 'numpy/random/tests'
+)
+
+py.install_sources(
+ [
+ 'tests/data/__init__.py',
+ 'tests/data/mt19937-testset-1.csv',
+ 'tests/data/mt19937-testset-2.csv',
+ 'tests/data/pcg64-testset-1.csv',
+ 'tests/data/pcg64-testset-2.csv',
+ 'tests/data/pcg64dxsm-testset-1.csv',
+ 'tests/data/pcg64dxsm-testset-2.csv',
+ 'tests/data/philox-testset-1.csv',
+ 'tests/data/philox-testset-2.csv',
+ 'tests/data/sfc64-testset-1.csv',
+ 'tests/data/sfc64-testset-2.csv',
+ ],
+ subdir: 'numpy/random/tests/data'
+)
+
+py.install_sources(
+ [
+ '_examples/cffi/extending.py',
+ '_examples/cffi/parse.py',
+ ],
+ subdir: 'numpy/random/_examples/cffi'
+)
+
+py.install_sources(
+ [
+ '_examples/cython/extending.pyx',
+ '_examples/cython/extending_distributions.pyx',
+ '_examples/cython/setup.py',
+ ],
+ subdir: 'numpy/random/_examples/cython'
+)
+
+py.install_sources(
+ [
+ '_examples/numba/extending.py',
+ '_examples/numba/extending_distributions.py',
+ ],
+ subdir: 'numpy/random/_examples/numba'
+)
diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py
index 0c652e01f..35eb4fd00 100644
--- a/numpy/tests/test_public_api.py
+++ b/numpy/tests/test_public_api.py
@@ -320,6 +320,7 @@ SKIP_LIST = [
"numpy.core.code_generators.generate_ufunc_api",
"numpy.core.code_generators.numpy_api",
"numpy.core.code_generators.generate_umath_doc",
+ "numpy.core.code_generators.verify_c_api_version",
"numpy.core.cversions",
"numpy.core.generate_numpy_api",
"numpy.distutils.msvc9compiler",
diff --git a/numpy/version.py b/numpy/version.py
index d5657d0d0..d9d2fe1b7 100644
--- a/numpy/version.py
+++ b/numpy/version.py
@@ -4,12 +4,20 @@ from ._version import get_versions
__ALL__ = ['version', '__version__', 'full_version', 'git_revision', 'release']
+
+_built_with_meson = False
+try:
+ from ._version_meson import get_versions
+ _built_with_meson = True
+except ImportError:
+ from ._version import get_versions
+
vinfo: dict[str, str] = get_versions()
version = vinfo["version"]
__version__ = vinfo.get("closest-tag", vinfo["version"])
-full_version = vinfo['version']
git_revision = vinfo['full-revisionid']
release = 'dev0' not in version and '+' not in version
-short_version = vinfo['version'].split("+")[0]
+full_version = version
+short_version = version.split("+")[0]
del get_versions, vinfo
diff --git a/pyproject.toml b/pyproject.toml
index 60e7f5826..b02250052 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,11 +1,64 @@
[build-system]
-# Minimum requirements for the build system to execute.
+# Uncomment this line in order to build with Meson by default
+#build-backend = "mesonpy"
requires = [
+ # setuptools, wheel and Cython are needed for the setup.py based build
"setuptools==59.2.0",
+ # `wheel` is needed for non-isolated builds, given that `meson-python`
+ # doesn't list it as a runtime requirement (at least in 0.11.0) - it's
+ # likely to be removed as a dependency in meson-python 0.12.0.
"wheel==0.37.0",
"Cython>=0.29.30,<3.0",
+ "meson-python>=0.10.0",
]
+[project]
+name = "numpy"
+
+# Using https://peps.python.org/pep-0639/
+# which is still in draft
+license = {text = "BSD-3-Clause"}
+license-files.paths = [
+ "LICENSE.txt",
+ "LICENSES_bundles.txt"
+]
+
+description = "Fundamental package for array computing in Python"
+maintainers = [
+ {name = "NumPy Developers", email="numpy-discussion@python.org"},
+]
+requires-python = ">=3.8"
+readme = "README.md"
+classifiers = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Intended Audience :: Science/Research',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Programming Language :: C',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
+ 'Programming Language :: Python :: 3.10',
+ 'Programming Language :: Python :: 3.11',
+ 'Programming Language :: Python :: 3 :: Only',
+ 'Programming Language :: Python :: Implementation :: CPython',
+ 'Topic :: Software Development',
+ 'Topic :: Scientific/Engineering',
+ 'Typing :: Typed',
+ 'Operating System :: Microsoft :: Windows',
+ 'Operating System :: POSIX',
+ 'Operating System :: Unix',
+ 'Operating System :: MacOS',
+]
+dynamic = ["version"]
+
+[project.urls]
+homepage = "https://numpy.org"
+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"
[tool.towncrier]
# Do no set this since it is hard to import numpy inside the source directory
@@ -104,3 +157,10 @@ environment = { OPENBLAS64_="openblas", OPENBLAS="", NPY_USE_BLAS_ILP64="1", CFL
[[tool.cibuildwheel.overrides]]
select = "*-win32"
environment = { OPENBLAS64_="", OPENBLAS="openblas", NPY_USE_BLAS_ILP64="0", CFLAGS="-m32", LDFLAGS="-m32" }
+
+[tool.devpy]
+package = 'numpy'
+
+[tool.devpy.commands]
+"Build" = ["devpy.build", "devpy.test"]
+"Environments" = ["devpy.shell", "devpy.ipython", "devpy.python"]
diff --git a/tools/check_installed_files.py b/tools/check_installed_files.py
new file mode 100644
index 000000000..f15ca7969
--- /dev/null
+++ b/tools/check_installed_files.py
@@ -0,0 +1,86 @@
+"""
+Check if all the test and .pyi files are installed after building.
+
+Examples::
+
+ $ python check_installed_files.py install_dirname
+
+ install_dirname:
+ the relative path to the directory where NumPy is installed after
+ building and running `meson install`.
+
+Notes
+=====
+
+The script will stop on encountering the first missing file in the install dir,
+it will not give a full listing. This should be okay, because the script is
+meant for use in CI so it's not like many files will be missing at once.
+
+"""
+
+import os
+import glob
+import sys
+
+
+CUR_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__)))
+ROOT_DIR = os.path.dirname(CUR_DIR)
+NUMPY_DIR = os.path.join(ROOT_DIR, 'numpy')
+
+
+# Files whose installation path will be different from original one
+changed_installed_path = {
+ #'numpy/_build_utils/some_file.py': 'numpy/lib/some_file.py'
+}
+
+
+def main(install_dir):
+ INSTALLED_DIR = os.path.join(ROOT_DIR, install_dir)
+ if not os.path.exists(INSTALLED_DIR):
+ raise ValueError(
+ f"Provided install dir {INSTALLED_DIR} does not exist"
+ )
+
+ numpy_test_files = get_files(NUMPY_DIR, kind='test')
+ installed_test_files = get_files(INSTALLED_DIR, kind='test')
+
+ # Check test files detected in repo are installed
+ for test_file in numpy_test_files.keys():
+ if test_file not in installed_test_files.keys():
+ raise Exception(
+ "%s is not installed" % numpy_test_files[test_file]
+ )
+
+ print("----------- All the test files were installed --------------")
+
+ numpy_pyi_files = get_files(NUMPY_DIR, kind='stub')
+ installed_pyi_files = get_files(INSTALLED_DIR, kind='stub')
+
+ # Check *.pyi files detected in repo are installed
+ for pyi_file in numpy_pyi_files.keys():
+ if pyi_file not in installed_pyi_files.keys():
+ raise Exception("%s is not installed" % numpy_pyi_files[pyi_file])
+
+ print("----------- All the .pyi files were installed --------------")
+
+
+def get_files(dir_to_check, kind='test'):
+ files = dict()
+ patterns = {
+ 'test': f'{dir_to_check}/**/test_*.py',
+ 'stub': f'{dir_to_check}/**/*.pyi',
+ }
+ for path in glob.glob(patterns[kind], recursive=True):
+ relpath = os.path.relpath(path, dir_to_check)
+ files[relpath] = path
+
+ return files
+
+
+if __name__ == '__main__':
+ if not len(sys.argv) == 2:
+ raise ValueError("Incorrect number of input arguments, need "
+ "check_installation.py relpath/to/installed/numpy")
+
+ install_dir = sys.argv[1]
+ main(install_dir)