diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 7b04634..8f6c840 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -41,7 +41,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 cmake sphinx sphinx_rtd_theme furo pydot graphviz sphinxcontrib-programoutput sphinxcontrib-googleanalytics sphinx_design - name: Checkout repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/.github/workflows/build-with-clang.yml b/.github/workflows/build-with-clang.yml index 37eeec2..2594eea 100644 --- a/.github/workflows/build-with-clang.yml +++ b/.github/workflows/build-with-clang.yml @@ -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,7 +53,7 @@ jobs: - name: Install mkl_random dependencies run: | - pip install cython setuptools">=77" + pip install meson-python ninja cython cmake pip install "${{ matrix.numpy_version }}" - name: List oneAPI folder content diff --git a/.github/workflows/build-with-standard-clang.yml b/.github/workflows/build-with-standard-clang.yml new file mode 100644 index 0000000..94e916d --- /dev/null +++ b/.github/workflows/build-with-standard-clang.yml @@ -0,0 +1,65 @@ +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 mkl + pip install ${{ matrix.numpy_version }} + + - name: Build mkl_random + run: | + export CC=${{ env.COMPILER_ROOT }}/clang + export CXX=${{ env.COMPILER_ROOT }}/clang++ + pip install . --no-build-isolation --no-deps --verbose + + - name: Run mkl_random tests + run: | + pip install pytest + # mkl_random cannot be installed in editable mode, we need + # to change directory before importing it and running tests + cd .. + 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 0000000..93740aa --- /dev/null +++ b/.github/workflows/build_pip.yml @@ -0,0 +1,50 @@ +name: Editable build using pip and pre-release NumPy + +on: + push: + branches: + - master + pull_request: + +permissions: read-all + +env: + PACKAGE_NAME: mkl_random + MODULE_NAME: mkl_random + TEST_ENV_NAME: test_mkl_random + +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 mkl + + - name: Build conda package + run: | + pip install --no-cache-dir meson-python ninja cmake cython + pip install --no-cache-dir numpy ${{ matrix.use_pre }} + pip install -e ".[test]" --no-build-isolation --verbose + pip list + python -m pytest -v mkl_random/tests diff --git a/conda-recipe-cf/bld.bat b/conda-recipe-cf/bld.bat index 29a732b..a08c27b 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 f513746..562c55f 100644 --- a/conda-recipe-cf/build.sh +++ b/conda-recipe-cf/build.sh @@ -1,18 +1,3 @@ #!/bin/bash -x -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/meta.yaml b/conda-recipe-cf/meta.yaml index ba58267..5c59d97 100644 --- a/conda-recipe-cf/meta.yaml +++ b/conda-recipe-cf/meta.yaml @@ -18,9 +18,12 @@ requirements: - {{ compiler('cxx') }} - {{ stdlib('c') }} host: + - meson-python >=0.13.0 + - meson + - cmake + - ninja - python - python-gil # [py>=314] - - setuptools >=77 - mkl-devel - cython - numpy diff --git a/conda-recipe/bld.bat b/conda-recipe/bld.bat index 29a732b..fed6ce0 100644 --- a/conda-recipe/bld.bat +++ b/conda-recipe/bld.bat @@ -1,7 +1,5 @@ @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 . diff --git a/conda-recipe/build.sh b/conda-recipe/build.sh index f513746..527f695 100644 --- a/conda-recipe/build.sh +++ b/conda-recipe/build.sh @@ -2,7 +2,6 @@ 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' ' ')" diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 4abefcd..b4c460a 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -21,9 +21,12 @@ requirements: - {{ compiler('cxx') }} - {{ stdlib('c') }} host: + - meson-python >=0.13.0 + - meson + - cmake + - ninja - python - python-gil # [py>=314] - - setuptools >=77 - mkl-devel - cython {% if use_numpy_base %} diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..727ebde --- /dev/null +++ b/meson.build @@ -0,0 +1,94 @@ +project( + 'mkl_random', + ['c', 'cpp', 'cython'], + version: run_command( + 'python', '-c', + 'import os; exec(open("mkl_random/_version.py").read()); print(__version__)', + check: true + ).stdout().strip(), + 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 = meson.get_compiler('cpp') +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 = [] + +if cpp.get_argument_syntax() == 'msvc' + link_args += ['Advapi32.lib'] +else + cpp_args += ['-Wno-unused-but-set-variable', '-Wno-unused-function'] +endif + +mkl_dep = dependency('MKL', method: 'cmake', + modules: ['MKL::MKL'], + cmake_args: [ + '-DMKL_ARCH=intel64', + '-DMKL_LINK=dynamic', + '-DMKL_THREADING=intel_thread', + '-DMKL_INTERFACE=lp64' + ], + required: true +) + +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, + override_options: ['cython_language=cpp'], + install: true, + subdir: 'mkl_random' +) + +# install python sources + +py.install_sources( + [ + 'mkl_random/__init__.py', + 'mkl_random/_init_helper.py', + 'mkl_random/_patch_numpy.py', + 'mkl_random/_version.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 744223e..0000000 --- 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 145723c..e867edd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,13 +24,17 @@ # 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.13.0", + "ninja", + "Cython", + "numpy", + "cmake" +] [project] -authors = [ - {name = "Intel Corporation", email = "scripting@intel.com"} -] +authors = [{name = "Intel Corporation"}] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Science/Research", @@ -98,13 +102,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 0b90bf9..0000000 --- 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, -)