diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 88cbdd8f..a1e8e0c2 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -44,7 +44,7 @@ jobs: if: ${{ !github.event.pull_request || github.event.action != 'closed' }} shell: bash -l {0} run: | - pip install numpy cython setuptools">=77" scikit-build cmake sphinx sphinx_rtd_theme furo pydot graphviz sphinxcontrib-programoutput sphinxcontrib-googleanalytics sphinx_design + pip install meson-python ninja cython cmake numpy sphinx sphinx_rtd_theme furo pydot graphviz sphinxcontrib-programoutput sphinxcontrib-googleanalytics sphinx_design - name: Checkout repo uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: diff --git a/.github/workflows/build-with-clang.yml b/.github/workflows/build-with-clang.yml index f18e6cf0..45137e15 100644 --- a/.github/workflows/build-with-clang.yml +++ b/.github/workflows/build-with-clang.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: python: ["3.10", "3.11", "3.12", "3.13", "3.14"] - numpy_version: ["numpy>=2"] + numpy_version: ["'numpy>=2'"] env: ONEAPI_ROOT: /opt/intel/oneapi @@ -38,7 +38,6 @@ jobs: - name: Install Intel OneAPI run: | sudo apt-get install intel-oneapi-compiler-dpcpp-cpp - sudo apt-get install intel-oneapi-tbb sudo apt-get install intel-oneapi-mkl-devel - name: Setup Python @@ -54,8 +53,8 @@ jobs: - name: Install mkl_random dependencies run: | - pip install cython setuptools">=77" - pip install "${{ matrix.numpy_version }}" + pip install meson-python ninja cython cmake + pip install ${{ matrix.numpy_version }} - name: List oneAPI folder content run: ls "${{ env.ONEAPI_ROOT }}/compiler" diff --git a/.github/workflows/build-with-standard-clang.yml b/.github/workflows/build-with-standard-clang.yml new file mode 100644 index 00000000..97c1d48b --- /dev/null +++ b/.github/workflows/build-with-standard-clang.yml @@ -0,0 +1,62 @@ +name: Build project with standard clang compiler + +on: + pull_request: + push: + branches: [master] + +permissions: read-all + +jobs: + build-with-standard-clang: + runs-on: ubuntu-latest + + strategy: + matrix: + python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + numpy_version: ["'numpy>=2'"] + + env: + COMPILER_ROOT: /usr/bin + + defaults: + run: + shell: bash -el {0} + + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@3155a141048f8f89c06b4cdae32e7853e97536bc # 0.13.0 + with: + access_token: ${{ github.token }} + + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang + + - name: Setup Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: ${{ matrix.python }} + architecture: x64 + + - name: Checkout repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - name: Install mkl_random dependencies + run: | + pip install meson-python ninja cmake cython mkl-devel + pip install ${{ matrix.numpy_version }} + + - name: Build mkl_random + run: | + export CC=${{ env.COMPILER_ROOT }}/clang + export CXX=${{ env.COMPILER_ROOT }}/clang++ + pip install -e . --no-build-isolation --no-deps --verbose + + - name: Run mkl_random tests + run: | + pip install pytest + python -m pytest -sv --pyargs mkl_random diff --git a/.github/workflows/build_pip.yml b/.github/workflows/build_pip.yml new file mode 100644 index 00000000..798b1ff7 --- /dev/null +++ b/.github/workflows/build_pip.yml @@ -0,0 +1,46 @@ +name: Editable build using pip and pre-release NumPy + +on: + push: + branches: + - master + pull_request: + +permissions: read-all + +jobs: + build: + runs-on: ubuntu-latest + defaults: + run: + shell: bash -el {0} + + strategy: + matrix: + python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + use_pre: ["", "--pre"] + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - uses: conda-incubator/setup-miniconda@fc2d68f6413eb2d87b895e92f8584b5b94a10167 # v3.3.0 + with: + miniforge-version: latest + channels: conda-forge + activate-environment: test + python-version: ${{ matrix.python }} + + - name: Install MKL + run: | + conda install mkl-devel + + - name: Build with pip + run: | + pip install --no-cache-dir meson-python ninja cmake cython + pip install --no-cache-dir numpy ${{ matrix.use_pre }} + pip install -e . --no-build-isolation --no-deps --verbose + pip install --no-cache-dir pytest + pip list + python -m pytest -v mkl_random/tests diff --git a/.github/workflows/conda-package-cf.yml b/.github/workflows/conda-package-cf.yml index 1760991b..0fb666eb 100644 --- a/.github/workflows/conda-package-cf.yml +++ b/.github/workflows/conda-package-cf.yml @@ -323,3 +323,157 @@ jobs: run: | conda activate ${{ env.TEST_ENV_NAME }} pytest -v --pyargs ${{ env.MODULE_NAME }} + + build_osx: + runs-on: macos-26-intel + strategy: + matrix: + include: + - python: "3.10" + numpy: "2.2" + - python: "3.11" + numpy: "2.3" + - python: "3.12" + numpy: "2.3" + - python: "3.13" + numpy: "2.3" + - python: "3.14" + numpy: "2.3" + + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # v0.13.1 + with: + access_token: ${{ github.token }} + + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 + with: + miniforge-version: latest + activate-environment: build + channels: conda-forge + python-version: ${{ matrix.python }} + + - name: Cache conda packages + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + env: + CACHE_NUMBER: 0 # Increase to reset cache + with: + path: /Users/runner/conda_pkgs_dir + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + restore-keys: | + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- + + - name: Install conda-build + shell: bash -el {0} + run: | + conda install -n base -y conda-build + conda list -n base + + - name: Store conda paths as envs + shell: bash -el {0} + run: | + echo "CONDA_BLD=$CONDA/conda-bld/osx-64/" >> "$GITHUB_ENV" + + - name: Build conda package + shell: bash -el {0} + run: | + CHANNELS=(-c conda-forge --override-channels) + VERSIONS=(--python "${{ matrix.python }}" --numpy "${{ matrix.numpy }}") + TEST=(--no-test) + + conda build \ + "${TEST[@]}" \ + "${VERSIONS[@]}" \ + "${CHANNELS[@]}" \ + conda-recipe-cf + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda + + test_osx: + needs: build_osx + runs-on: macos-26-intel + strategy: + matrix: + include: + - python: "3.10" + numpy: "2.2" + - python: "3.11" + numpy: "2.3" + - python: "3.12" + numpy: "2.3" + - python: "3.13" + numpy: "2.3" + - python: "3.14" + numpy: "2.3" + + steps: + - name: Download artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + + - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 + with: + miniforge-version: latest + channels: conda-forge + activate-environment: base + + - name: Install conda-index + shell: bash -el {0} + run: conda install -n base -y conda-index + + - name: Create conda channel + shell: bash -el {0} + run: | + mkdir -p "$GITHUB_WORKSPACE/channel/osx-64" + conda index "$GITHUB_WORKSPACE/channel" || exit 1 + mv "${PACKAGE_NAME}"-*.conda "$GITHUB_WORKSPACE/channel/osx-64" || exit 1 + conda index "$GITHUB_WORKSPACE/channel" || exit 1 + # Test channel + conda search "$PACKAGE_NAME" -c "$GITHUB_WORKSPACE/channel" --override-channels --info --json > "$GITHUB_WORKSPACE/ver.json" + cat ver.json + + - name: Collect dependencies + shell: bash -el {0} + run: | + PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" + export PACKAGE_VERSION + conda create -n "${{ env.TEST_ENV_NAME }}" "${PACKAGE_NAME}=${PACKAGE_VERSION}" "python=${{ matrix.python }}" "numpy=${{ matrix.numpy }}" -c "$GITHUB_WORKSPACE/channel" -c conda-forge --override-channels --only-deps --dry-run > lockfile + cat lockfile + + - name: Cache conda packages + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + env: + CACHE_NUMBER: 0 # Increase to reset cache + with: + path: /Users/runner/conda_pkgs_dir + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + restore-keys: | + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- + + - name: Install mkl_random + shell: bash -el {0} + run: | + PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" + export PACKAGE_VERSION + conda create -n "${{ env.TEST_ENV_NAME }}" "${PACKAGE_NAME}=${PACKAGE_VERSION}" pytest "python=${{ matrix.python }}" "numpy=${{ matrix.numpy }}" -c "$GITHUB_WORKSPACE/channel" -c conda-forge --override-channels + # Test installed packages + conda list -n "${{ env.TEST_ENV_NAME }}" + + - name: Run tests + shell: bash -el {0} + run: | + conda activate ${{ env.TEST_ENV_NAME }} + pytest -vv --pyargs ${{ env.MODULE_NAME }} diff --git a/.gitignore b/.gitignore index 89fa448a..d16f217a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,7 @@ -# CMake build and local install directory +# Meson build and local install directory build/ +.mesonpy-* mkl_random.egg-info/ # Byte-compiled / optimized / DLL files __pycache__/ - -mkl_random/src/mklrand.c -mkl_random/mklrand.cpp -mkl_random/mklrand.cpython*.so diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f0c3d0..96b27dcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Removed `numpy-base` dependency and `USE_NUMPY_BASE` environment variable from conda recipe [gh-124](https://github.com/IntelPython/mkl_random/pull/124) +* Migrated the build system from `setuptools` to `meson-python`, removing `setup.py` in favor of `meson.build` [gh-113](https://github.com/IntelPython/mkl_random/pull/113) ### Fixed * Fixed compatibility with NumPy 2.5 by replacing the deprecated in-place array `shape` assignment with `reshape`, and by replacing the deprecated `numpy.testing.suppress_warnings` usage in tests with `pytest.warns` [gh-137](https://github.com/IntelPython/mkl_random/pull/137) diff --git a/README.md b/README.md index 9cde034e..7e5f06a8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ ## `mkl_random` -- a NumPy-based Python interface to IntelĀ® oneAPI Math Kernel Library (OneMKL) Random Number Generation functionality +[![Conda package](https://github.com/IntelPython/mkl_random/actions/workflows/conda-package.yml/badge.svg)](https://github.com/IntelPython/mkl_random/actions/workflows/conda-package.yml) +[![Editable build using pip and pre-release NumPy](https://github.com/IntelPython/mkl_random/actions/workflows/build_pip.yml/badge.svg)](https://github.com/IntelPython/mkl_random/actions/workflows/build_pip.yml) [![Conda package using conda-forge](https://github.com/IntelPython/mkl_random/actions/workflows/conda-package-cf.yml/badge.svg)](https://github.com/IntelPython/mkl_random/actions/workflows/conda-package-cf.yml) [![Coverity Scan Build Status](https://scan.coverity.com/projects/33198/badge.svg)](https://scan.coverity.com/projects/intelpython-mkl_random) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/IntelPython/mkl_random/badge)](https://securityscorecards.dev/viewer/?uri=github.com/IntelPython/mkl_random) @@ -134,7 +136,25 @@ with mkl_random.mkl_random(): --- -To build `mkl_random` from sources on Linux: - - install a recent version of MKL, if necessary; - - execute `source /path_to_oneapi/mkl/latest/env/vars.sh`; - - execute `python -m pip install .` +# Building from source + +A C++ compiler, IntelĀ® oneAPI Math Kernel Library (oneMKL), and NumPy are required +to build `mkl_random` from source. + +Executing +```sh +python -m pip install . +``` +will pull in the required build dependencies, including `mkl` and `numpy`, and build `mkl_random`. + +If you already have `mkl` and `numpy` installed (from your system or a conda environment) +and want to reuse them instead of pulling fresh copies into an isolated build, first +install the build dependencies: +```sh +pip install meson-python cmake ninja cython numpy mkl-devel +``` + +then build against the existing installation with: +```sh +python -m pip install --no-build-isolation --no-deps . +``` diff --git a/conda-recipe-cf/bld.bat b/conda-recipe-cf/bld.bat index 29a732bd..a08c27bb 100644 --- a/conda-recipe-cf/bld.bat +++ b/conda-recipe-cf/bld.bat @@ -1,15 +1,2 @@ -@rem Remember to source the compiler - -set MKLROOT=%CONDA_PREFIX% - -rem Build wheel package -if NOT "%WHEELS_OUTPUT_FOLDER%"=="" ( - %PYTHON% -m pip wheel --no-build-isolation --no-deps . - if errorlevel 1 exit 1 - copy mkl_random*.whl %WHEELS_OUTPUT_FOLDER% - if errorlevel 1 exit 1 -) ELSE ( - rem Build conda package - %PYTHON% -m pip install --no-build-isolation --no-deps . - if errorlevel 1 exit 1 -) +%PYTHON% -m pip install --no-build-isolation --no-deps . +if errorlevel 1 exit 1 diff --git a/conda-recipe-cf/build.sh b/conda-recipe-cf/build.sh index f513746f..72e5e4e6 100644 --- a/conda-recipe-cf/build.sh +++ b/conda-recipe-cf/build.sh @@ -1,18 +1,3 @@ -#!/bin/bash -x +#!/bin/bash -ex -export CFLAGS="-I$PREFIX/include $CFLAGS" -export LDFLAGS="-Wl,-rpath,\$ORIGIN/../.. -Wl,-rpath,\$ORIGIN/../../.. -L${PREFIX}/lib ${LDFLAGS}" -export MKLROOT=$CONDA_PREFIX - -read -r GLIBC_MAJOR GLIBC_MINOR <<<"$(conda list '^sysroot_linux-64$' \ - | tail -n 1 | awk '{print $2}' | grep -oP '\d+' | head -n 2 | tr '\n' ' ')" - -# Build wheel package -if [ -n "${WHEELS_OUTPUT_FOLDER}" ]; then - $PYTHON -m pip wheel --no-build-isolation --no-deps . - ${PYTHON} -m wheel tags --remove --platform-tag "manylinux_${GLIBC_MAJOR}_${GLIBC_MINOR}_x86_64" mkl_random*.whl - cp mkl_random*.whl "${WHEELS_OUTPUT_FOLDER}" -else - # Build conda package - $PYTHON -m pip install --no-build-isolation --no-deps . -fi +$PYTHON -m pip install --no-build-isolation --no-deps . diff --git a/conda-recipe-cf/conda_build_config.yaml b/conda-recipe-cf/conda_build_config.yaml index 822fd77b..a830d0aa 100644 --- a/conda-recipe-cf/conda_build_config.yaml +++ b/conda-recipe-cf/conda_build_config.yaml @@ -8,6 +8,12 @@ c_stdlib: # [linux] - sysroot # [linux] c_stdlib_version: # [linux] - '2.28' # [linux] +c_compiler: # [osx] + - clang # [osx] +cxx_compiler: # [osx] + - clangxx # [osx] +c_stdlib: # [osx] + - macosx_deployment_target # [osx] c_stdlib: # [win] - vs # [win] cxx_compiler: # [win] diff --git a/conda-recipe-cf/meta.yaml b/conda-recipe-cf/meta.yaml index 4effa580..c1dcd498 100644 --- a/conda-recipe-cf/meta.yaml +++ b/conda-recipe-cf/meta.yaml @@ -7,10 +7,9 @@ source: build: number: {{ GIT_DESCRIBE_NUMBER }} - script_env: - - WHEELS_OUTPUT_FOLDER ignore_run_exports: - blas + - numpy requirements: build: @@ -18,9 +17,11 @@ requirements: - {{ compiler('cxx') }} - {{ stdlib('c') }} host: + - meson-python >=0.16.0 + - cmake + - ninja - python - python-gil # [py>=314] - - setuptools >=77 - mkl-devel - cython - numpy @@ -28,7 +29,7 @@ requirements: - wheel >=0.41.3 run: - python - - python-gil [py>=314] + - python-gil # [py>=314] - {{ pin_compatible('numpy', min_pin="x.x", max_pin="x") }} - {{ pin_compatible('mkl', min_pin="x.x", max_pin="x") }} diff --git a/conda-recipe/bld.bat b/conda-recipe/bld.bat index 29a732bd..38d7c254 100644 --- a/conda-recipe/bld.bat +++ b/conda-recipe/bld.bat @@ -1,15 +1,20 @@ -@rem Remember to source the compiler +:: -wnx flags mean: --wheel --no-isolation --skip-dependency-check +:: -Ccompile-args=-v makes ninja print full compiler commands (verbose build) +%PYTHON% -m build -w -n -x -Ccompile-args=-v +if %ERRORLEVEL% neq 0 exit 1 -set MKLROOT=%CONDA_PREFIX% +for /f %%f in ('dir /b /S .\dist') do ( + %PYTHON% -m pip install %%f ^ + --no-build-isolation ^ + --no-deps ^ + --only-binary :all: ^ + --no-index ^ + --prefix %PREFIX% ^ + -vv + if %ERRORLEVEL% neq 0 exit 1 +) -rem Build wheel package if NOT "%WHEELS_OUTPUT_FOLDER%"=="" ( - %PYTHON% -m pip wheel --no-build-isolation --no-deps . - if errorlevel 1 exit 1 - copy mkl_random*.whl %WHEELS_OUTPUT_FOLDER% - if errorlevel 1 exit 1 -) ELSE ( - rem Build conda package - %PYTHON% -m pip install --no-build-isolation --no-deps . - if errorlevel 1 exit 1 + copy dist\mkl_random*.whl %WHEELS_OUTPUT_FOLDER% + if %ERRORLEVEL% neq 0 exit 1 ) diff --git a/conda-recipe/build.sh b/conda-recipe/build.sh index f513746f..55b00217 100644 --- a/conda-recipe/build.sh +++ b/conda-recipe/build.sh @@ -1,18 +1,29 @@ -#!/bin/bash -x +#!/bin/bash -ex -export CFLAGS="-I$PREFIX/include $CFLAGS" -export LDFLAGS="-Wl,-rpath,\$ORIGIN/../.. -Wl,-rpath,\$ORIGIN/../../.. -L${PREFIX}/lib ${LDFLAGS}" -export MKLROOT=$CONDA_PREFIX +if [ -d "build" ]; then + rm -rf build +fi read -r GLIBC_MAJOR GLIBC_MINOR <<<"$(conda list '^sysroot_linux-64$' \ | tail -n 1 | awk '{print $2}' | grep -oP '\d+' | head -n 2 | tr '\n' ' ')" -# Build wheel package -if [ -n "${WHEELS_OUTPUT_FOLDER}" ]; then - $PYTHON -m pip wheel --no-build-isolation --no-deps . - ${PYTHON} -m wheel tags --remove --platform-tag "manylinux_${GLIBC_MAJOR}_${GLIBC_MINOR}_x86_64" mkl_random*.whl - cp mkl_random*.whl "${WHEELS_OUTPUT_FOLDER}" -else - # Build conda package - $PYTHON -m pip install --no-build-isolation --no-deps . +# -wnx flags mean: --wheel --no-isolation --skip-dependency-check +# -Ccompile-args=-v makes ninja print full compiler commands (verbose build) +${PYTHON} -m build -w -n -x -Ccompile-args=-v + +${PYTHON} -m wheel tags --remove \ + --platform-tag "manylinux_${GLIBC_MAJOR}_${GLIBC_MINOR}_x86_64" \ + dist/mkl_random*.whl + +${PYTHON} -m pip install dist/mkl_random*.whl \ + --no-build-isolation \ + --no-deps \ + --only-binary :all: \ + --no-index \ + --prefix "${PREFIX}" \ + -vv + +# Copy wheel package +if [[ -d "${WHEELS_OUTPUT_FOLDER}" ]]; then + cp dist/mkl_random*.whl "${WHEELS_OUTPUT_FOLDER[@]}" fi diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 4de995a0..dbdedbbe 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -11,6 +11,7 @@ build: - WHEELS_OUTPUT_FOLDER ignore_run_exports: - blas + - numpy requirements: build: @@ -18,9 +19,12 @@ requirements: - {{ compiler('cxx') }} - {{ stdlib('c') }} host: + - meson-python >=0.16.0 + - python-build >=1.2.2 + - cmake + - ninja - python - python-gil # [py>=314] - - setuptools >=77 - mkl-devel - cython - numpy diff --git a/docs/source/maintenance/index.rst b/docs/source/maintenance/index.rst index 128b824a..87ea22b6 100644 --- a/docs/source/maintenance/index.rst +++ b/docs/source/maintenance/index.rst @@ -21,17 +21,18 @@ Make sure to install Python packages required to build :mod:`mkl_random`: * :mod:`python` * :mod:`numpy` * :mod:`cython` -* :mod:`setuptools` +* :mod:`meson-python` +* :mod:`ninja` +* :mod:`cmake` +* :mod:`mkl-devel` -You would also need Intel(R) MKL library and its headers. Set :code:`MKLROOT` environment -variable so that :code:`${MKLROOT}/include/mkl.h` and :code:`${MKLROOT}/lib/libmkl_rt.so` -can be found. +The Intel(R) MKL library and its headers are provided by the :mod:`mkl-devel` +package and located through CMake, so no environment variable needs to be set. .. code-block:: bash :caption: Building mkl_random - $ export MKLROOT= - python -m pip install . + python -m pip install . --no-build-isolation --no-deps To run test suite, install :mod:`pytest`, and run diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..2ff5a1c1 --- /dev/null +++ b/meson.build @@ -0,0 +1,115 @@ +project( + 'mkl_random', + ['c', 'cython'], + version: run_command( + find_program('python3', 'python'), + ['-c', 'exec(open("mkl_random/_version.py").read()); print(__version__)'], + check: true + ).stdout().strip(), + meson_version: '>=1.8.3', + default_options: [ + 'cpp_std=c++11', + 'buildtype=release', + ] +) + +py = import('python').find_installation(pure: false) +py_dep = py.dependency() + +# numpy includes +np_dir = run_command(py, + ['-c', 'import numpy; print(numpy.get_include())'], + check: true +).stdout().strip() + +inc_np = include_directories(np_dir, 'mkl_random/src') + +# compiler/linker +cpp_args = [ + '-D_FILE_OFFSET_BITS=64', + '-D_LARGEFILE_SOURCE=1', + '-D_LARGEFILE64_SOURCE=1', + '-DPY_ARRAY_UNIQUE_SYMBOL=mkl_random_ext', + '-DNDEBUG' +] +link_args = [] + +rpath_link_args = [] +if host_machine.system() != 'windows' + if host_machine.system() == 'darwin' + origin = '@loader_path' + else + origin = '$ORIGIN' + endif + + rpath_link_args = [ + '-Wl,-rpath,' + origin / '../..', + '-Wl,-rpath,' + origin / '../../..', + ] +endif + +mkl_dep = dependency('MKL', method: 'cmake', + modules: ['MKL::MKL'], + cmake_args: [ + '-DMKL_ARCH=intel64', + '-DMKL_LINK=sdl', + ], + required: true +) + +# cpp must be added after MKL detection: +# MKLConfig.cmake runs check_cxx_compiler_flag when CXX is present +# in the cmake toolchain which fails with non-Intel clang++ +add_languages('cpp', native: false) +cpp = meson.get_compiler('cpp') + +if cpp.get_argument_syntax() == 'msvc' + link_args += ['Advapi32.lib'] +else + cpp_args += ['-Wno-unused-but-set-variable', '-Wno-unused-function'] +endif + +py.extension_module( + 'mklrand', + sources: [ + 'mkl_random/mklrand.pyx', + 'mkl_random/src/mkl_distributions.cpp', + 'mkl_random/src/randomkit.cpp' + ], + include_directories: inc_np, + dependencies: [mkl_dep, py_dep], + cpp_args: cpp_args, + link_args: link_args + rpath_link_args, + override_options: ['cython_language=cpp'], + install: true, + subdir: 'mkl_random' +) + +# Python sources +py.install_sources( + [ + 'mkl_random/__init__.py', + 'mkl_random/__main__.py', + 'mkl_random/_init_helper.py', + 'mkl_random/_patch_numpy.py', + 'mkl_random/_patch_startup.py', + 'mkl_random/_version.py', + 'mkl_random/patch.py', + 'mkl_random/with_patch.py', + ], + subdir: 'mkl_random' +) + +py.install_sources( + [ + 'mkl_random/interfaces/__init__.py', + 'mkl_random/interfaces/_numpy_random.py', + 'mkl_random/interfaces/numpy_random.py', + ], + subdir: 'mkl_random/interfaces' +) + +install_subdir( + 'mkl_random/tests', + install_dir: py.get_install_dir() / 'mkl_random' +) diff --git a/mkl_random/src/generate_mklrand_c.py b/mkl_random/src/generate_mklrand_c.py deleted file mode 100644 index 744223ed..00000000 --- a/mkl_random/src/generate_mklrand_c.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -from __future__ import absolute_import, division, print_function - -import os -import re -import sys - -unused_internal_funcs = [ - "__Pyx_PrintItem", - "__Pyx_PrintNewline", - "__Pyx_ReRaise", - # '__Pyx_GetExcValue', - "__Pyx_ArgTypeTest", - "__Pyx_SetVtable", - "__Pyx_GetVtable", - "__Pyx_CreateClass", -] - -if __name__ == "__main__": - # Use cython here so that long docstrings are broken up. - # This is needed for some VC++ compilers. - os.system("cython mklrand.pyx") - mklrand_c = open("mklrand.c", "r") - processed = open("mklrand_pp.c", "w") - unused_funcs_str = "(" + "|".join(unused_internal_funcs) + ")" - uifpat = re.compile(r"static \w+ \*?" + unused_funcs_str + r".*/\*proto\*/") - linepat = re.compile(r'/\* ".*/mklrand.pyx":') - for linenum, line in enumerate(mklrand_c): - m = re.match( - r"^(\s+arrayObject\w*\s*=\s*[(])[(]PyObject\s*[*][)]", line - ) - if m: - line = "%s(PyArrayObject *)%s" % (m.group(1), line[m.end() :]) - m = uifpat.match(line) - if m: - line = "" - m = re.search(unused_funcs_str, line) - if m: - print( - "%s was declared unused, but is used at line %d" - % (m.group(), linenum + 1), - file=sys.stderr, - ) - line = linepat.sub(r'/* "mklrand.pyx":', line) - processed.write(line) - mklrand_c.close() - processed.close() - os.rename("mklrand_pp.c", "mklrand.c") diff --git a/pyproject.toml b/pyproject.toml index 0476dba7..c841c9a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,15 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [build-system] -build-backend = "setuptools.build_meta" -requires = ["setuptools>=77", "Cython", "numpy"] +build-backend = "mesonpy" +requires = [ + "meson-python>=0.16.0", + "ninja", + "Cython", + "numpy", + "mkl-devel", + "cmake" +] [project] authors = [ @@ -98,13 +105,3 @@ extension-pkg-allow-list = ["numpy", "mkl_random.mklrand"] [tool.pylint.typecheck] generated-members = ["RandomState", "min", "max"] - -[tool.setuptools] -include-package-data = true -packages = ["mkl_random", "mkl_random.interfaces"] - -[tool.setuptools.dynamic] -version = {attr = "mkl_random._version.__version__"} - -[tool.setuptools.package-data] -"mkl_random" = ["tests/**/*.py"] diff --git a/setup.py b/setup.py deleted file mode 100644 index 0b90bf9d..00000000 --- a/setup.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) 2017, Intel Corporation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Intel Corporation nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import sys -from os.path import join - -import Cython.Build -import numpy as np -from setuptools import Extension, setup - - -def extensions(): - mkl_root = os.environ.get("MKLROOT", None) - if mkl_root: - mkl_info = { - "include_dirs": [join(mkl_root, "include")], - "library_dirs": [ - join(mkl_root, "lib"), - join(mkl_root, "lib", "intel64"), - ], - "libraries": ["mkl_rt"], - } - else: - raise ValueError("MKLROOT environment variable not set.") - - mkl_include_dirs = mkl_info.get("include_dirs", []) - mkl_library_dirs = mkl_info.get("library_dirs", []) - mkl_libraries = mkl_info.get("libraries", ["mkl_rt"]) - - libs = mkl_libraries - lib_dirs = mkl_library_dirs - - if sys.platform == "win32": - libs.append("Advapi32") - - Q = ( - "/Q" - if sys.platform.startswith("win") or sys.platform == "cygwin" - else "-" - ) - eca = [Q + "std=c++11"] - if sys.platform == "linux": - eca.extend(["-Wno-unused-but-set-variable", "-Wno-unused-function"]) - - defs = [ - ("_FILE_OFFSET_BITS", "64"), - ("_LARGEFILE_SOURCE", "1"), - ("_LARGEFILE64_SOURCE", "1"), - ("PY_ARRAY_UNIQUE_SYMBOL", "mkl_random_ext"), - ] - - exts = [ - Extension( - "mkl_random.mklrand", - sources=[ - join("mkl_random", "mklrand.pyx"), - join("mkl_random", "src", "mkl_distributions.cpp"), - join("mkl_random", "src", "randomkit.cpp"), - ], - depends=[ - join("mkl_random", "src", "mkl_distributions.hpp"), - join("mkl_random", "src", "randomkit.h"), - join("mkl_random", "src", "numpy_multiiter_workaround.h"), - ], - include_dirs=[join("mkl_random", "src"), np.get_include()] - + mkl_include_dirs, - libraries=libs, - library_dirs=lib_dirs, - extra_compile_args=eca, - define_macros=defs + [("NDEBUG", None)], - language="c++", - ), - ] - - return exts - - -setup( - cmdclass={"build_ext": Cython.Build.build_ext}, - ext_modules=extensions(), - zip_safe=False, -)