diff --git a/.bumpversion.cfg b/.bumpversion.cfg index a2a4de3..32b34b8 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,6 @@ [bumpversion] current_version = 3.2.3 -[bumpversion:file:setup.py] +[bumpversion:file:legacy_setup.py] +[bumpversion:file:pyproject.toml] + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 416dd5d..883255d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,15 +17,6 @@ jobs: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" - lint: - name: black formatter - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: rickstaa/action-black@v1 - with: - black_args: ". --line-length=80 --check" - build_mkl: runs-on: ${{ matrix.os }} defaults: @@ -34,7 +25,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-10.15 ] # windows-latest not finding MKL + os: [ ubuntu-latest, macos-latest ] # windows-latest not finding MKL python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11" ] env: @@ -54,7 +45,7 @@ jobs: conda install mkl scipy numpy pytest - name: Test run: | - python setup.py install --scs --mkl + python legacy_setup.py install --scs --mkl pytest rm -rf build/ @@ -86,7 +77,7 @@ jobs: conda install scipy numpy pytest - name: Test run: | - python setup.py install --scs --openmp + python legacy_setup.py install --scs --openmp pytest rm -rf build/ @@ -98,8 +89,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-10.15, windows-latest ] - python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11" ] + os: [ ubuntu-latest, macos-latest, windows-latest ] + python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11", "3.12"] env: PYTHON_VERSION: ${{ matrix.python-version }} @@ -125,18 +116,29 @@ jobs: conda install scipy=1.7 numpy=1.21 pytest mkl openblas lapack elif [[ "$PYTHON_VERSION" == "3.11" ]]; then conda install scipy=1.9.3 numpy=1.23.4 pytest mkl openblas lapack + elif [[ "$PYTHON_VERSION" == "3.12" ]]; then + conda install scipy numpy pytest mkl openblas lapack + fi + - name: Build + run: | + if [[ "$PYTHON_VERSION" == "3.7" ]] || [[ "$PYTHON_VERSION" == "3.8" ]]; then + python legacy_setup.py install + elif [[ "$PYTHON_VERSION" != "3.7" ]] && [[ "$PYTHON_VERSION" != "3.8" ]]; then + python -c "import numpy as np; print('NUMPY BLAS INFOS'); print(np.show_config())" + python -m pip install --verbose . fi - name: Test run: | - python setup.py install pytest rm -rf build/ - name: Build and test windows wheels if: ${{env.DEPLOY == 'True' && startsWith(matrix.os, 'windows')}} run: | - python setup.py bdist_wheel + python -m pip install build + python -m build -Csetup-args="-Dlink_blas_statically=True" python -m pip install delvewheel delvewheel repair dist/*whl + conda remove openblas # to check static linkage pip install wheelhouse/*whl --force-reinstall pytest - name: Upload artifacts to github @@ -154,8 +156,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-10.15 ] - python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11" ] + os: [ ubuntu-latest, macos-latest ] + python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11", "3.12"] env: RUNNER_OS: ${{ matrix.os }} @@ -196,7 +198,8 @@ jobs: - name: Build source if: ${{env.DEPLOY == 'True' && env.SINGLE_ACTION_CONFIG == 'True'}} run: | - python setup.py sdist --dist-dir=wheelhouse + python -m pip install build + python -m build -Csetup-args="-Dlink_blas_statically=True" --outdir=wheelhouse - name: Upload artifacts to github if: ${{env.DEPLOY == 'True'}} diff --git a/.gitmodules b/.gitmodules index 0b92675..10fefc2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "scs"] - path = scs + path = scs_source url = https://github.com/cvxgrp/scs.git diff --git a/setup.py b/legacy_setup.py similarity index 89% rename from setup.py rename to legacy_setup.py index 9f4ddbd..639598c 100644 --- a/setup.py +++ b/legacy_setup.py @@ -176,8 +176,12 @@ def install_scs(**kwargs): extra_compile_args = ["-O3"] extra_link_args = [] libraries = [] - sources = ["src/scspy.c"] + glob("scs/src/*.c") + glob("scs/linsys/*.c") - include_dirs = ["scs/include", "scs/linsys"] + sources = ( + ["scs/scspy.c"] + + glob("scs_source/src/*.c") + + glob("scs_source/linsys/*.c") + ) + include_dirs = ["scs_source/include", "scs_source/linsys"] define_macros = [("PYTHON", None), ("CTRLC", 1)] if args.openmp: extra_compile_args += ["-fopenmp"] @@ -198,16 +202,16 @@ def install_scs(**kwargs): _scs_direct = Extension( name="_scs_direct", sources=sources - + glob("scs/linsys/cpu/direct/*.c") - + glob("scs/linsys/external/amd/*.c") - + glob("scs/linsys/external/qdldl/*.c"), - depends=glob("src/*.h"), + + glob("scs_source/linsys/cpu/direct/*.c") + + glob("scs_source/linsys/external/amd/*.c") + + glob("scs_source/linsys/external/qdldl/*.c"), + depends=glob("scs/*.h"), define_macros=list(define_macros), include_dirs=include_dirs + [ - "scs/linsys/cpu/direct/", - "scs/linsys/external/amd", - "scs/linsys/external/dqlql", + "scs_source/linsys/cpu/direct/", + "scs_source/linsys/external/amd", + "scs_source/linsys/external/dqlql", ], libraries=list(libraries), extra_compile_args=list(extra_compile_args), @@ -216,11 +220,11 @@ def install_scs(**kwargs): _scs_indirect = Extension( name="_scs_indirect", - sources=sources + glob("scs/linsys/cpu/indirect/*.c"), - depends=glob("src/*.h"), + sources=sources + glob("scs_source/linsys/cpu/indirect/*.c"), + depends=glob("scs/*.h"), define_macros=list(define_macros) + [("PY_INDIRECT", None), ("INDIRECT", 1)], - include_dirs=include_dirs + ["scs/linsys/cpu/indirect/"], + include_dirs=include_dirs + ["scs_source/linsys/cpu/indirect/"], libraries=list(libraries), extra_compile_args=list(extra_compile_args), extra_link_args=list(extra_link_args), @@ -241,13 +245,13 @@ def install_scs(**kwargs): _scs_gpu = Extension( name="_scs_gpu", sources=sources - + glob("scs/linsys/gpu/*.c") - + glob("scs/linsys/gpu/indirect/*.c"), - depends=glob("src/*.h"), + + glob("scs_source/linsys/gpu/*.c") + + glob("scs_source/linsys/gpu/indirect/*.c"), + depends=glob("scs/*.h"), define_macros=list(define_macros) + [("PY_GPU", None), ("INDIRECT", 1)], include_dirs=include_dirs - + ["scs/linsys/gpu/", "scs/linsys/gpu/indirect"], + + ["scs_source/linsys/gpu/", "scs_source/linsys/gpu/indirect"], library_dirs=library_dirs, libraries=libraries + ["cudart", "cublas", "cusparse"], extra_compile_args=list(extra_compile_args), @@ -272,10 +276,10 @@ def install_scs(**kwargs): # MKL should be included in the libraries already: _scs_mkl = Extension( name="_scs_mkl", - sources=sources + glob("scs/linsys/mkl/direct/*.c"), - depends=glob("src/*.h"), + sources=sources + glob("scs_source/linsys/mkl/direct/*.c"), + depends=glob("scs/*.h"), define_macros=list(define_macros) + [("PY_MKL", None)], - include_dirs=include_dirs + ["scs/linsys/mkl/direct/"], + include_dirs=include_dirs + ["scs_source/linsys/mkl/direct/"], libraries=list(libraries), extra_compile_args=list(extra_compile_args), extra_link_args=list(extra_link_args), @@ -289,7 +293,7 @@ def install_scs(**kwargs): author_email="bodonoghue85@gmail.com", url="http://github.com/cvxgrp/scs", description="scs: splitting conic solver", - package_dir={"scs": "src"}, + package_dir={"scs": "scs"}, packages=["scs"], ext_modules=ext_modules, cmdclass={"build_ext": build_ext_scs}, diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..3b29f06 --- /dev/null +++ b/meson.build @@ -0,0 +1,143 @@ +project('scs', 'c') + +py = import('python').find_installation(pure: false) + +cc = meson.get_compiler('c') +blas_deps = [] +if host_machine.system() == 'darwin' + blas_deps = [dependency('Accelerate')] +else + blas_deps = [cc.find_library('openblas', static: get_option('link_blas_statically'), required : false)] +endif + +# try to find blas/cblas (e.g., Linux) +if not blas_deps[0].found() + blas_deps = [cc.find_library('blas', static: get_option('link_blas_statically'), required : false)] + cblas_dep = cc.find_library('cblas', static: get_option('link_blas_statically'), required : false) + if cblas_dep.found() + blas_deps += cblas_dep + endif +endif + +# We find anaconda blas on windows for github CI +if host_machine.system() == 'windows' and not blas_deps[0].found() + message(run_command(py,['-c','''import os; print('CONDA LIB FOLDER'); print(os.listdir('C:/Miniconda/envs/test\\Library\\lib'))''']).stdout()) + blas_deps = [cc.find_library('openblas', + dirs: ['C:/Miniconda/envs/test\\Library\\lib'], # this is the location on github CI + static: get_option('link_blas_statically'), + required : false)] +endif + +# Since nothing above was required, we stop here if failed +if not blas_deps[0].found() + error('OpenBLAS or Netlib BLAS/CBLAS is required on all platforms except Windows, and was not found.') +endif + +fs = import('fs') +if not fs.exists('scs_source/README.md') + error('Missing the `scs_source` submodule! Run `git submodule update --init` to fix this.') +endif + +incdir_numpy = run_command(py,['-c', +'''import os +import numpy as np +try: + incdir = os.path.relpath(np.get_include()) +except Exception: + incdir = np.get_include() +print(incdir) +'''], check: true).stdout().strip() + +# rw.c emits a lot of -Wunused-result warnings, silence them for now: +c_args = cc.get_supported_arguments('-Wno-unused-result') + + +py.extension_module( + '_scs_direct', + + 'scs/scspy.c', + 'scs_source/linsys/cpu/direct/private.c', + + # scs_source/src: + 'scs_source/src/aa.c', + 'scs_source/src/cones.c', + 'scs_source/src/ctrlc.c', + 'scs_source/src/exp_cone.c', + 'scs_source/src/linalg.c', + 'scs_source/src/normalize.c', + 'scs_source/src/rw.c', + 'scs_source/src/scs_version.c', + 'scs_source/src/scs.c', + 'scs_source/src/util.c', + + # scs_source/linsys: + 'scs_source/linsys/scs_matrix.c', + 'scs_source/linsys/csparse.c', + + # scs_source/linsys/external/qdldl: + 'scs_source/linsys/external/qdldl/qdldl.c', + + # scs_source/linsys/external/amd: + 'scs_source/linsys/external/amd/amd_1.c', + 'scs_source/linsys/external/amd/amd_2.c', + 'scs_source/linsys/external/amd/amd_aat.c', + 'scs_source/linsys/external/amd/amd_control.c', + 'scs_source/linsys/external/amd/amd_defaults.c', + 'scs_source/linsys/external/amd/amd_dump.c', + 'scs_source/linsys/external/amd/amd_global.c', + 'scs_source/linsys/external/amd/amd_info.c', + 'scs_source/linsys/external/amd/amd_order.c', + 'scs_source/linsys/external/amd/amd_post_tree.c', + 'scs_source/linsys/external/amd/amd_postorder.c', + 'scs_source/linsys/external/amd/amd_preprocess.c', + 'scs_source/linsys/external/amd/amd_valid.c', + 'scs_source/linsys/external/amd/SuiteSparse_config.c', + + include_directories : [ + 'scs', + 'scs_source/include', + 'scs_source/linsys', + 'scs_source/linsys/cpu/direct', + 'scs_source/linsys/external/qdldl', + 'scs_source/linsys/external/amd', + incdir_numpy], + install: true, + c_args: c_args + ['-DPYTHON', '-DCTRLC=1', '-DUSE_LAPACK=1', '-DDLONG=1'], + dependencies: blas_deps, +) + +py.extension_module( + '_scs_indirect', + + 'scs/scspy.c', + 'scs_source/linsys/cpu/indirect/private.c', + + # scs_source/src: + 'scs_source/src/aa.c', + 'scs_source/src/cones.c', + 'scs_source/src/ctrlc.c', + 'scs_source/src/exp_cone.c', + 'scs_source/src/linalg.c', + 'scs_source/src/normalize.c', + 'scs_source/src/rw.c', + 'scs_source/src/scs_version.c', + 'scs_source/src/scs.c', + 'scs_source/src/util.c', + + # scs_source/linsys: + 'scs_source/linsys/scs_matrix.c', + 'scs_source/linsys/csparse.c', + + include_directories : [ + 'scs', + 'scs_source/include', + 'scs_source/linsys', + 'scs_source/linsys/cpu/indirect', + incdir_numpy], + install: true, + c_args: c_args + ['-DPYTHON', '-DCTRLC=1', '-DPY_INDIRECT', '-DINDIRECT=1', + '-DUSE_LAPACK=1', '-DDLONG=1'], + dependencies: blas_deps, +) + +py.install_sources('scs/__init__.py', subdir: 'scs') diff --git a/meson.options b/meson.options new file mode 100644 index 0000000..5db6627 --- /dev/null +++ b/meson.options @@ -0,0 +1,5 @@ +# we use this to build pre-compiled wheels on github CI +# copying anaconda openblas into SCS wheels for ease of +# installation +option('link_blas_statically', type: 'boolean', + value: false, description: 'copy BLAS compiled object into SCS module(s)') diff --git a/pyproject.toml b/pyproject.toml index 8efd161..ab1b017 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,17 @@ [build-system] -requires = [ - "setuptools<65.6.0", - "wheel", - "oldest-supported-numpy", -] -build-backend = "setuptools.build_meta" +build-backend = 'mesonpy' +requires = ['meson-python', 'numpy'] + +[project] +name = 'scs' +version = "3.2.3" +description = 'Splitting conic solver' +readme = 'README.md' +requires-python = '>=3.8' +license = {file = 'LICENSE'} +authors = [ + {name = "Brendan O'Donoghue", email = "bodonoghue85@gmail.com"}] +dependencies = [ + 'numpy', + 'scipy', +] \ No newline at end of file diff --git a/src/__init__.py b/scs/__init__.py similarity index 100% rename from src/__init__.py rename to scs/__init__.py diff --git a/src/scsmodule.h b/scs/scsmodule.h similarity index 100% rename from src/scsmodule.h rename to scs/scsmodule.h diff --git a/src/scsobject.h b/scs/scsobject.h similarity index 100% rename from src/scsobject.h rename to scs/scsobject.h diff --git a/src/scspy.c b/scs/scspy.c similarity index 100% rename from src/scspy.c rename to scs/scspy.c diff --git a/scs b/scs_source similarity index 100% rename from scs rename to scs_source