From 0e9e4c07740f296a1d5197e2aae52c257401343b Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 1 Aug 2022 18:33:35 +0300 Subject: [PATCH 01/23] rename build files --- .github/workflows/{multibuild.yml => posix.yml} | 0 .github/workflows/{build.yml => windows.yml} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{multibuild.yml => posix.yml} (100%) rename .github/workflows/{build.yml => windows.yml} (100%) diff --git a/.github/workflows/multibuild.yml b/.github/workflows/posix.yml similarity index 100% rename from .github/workflows/multibuild.yml rename to .github/workflows/posix.yml diff --git a/.github/workflows/build.yml b/.github/workflows/windows.yml similarity index 100% rename from .github/workflows/build.yml rename to .github/workflows/windows.yml From 5c947eb0519a838a42588a1bca82b4e6fc668032 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 3 Aug 2022 12:15:36 +0300 Subject: [PATCH 02/23] add pyproject.yaml and build a wheel for posix via CI --- .github/workflows/posix.yml | 16 ++++++++++--- .gitignore | 3 +++ pyproject.toml | 46 +++++++++++++++++++++++++++++++++++++ setup.py | 4 ++++ 4 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 pyproject.toml create mode 100644 setup.py diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 273d9ce0..3dc28681 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -37,7 +37,7 @@ jobs: INTERFACE64: '1' MB_ML_LIBC: musllinux MB_ML_VER: _1_1 - platform: [x64] + platform: x64 - os: ubuntu-latest PLAT: x86_64 INTERFACE64: '0' @@ -95,7 +95,7 @@ jobs: run: | python -m pip install --upgrade pip pip install virtualenv - - name: Build and Install Wheels + - name: Build OpenBLAS run: | set -xeo pipefail if [[ "$PLAT" == "arm64" ]]; then @@ -118,11 +118,21 @@ jobs: build_lib "$PLAT" "$INTERFACE64" "0" fi + - name: Build wheel + run: | + mkdir -p local/openblas + tar -C local/openblas --strip-components=2 -xf libs/openblas*.tar.gz + python -m pip wheel -w dist -vv . + - uses: actions/upload-artifact@v3 with: path: libs/openblas*.tar.gz - - name: Upload tarballs + - uses: actions/upload-artifact@v3 + with: + path: dist/openblas*.tar.gz + + - name: Upload run: | set -ex TOKEN=${{ secrets.ANACONDA_SCIENTIFIC_PYTHON_UPLOAD }} diff --git a/.gitignore b/.gitignore index 2d8e2638..6fa4069c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ builds/ *.pyc *.swp for_test/ +test.exe +local/ +dist/ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..3cb00953 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + "setuptools", + "wheel", +] +build-backend = "setuptools.build_meta" + +[project] +name = "openblas" +version = "0.3.20" +description = "Provides OpenBLAS for python packaging" +readme = "README.md" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: C++", + "License :: OSI Approved :: BSD License", +] +# authors = [ +# ] +# maintainers = [ +# ] + +[project.urls] +homepage = "https://github.com/MacPython/openblas-libs" +upstream = "https://github.com/xianyi/OpenBLAS" + +[tool.setuptools.packages.find] +# scanning for namespace packages is true by default in pyproject.toml, so +# # you do NOT need to include the following line. +namespaces = true +where = ["local"] + +[tool.setuptools.package-data] +openblas = ["lib/*", "include/*", "lib/pkgconfig/*", "lib/cmake/openblas/*"] + + +#[tool.setuptools.data_files] +# Deprecated in setuptools, but may be revived as a new standard, see +# https://discuss.python.org/t/pep-proposal-external-data-for-python-packages +#"/local" = [ +# "local/include/*.h", +# "local/lib/*", +# "local/lib/pkgconfig/*", +# "local/lib/cmake/OpenBLAS/*", +#] diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..8d054a21 --- /dev/null +++ b/setup.py @@ -0,0 +1,4 @@ +from setuptools import setup, find_packages + +setup( +) From 54b69a406ff8507f850aa7afcb7eac02a60eb48a Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 3 Aug 2022 15:30:14 +0300 Subject: [PATCH 03/23] fix wheel name for artifact upload --- .github/workflows/posix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 3dc28681..afa9bc8d 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -130,7 +130,7 @@ jobs: - uses: actions/upload-artifact@v3 with: - path: dist/openblas*.tar.gz + path: dist/openblas*.whl - name: Upload run: | From 452bef53f71432bb33116ed62c8a00d1e504ec04 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 12 Oct 2022 23:22:22 +0300 Subject: [PATCH 04/23] remove static libraries --- .github/workflows/posix.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index afa9bc8d..c335818a 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -122,6 +122,8 @@ jobs: run: | mkdir -p local/openblas tar -C local/openblas --strip-components=2 -xf libs/openblas*.tar.gz + # do not package the static libs, they are ~55MB + rm local/openblas/*.a python -m pip wheel -w dist -vv . - uses: actions/upload-artifact@v3 From f132e6122b8c9f8888eafbbcf5a3c53481ef2c29 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 13 Oct 2022 16:11:52 +0300 Subject: [PATCH 05/23] add a real module with a preliminary API --- .gitignore | 12 +++++++- local/openblas/__init__.py | 27 ++++++++++++++++++ local/openblas/__main__.py | 4 +++ pyproject.toml | 3 ++ setup.py | 21 +++++++++++++- src/_init_openblas.c | 58 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 local/openblas/__init__.py create mode 100644 local/openblas/__main__.py create mode 100644 src/_init_openblas.c diff --git a/.gitignore b/.gitignore index 6fa4069c..b93366d7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,15 @@ builds/ *.swp for_test/ test.exe -local/ dist/ +build/ +libs/ +# These are artifacts when using editable builds +local/lib +local/include +local/openblas.egg-info +local/openblas/lib +local/openblas/include +local/openblas/*.so +local/openblas/*.pyd +local/openblas/*.dylib diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py new file mode 100644 index 00000000..143ac86b --- /dev/null +++ b/local/openblas/__init__.py @@ -0,0 +1,27 @@ +import os +from . import _init_openblas + +# Use importlib.metadata to single-source the version + +try: + # importlib.metadata is present in Python 3.8 and later + import importlib.metadata as importlib_metadata +except ImportError: + # use the shim package importlib-metadata pre-3.8 + import importlib_metadata as importlib_metadata + +try: + # __package__ allows for the case where __name__ is "__main__" + __version__ = importlib_metadata.version(__package__ or __name__) +except importlib_metadata.PackageNotFoundError: + __version__ = "0.0.0" + +openblas_config = _init_openblas.get_config() + +path_to_so = os.path.join(os.path.dirname(__file__), 'lib', 'libopenblas64_.so') + + +def open_so(): + _init_openblas.open_so(path_to_so) + + diff --git a/local/openblas/__main__.py b/local/openblas/__main__.py new file mode 100644 index 00000000..eff65cab --- /dev/null +++ b/local/openblas/__main__.py @@ -0,0 +1,4 @@ +import openblas + +if __name__ == "__main__": + print(f"OpenBLAS using '{openblas.openblas_config}'") diff --git a/pyproject.toml b/pyproject.toml index 3cb00953..a2d4ccb3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,9 @@ upstream = "https://github.com/xianyi/OpenBLAS" namespaces = true where = ["local"] +[options] +install_requires = "importlib-metadata ~= 1.0 ; python_version < '3.8'" + [tool.setuptools.package-data] openblas = ["lib/*", "include/*", "lib/pkgconfig/*", "lib/cmake/openblas/*"] diff --git a/setup.py b/setup.py index 8d054a21..974e35b5 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,23 @@ -from setuptools import setup, find_packages +import os +from setuptools import setup, Extension + +mydir = os.path.abspath(os.path.dirname(__file__)) + +# TODO: determine if we are building 64- or 32- bit interfaces +use_64=True +if use_64: + libraries = ["openblas64_",] + macros = [("SUFFIX", "64_")] +else: + libraries = ["openblas",] + macros = [] setup( + ext_modules=[Extension( + "openblas._init_openblas", ["src/_init_openblas.c"], + libraries=libraries, + library_dirs=[os.path.join(mydir, 'local', 'openblas', 'lib'),], + extra_link_args=["-Wl,-rpath,$ORIGIN/lib"], + define_macros=macros, + )], ) diff --git a/src/_init_openblas.c b/src/_init_openblas.c new file mode 100644 index 00000000..0304d102 --- /dev/null +++ b/src/_init_openblas.c @@ -0,0 +1,58 @@ +#include "Python.h" +#include +#include + +#ifdef SUFFIX + #define openblas_get_config openblas_get_config64_ +#endif + +extern const char * openblas_get_config(); + +PyObject * +get_config(PyObject *self, PyObject *args) { + const char * config = openblas_get_config(); + return PyUnicode_FromString(config); +} + +PyObject* +open_so(PyObject *self, PyObject *args) { + const char *utf8 = PyUnicode_AsUTF8(args); + if (utf8 == NULL) { + return NULL; + } + void *handle = dlopen(utf8, RTLD_GLOBAL | RTLD_NOW); + if (handle == NULL) { + PyErr_SetString(PyExc_ValueError, "Could not open SO"); + return NULL; + } + Py_RETURN_TRUE; +} + +static PyMethodDef InitMethods[] = { + {"get_config", get_config, METH_NOARGS, + "Return openblas_get_config(), see https://github.com/xianyi/OpenBLAS/wiki/OpenBLAS-Extensions"}, + {"open_so", open_so, METH_O, + "Use dlopen to load the shared object, which must exist"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static struct PyModuleDef initmodule = { + PyModuleDef_HEAD_INIT, + "_init_openblas", /* name of module */ + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + InitMethods +}; + +PyMODINIT_FUNC +PyInit__init_openblas(void) +{ + PyObject *m; + + m = PyModule_Create(&initmodule); + if (m == NULL) + return NULL; + + return m; +} From b840e12d3026a17e83446a9095f5fb76455c7851 Mon Sep 17 00:00:00 2001 From: mayeut Date: Sun, 23 Oct 2022 18:08:02 +0200 Subject: [PATCH 06/23] create an ABI3 wheel when possible --- .github/workflows/posix.yml | 18 +++++++++++++++--- local/openblas/__init__.py | 8 -------- pyproject.toml | 12 +----------- setup.py | 32 +++++++++++++++++++++++++------- src/_init_openblas.c | 20 +------------------- 5 files changed, 42 insertions(+), 48 deletions(-) diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index c335818a..b71bc30c 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -122,9 +122,21 @@ jobs: run: | mkdir -p local/openblas tar -C local/openblas --strip-components=2 -xf libs/openblas*.tar.gz - # do not package the static libs, they are ~55MB - rm local/openblas/*.a - python -m pip wheel -w dist -vv . + cp local/openblas/lib/libopenblas64_.so local/openblas/libopenblas_python.so + # do not package the static libs and symlinks, they are ~55MB + rm -rf local/openblas/lib/* + mv local/openblas/libopenblas_python.so local/openblas/lib/ + + cat < run_in_docker.sh + cd /openblas + patchelf --set-soname libopenblas_python.so local/openblas/lib/libopenblas_python.so + python3.7 -m pip wheel -w /tmp/wheelhouse -vv . + auditwheel repair -w dist/ /tmp/wheelhouse/openblas-*.whl + python3.10 -m pip install dist/openblas-*.whl + python3.10 -m openblas + EOF + + docker run --rm -v $(pwd):/openblas quay.io/pypa/manylinux2014_x86_64 /bin/bash -xe /openblas/run_in_docker.sh - uses: actions/upload-artifact@v3 with: diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py index 143ac86b..2ae6d178 100644 --- a/local/openblas/__init__.py +++ b/local/openblas/__init__.py @@ -17,11 +17,3 @@ __version__ = "0.0.0" openblas_config = _init_openblas.get_config() - -path_to_so = os.path.join(os.path.dirname(__file__), 'lib', 'libopenblas64_.so') - - -def open_so(): - _init_openblas.open_so(path_to_so) - - diff --git a/pyproject.toml b/pyproject.toml index a2d4ccb3..3da6bb7b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ build-backend = "setuptools.build_meta" [project] name = "openblas" version = "0.3.20" +requires-python = ">=3.7" description = "Provides OpenBLAS for python packaging" readme = "README.md" classifiers = [ @@ -36,14 +37,3 @@ install_requires = "importlib-metadata ~= 1.0 ; python_version < '3.8'" [tool.setuptools.package-data] openblas = ["lib/*", "include/*", "lib/pkgconfig/*", "lib/cmake/openblas/*"] - - -#[tool.setuptools.data_files] -# Deprecated in setuptools, but may be revived as a new standard, see -# https://discuss.python.org/t/pep-proposal-external-data-for-python-packages -#"/local" = [ -# "local/include/*.h", -# "local/lib/*", -# "local/lib/pkgconfig/*", -# "local/lib/cmake/OpenBLAS/*", -#] diff --git a/setup.py b/setup.py index 974e35b5..f0d83c13 100644 --- a/setup.py +++ b/setup.py @@ -1,23 +1,41 @@ import os +import sys from setuptools import setup, Extension +from wheel.bdist_wheel import bdist_wheel + mydir = os.path.abspath(os.path.dirname(__file__)) + +class bdist_wheel_abi3(bdist_wheel): + def get_tag(self): + python, abi, plat = bdist_wheel.get_tag(self) + return python, "abi3", plat + + # TODO: determine if we are building 64- or 32- bit interfaces use_64=True if use_64: - libraries = ["openblas64_",] macros = [("SUFFIX", "64_")] else: - libraries = ["openblas",] macros = [] +if sys.implementation.name == "cpython": + cmdclass = {"bdist_wheel": bdist_wheel_abi3} + py_limited_api = {"py_limited_api": True} + macros.append(('Py_LIMITED_API', '0x03070000')) +else: + cmdclass = {} + py_limited_api = {} + setup( + cmdclass=cmdclass, ext_modules=[Extension( - "openblas._init_openblas", ["src/_init_openblas.c"], - libraries=libraries, - library_dirs=[os.path.join(mydir, 'local', 'openblas', 'lib'),], - extra_link_args=["-Wl,-rpath,$ORIGIN/lib"], - define_macros=macros, + "openblas._init_openblas", ["src/_init_openblas.c"], + libraries=["openblas_python"], + library_dirs=[os.path.join(mydir, 'local', 'openblas', 'lib'),], + extra_link_args=["-Wl,-rpath,$ORIGIN/lib"], + define_macros=macros, + **py_limited_api )], ) diff --git a/src/_init_openblas.c b/src/_init_openblas.c index 0304d102..2145b9c2 100644 --- a/src/_init_openblas.c +++ b/src/_init_openblas.c @@ -1,6 +1,4 @@ -#include "Python.h" -#include -#include +#include #ifdef SUFFIX #define openblas_get_config openblas_get_config64_ @@ -14,25 +12,9 @@ get_config(PyObject *self, PyObject *args) { return PyUnicode_FromString(config); } -PyObject* -open_so(PyObject *self, PyObject *args) { - const char *utf8 = PyUnicode_AsUTF8(args); - if (utf8 == NULL) { - return NULL; - } - void *handle = dlopen(utf8, RTLD_GLOBAL | RTLD_NOW); - if (handle == NULL) { - PyErr_SetString(PyExc_ValueError, "Could not open SO"); - return NULL; - } - Py_RETURN_TRUE; -} - static PyMethodDef InitMethods[] = { {"get_config", get_config, METH_NOARGS, "Return openblas_get_config(), see https://github.com/xianyi/OpenBLAS/wiki/OpenBLAS-Extensions"}, - {"open_so", open_so, METH_O, - "Use dlopen to load the shared object, which must exist"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; From 84edd9f36a5f699dc14a9f54c099f22fd0657780 Mon Sep 17 00:00:00 2001 From: mayeut Date: Mon, 24 Oct 2022 00:49:04 +0200 Subject: [PATCH 07/23] add helpers --- local/openblas/__init__.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py index 2ae6d178..30414a1c 100644 --- a/local/openblas/__init__.py +++ b/local/openblas/__init__.py @@ -1,6 +1,11 @@ -import os +from pathlib import Path + from . import _init_openblas + +_HERE = Path(__file__).resolve().parent + + # Use importlib.metadata to single-source the version try: @@ -17,3 +22,15 @@ __version__ = "0.0.0" openblas_config = _init_openblas.get_config() + + +def get_include_dir(): + return str(_HERE / "include") + + +def get_lib_dir(): + return str(_HERE / "lib") + + +def get_library(): + return "openblas_python" From 4397282968bcabbce9f5e92af1d5303a9821f01c Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 15 Aug 2023 12:52:20 +0300 Subject: [PATCH 08/23] add get_pkg_config, work on README --- README.md | 31 ++++++++++++++++++++++++++----- local/openblas/__init__.py | 19 +++++++++++++++++++ pyproject.toml | 2 +- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ba276ae6..da70aadf 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,33 @@ -# Building OpenBLAS +# OpenBLAS -This is a repository to trigger builds of OpenBLAS on Travis-CI (for aarch64, -ppc64, s390x) and github actions for all the others. +We build OpenBLAS on Travis-CI (for linux aarch64, ppc64, s390x) and github actions +for linux, windows, macOS x86_64 and macOS arm64. -The OpenBLAS libraries get uploaded to +Tarballs are at https://anaconda.org/scientific-python-nightly-wheels/openblas-libs/files -A project using these libraries, for Manylinux or macOS, will need the +A project using the tarball, for Manylinux or macOS, will need the ``gfortran-install`` submodule used here, from https://github.com/MacPython/gfortran-install +We also build and upload a pip-installable wheel. The wheel is self-contianed, +no additional fortran support installations are needed. The wheel supplies +interfaces for building and using OpenBLAS in a python project like SciPy or +NumPy: + +## Buildtime + +- `get_include_dir()`, `get_lib_dir()` and `get_library()` for use in compiler + or project arguments +- `get_pkg_config()` will return a multi-line text that can be saved into a + file and used with pkg-config for build systems like meson. This works around + the problem of [relocatable pkg-config + files](https://docs.conan.io/en/1.43/integrations/build_system/pkg_config_pc_files.html) + since the windows build uses pkgconfiglite v0.28 which does not support + `--define-prefix`. + +## Runtime + +- `open_so()` will load openblas into the executable and provide the openblas + symbols linked in from the `get_include_dir()` includes (on windows linking + with `get_lib_dir()`/`get_libarary()` is required). diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py index 30414a1c..a36f843c 100644 --- a/local/openblas/__init__.py +++ b/local/openblas/__init__.py @@ -1,10 +1,12 @@ from pathlib import Path from . import _init_openblas +from textwrap import dedent _HERE = Path(__file__).resolve().parent +__all__ = ["get_include_dir", "get_lib_dir", "get_library", "get_pkg_config"] # Use importlib.metadata to single-source the version @@ -34,3 +36,20 @@ def get_lib_dir(): def get_library(): return "openblas_python" + +def get_pkg_config(): + return f"""\ + libdir={_HERE}/lib + includedir={_HERE}/include + openblas_config= USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER= NO_CBLAS= NO_LAPACK= NO_LAPACKE= NO_AFFINITY=1 USE_OPENMP= PRESCOTT MAX_THREADS=24 + version=0.3.23 + extralib=-lm -lpthread -lgfortran -lm -lpthread -lgfortran + Name: openblas + Description: OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version + Version: ${version} + URL: https://github.com/xianyi/OpenBLAS + Libs: -L${libdir} -lopenblas + Libs.private: ${extralib} + Cflags: -I${includedir} + """ + diff --git a/pyproject.toml b/pyproject.toml index 3da6bb7b..b3385e29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [project] name = "openblas" -version = "0.3.20" +version = "0.3.23" requires-python = ">=3.7" description = "Provides OpenBLAS for python packaging" readme = "README.md" From 05704038ba71b43767f5c5c521893d5f289a417b Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 15 Aug 2023 16:26:44 +0300 Subject: [PATCH 09/23] make more of CI work --- .github/workflows/posix.yml | 39 ++++++------- .github/workflows/windows.yml | 107 ++++++++++++++++++---------------- local/openblas/__init__.py | 6 +- tools/local_build.sh | 59 +++++++++++++++++++ travis-ci/build_wheel.sh | 20 +++++++ 5 files changed, 157 insertions(+), 74 deletions(-) create mode 100644 tools/local_build.sh create mode 100644 travis-ci/build_wheel.sh diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index b71bc30c..5c09f31b 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -1,4 +1,4 @@ -name: multibuild +name: posix on: push: @@ -71,10 +71,10 @@ jobs: with: submodules: recursive fetch-depth: 0 - - name: Set up Python 3.8 - uses: actions/setup-python@v2 + - name: Set up Python + uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.7 - name: Set extra env run: | if [ "macos-11" == "${{ matrix.os }}" ]; then @@ -93,7 +93,7 @@ jobs: echo "DOCKER_TEST_IMAGE: ${DOCKER_TEST_IMAGE}" - name: Install VirtualEnv run: | - python -m pip install --upgrade pip + python3 -m pip install --upgrade pip pip install virtualenv - name: Build OpenBLAS run: | @@ -120,23 +120,22 @@ jobs: - name: Build wheel run: | - mkdir -p local/openblas - tar -C local/openblas --strip-components=2 -xf libs/openblas*.tar.gz - cp local/openblas/lib/libopenblas64_.so local/openblas/libopenblas_python.so - # do not package the static libs and symlinks, they are ~55MB - rm -rf local/openblas/lib/* - mv local/openblas/libopenblas_python.so local/openblas/lib/ - cat < run_in_docker.sh - cd /openblas - patchelf --set-soname libopenblas_python.so local/openblas/lib/libopenblas_python.so - python3.7 -m pip wheel -w /tmp/wheelhouse -vv . - auditwheel repair -w dist/ /tmp/wheelhouse/openblas-*.whl - python3.10 -m pip install dist/openblas-*.whl - python3.10 -m openblas - EOF + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + source travis-ci/build_wheel.sh + else + docker run --rm -v $(pwd):/openblas quay.io/pypa/manylinux2014_${PLAT} /bin/bash -xe /openblas/travis-ci/build_wheel.sh + fi - docker run --rm -v $(pwd):/openblas quay.io/pypa/manylinux2014_x86_64 /bin/bash -xe /openblas/run_in_docker.sh + - name: Setup different python to test wheel + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Test wheel + run: | + python -m pip install --no-index --find-links dist openblas + python -m openblas - uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index f308156c..413e483b 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -27,61 +27,66 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - name: install-rtools - run: | - # rtools 42+ does not support 32 bits builds. - choco install -y rtools --noprogress --force --version=4.0.0.20220206 + - uses: actions/checkout@v3 + - name: install-rtools + run: | + # rtools 42+ does not support 32 bits builds. + choco install -y rtools --noprogress --force --version=4.0.0.20220206 - - name: Set env variables - run: | - echo "START_DIR=$PWD" >> $env:GITHUB_ENV - $BITS = ${{ matrix.BUILD_BITS }} - echo "BUILD_BITS=$BITS" >> $env:GITHUB_ENV - # For interpretation of MSYSTEM, see: - # https://sourceforge.net/p/msys2/discussion/general/thread/b7dfdac8/#3939 - if ($BITS -eq 32) { - echo "PLAT=i686" >> $env:GITHUB_ENV - echo "MSYSTEM=MINGW32" >> $env:GITHUB_ENV - echo "LDFLAGS=-static -static-libgcc" >> $env:GITHUB_ENV - } else { - echo "PLAT=x86_64" >> $env:GITHUB_ENV - echo "MSYSTEM=UCRT64" >> $env:GITHUB_ENV - echo "LDFLAGS=-lucrt -static -static-libgcc" >> $env:GITHUB_ENV - } - if ( ${{ matrix.INTERFACE64 }} -eq 1 ) { - echo "INTERFACE64=1" >> $env:GITHUB_ENV - } + - name: Set env variables + run: | + echo "START_DIR=$PWD" >> $env:GITHUB_ENV + $BITS = ${{ matrix.BUILD_BITS }} + echo "BUILD_BITS=$BITS" >> $env:GITHUB_ENV + # For interpretation of MSYSTEM, see: + # https://sourceforge.net/p/msys2/discussion/general/thread/b7dfdac8/#3939 + if ($BITS -eq 32) { + echo "PLAT=i686" >> $env:GITHUB_ENV + echo "MSYSTEM=MINGW32" >> $env:GITHUB_ENV + echo "LDFLAGS=-static -static-libgcc" >> $env:GITHUB_ENV + } else { + echo "PLAT=x86_64" >> $env:GITHUB_ENV + echo "MSYSTEM=UCRT64" >> $env:GITHUB_ENV + echo "LDFLAGS=-lucrt -static -static-libgcc" >> $env:GITHUB_ENV + } + if ( ${{ matrix.INTERFACE64 }} -eq 1 ) { + echo "INTERFACE64=1" >> $env:GITHUB_ENV + } - - name: Build - run: | - git submodule update --init --recursive - & $env:BASH_PATH -lc tools/build_openblas.sh + - name: Build + run: | + git submodule update --init --recursive + & $env:BASH_PATH -lc tools/build_openblas.sh - - name: Test - run: | - & $env:BASH_PATH -lc tools/build_gfortran.sh - echo "Static test" - .\for_test\test.exe - echo "Dynamic test" - .\for_test\test_dyn.exe + - name: Test + run: | + & $env:BASH_PATH -lc tools/build_gfortran.sh + echo "Static test" + .\for_test\test.exe + echo "Dynamic test" + .\for_test\test_dyn.exe - - name: Copy - run: | - cp for_test\test*.exe builds + - name: Copy + run: | + cp for_test\test*.exe builds - - uses: actions/upload-artifact@v3 - with: - path: builds/openblas*.zip + - name: Set up Python 3.8 + uses: actions/setup-python@v4 + with: + python-version: 3.8 - - uses: conda-incubator/setup-miniconda@v2 - with: - activate-environment: upload + - uses: actions/upload-artifact@v3 + with: + path: builds/openblas*.zip - - name: Upload - env: - ANACONDA_SCIENTIFIC_PYTHON_UPLOAD: ${{ secrets.ANACONDA_SCIENTIFIC_PYTHON_UPLOAD }} - run: | - # Pin urllib3<2 due to github.com/Anaconda-Platform/anaconda-client/issues/654 - conda install "urllib3<2" anaconda-client - & $env:BASH_PATH -lc tools/upload_to_anaconda_staging.sh + - uses: conda-incubator/setup-miniconda@v2 + with: + activate-environment: upload + + - name: Upload + env: + ANACONDA_SCIENTIFIC_PYTHON_UPLOAD: ${{ secrets.ANACONDA_SCIENTIFIC_PYTHON_UPLOAD }} + run: | + # Pin urllib3<2 due to github.com/Anaconda-Platform/anaconda-client/issues/654 + conda install "urllib3<2" anaconda-client + & $env:BASH_PATH -lc tools/upload_to_anaconda_staging.sh diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py index a36f843c..de77fd4e 100644 --- a/local/openblas/__init__.py +++ b/local/openblas/__init__.py @@ -41,12 +41,12 @@ def get_pkg_config(): return f"""\ libdir={_HERE}/lib includedir={_HERE}/include - openblas_config= USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER= NO_CBLAS= NO_LAPACK= NO_LAPACKE= NO_AFFINITY=1 USE_OPENMP= PRESCOTT MAX_THREADS=24 - version=0.3.23 + openblas_config= {openblas_config} + version={openblas_config.split(" ")[1]} extralib=-lm -lpthread -lgfortran -lm -lpthread -lgfortran Name: openblas Description: OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version - Version: ${version} + Version: ${{version}} URL: https://github.com/xianyi/OpenBLAS Libs: -L${libdir} -lopenblas Libs.private: ${extralib} diff --git a/tools/local_build.sh b/tools/local_build.sh new file mode 100644 index 00000000..efd5be89 --- /dev/null +++ b/tools/local_build.sh @@ -0,0 +1,59 @@ +# Replicate the workflow from posix.yml locally on posix +# This may bitrot, compare it to the original file before using + + +# Set extra env +if [ "uname -m" == "x86_64" ]; then + export TRAVIS_OS_NAME=ubuntu-latest + export PLAT=x86_64 + # export PLAT=i86 + DOCKER_TEST_IMAGE=multibuild/xenial_${PLAT} +else + export TRAVIS_OS_NAME=osx + export LDFLAGS="-L/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/lib" + export LIBRARY_PATH="-L/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/lib" + export PLAT=x86_64 + # export PLAT=arm64 + export SUFFIX=gf_c469a42 + +fi +export REPO_DIR=OpenBLAS +export OPENBLAS_COMMIT="c2f4bdb" + +# export MB_ML_LIBC=musllinux +# export MB_ML_VER=_1_1 +# export MB_ML_VER=2014 +export INTERFACE64=1 + +function install_virtualenv { + # Install VirtualEnv + python3 -m pip install --upgrade pip + pip install virtualenv +} + +function build_openblas { + # Build OpenBLAS + set -xeo pipefail + if [ "$PLAT" == "arm64" ]; then + sudo xcode-select -switch /Applications/Xcode_12.5.1.app + export SDKROOT=/Applications/Xcode_12.5.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk + clang --version + fi + source travis-ci/build_steps.sh + echo "------ BEFORE BUILD ---------" + before_build + if [[ "$NIGHTLY" = "true" ]]; then + echo "------ CLEAN CODE --------" + clean_code $REPO_DIR develop + echo "------ BUILD LIB --------" + build_lib "$PLAT" "$INTERFACE64" "1" + else + echo "------ CLEAN CODE --------" + clean_code $REPO_DIR $OPENBLAS_COMMIT + echo "------ BUILD LIB --------" + build_lib "$PLAT" "$INTERFACE64" "0" + fi +} + +# install_virtualenv +# build_openblas diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh new file mode 100644 index 00000000..8c555937 --- /dev/null +++ b/travis-ci/build_wheel.sh @@ -0,0 +1,20 @@ +set -xe +ls libs/openblas* >/dev/null 2>&1 && true +if [ "$?" != "0" ]; then + # inside docker + cd /openblas +fi + +mkdir -p local/openblas +# This will fail if there is more than one file in libs +tar -C local/openblas --strip-components=2 -xf libs/openblas*.tar.gz + +# do not package the static libs and symlinks, only take the shared object +find local/openblas/lib -maxdepth 1 -type l -delete +rm local/openblas/lib/*.a + +mv local/openblas/lib/libopenblas* local/openblas/lib/libopenblas_python.so +patchelf --set-soname libopenblas_python.so local/openblas/lib/libopenblas_python.so +python3.7 -m pip install wheel auditwheel +python3.7 -m pip wheel -w /tmp/wheelhouse -vv . +auditwheel repair -w dist/ /tmp/wheelhouse/openblas-*.whl From 94cf4155f63d8ca83f2f0a7694541a9a9735d7c9 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 16 Aug 2023 10:51:01 +0300 Subject: [PATCH 10/23] reduce manylinux builds, fix wheel building/testing --- .github/workflows/posix.yml | 30 ++++++------------------------ travis-ci/build_wheel.sh | 4 ++++ 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 5c09f31b..418c5729 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -19,36 +19,27 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-11] - platform: [x64] PLAT: [i686, x86_64] INTERFACE64: ['0', '1'] - MB_ML_VER: ['', 2010, 2014] + MB_ML_VER: [2014] include: - os: macos-11 PLAT: arm64 INTERFACE64: '1' - platform: [x64] - os: macos-11 PLAT: arm64 INTERFACE64: '0' - platform: [x64] - os: ubuntu-latest PLAT: x86_64 INTERFACE64: '1' MB_ML_LIBC: musllinux MB_ML_VER: _1_1 - platform: x64 - os: ubuntu-latest PLAT: x86_64 INTERFACE64: '0' MB_ML_LIBC: musllinux MB_ML_VER: _1_1 - platform: [x64] exclude: - - os: macos-11 - PLAT: i686 - - os: macos-11 - MB_ML_VER: 2010 - os: macos-11 MB_ML_VER: 2014 - PLAT: i686 @@ -78,7 +69,6 @@ jobs: - name: Set extra env run: | if [ "macos-11" == "${{ matrix.os }}" ]; then - ls /Library/Developer/CommandLineTools/SDKs echo "TRAVIS_OS_NAME=osx" >> $GITHUB_ENV; echo "LDFLAGS=-L/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/lib" >> $GITHUB_ENV; echo "LIBRARY_PATH=-L/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/lib" >> $GITHUB_ENV; @@ -118,25 +108,17 @@ jobs: build_lib "$PLAT" "$INTERFACE64" "0" fi - - name: Build wheel + - name: Build and test wheel run: | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew install patchelf source travis-ci/build_wheel.sh else - docker run --rm -v $(pwd):/openblas quay.io/pypa/manylinux2014_${PLAT} /bin/bash -xe /openblas/travis-ci/build_wheel.sh + libc=${MB_ML_LIBC:-manylinux} + docker_image=quay.io/pypa/${libc}${MB_ML_VER}_${PLAT} + docker run --rm -v $(pwd):/openblas docker_image /bin/bash -xe /openblas/travis-ci/build_wheel.sh fi - - name: Setup different python to test wheel - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - - name: Test wheel - run: | - python -m pip install --no-index --find-links dist openblas - python -m openblas - - uses: actions/upload-artifact@v3 with: path: libs/openblas*.tar.gz diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index 8c555937..b53173f7 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -18,3 +18,7 @@ patchelf --set-soname libopenblas_python.so local/openblas/lib/libopenblas_pytho python3.7 -m pip install wheel auditwheel python3.7 -m pip wheel -w /tmp/wheelhouse -vv . auditwheel repair -w dist/ /tmp/wheelhouse/openblas-*.whl + +# Test that the wheel works with a different python +python3.11 -m pip install --no-index --find-links dist openblas +python3.11 -m openblas From 47bdfaf75ca474d01bbde2728b97d4f9566ad1a7 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 16 Aug 2023 12:55:31 +0300 Subject: [PATCH 11/23] do not rename dll, start work on windows --- .github/workflows/posix.yml | 3 +-- .github/workflows/windows.yml | 20 +++++++++++++------- setup.py | 7 ++++++- tools/build_wheel_winbash.sh | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 tools/build_wheel_winbash.sh diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 418c5729..d6de5cf3 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -111,12 +111,11 @@ jobs: - name: Build and test wheel run: | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew install patchelf source travis-ci/build_wheel.sh else libc=${MB_ML_LIBC:-manylinux} docker_image=quay.io/pypa/${libc}${MB_ML_VER}_${PLAT} - docker run --rm -v $(pwd):/openblas docker_image /bin/bash -xe /openblas/travis-ci/build_wheel.sh + docker run --rm -v $(pwd):/openblas $docker_image /bin/bash -xe /openblas/travis-ci/build_wheel.sh fi - uses: actions/upload-artifact@v3 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 413e483b..b016e2a2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -17,11 +17,11 @@ jobs: build: strategy: matrix: - BUILD_BITS: [64, 32] + plat: ['x64', 'x86'] INTERFACE64: ['1', '0'] os: [windows-latest] exclude: - - BUILD_BITS: 32 + - plat: x86 INTERFACE64: 1 fail-fast: false runs-on: ${{ matrix.os }} @@ -36,18 +36,18 @@ jobs: - name: Set env variables run: | echo "START_DIR=$PWD" >> $env:GITHUB_ENV - $BITS = ${{ matrix.BUILD_BITS }} - echo "BUILD_BITS=$BITS" >> $env:GITHUB_ENV # For interpretation of MSYSTEM, see: # https://sourceforge.net/p/msys2/discussion/general/thread/b7dfdac8/#3939 - if ($BITS -eq 32) { + if ( ${{ matrix.plat }} -eq x86) { echo "PLAT=i686" >> $env:GITHUB_ENV echo "MSYSTEM=MINGW32" >> $env:GITHUB_ENV echo "LDFLAGS=-static -static-libgcc" >> $env:GITHUB_ENV + echo "BUILD_BITS=32" >> $env:GITHUB_ENV } else { echo "PLAT=x86_64" >> $env:GITHUB_ENV echo "MSYSTEM=UCRT64" >> $env:GITHUB_ENV echo "LDFLAGS=-lucrt -static -static-libgcc" >> $env:GITHUB_ENV + echo "BUILD_BITS=64" >> $env:GITHUB_ENV } if ( ${{ matrix.INTERFACE64 }} -eq 1 ) { echo "INTERFACE64=1" >> $env:GITHUB_ENV @@ -70,10 +70,16 @@ jobs: run: | cp for_test\test*.exe builds - - name: Set up Python 3.8 + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.7 + architecture: ${{ matrix.plat }} + + + - name: Build wheel + run: | + & $env:BASH_PATH -lc tools/build_wheel_winbash.sh - uses: actions/upload-artifact@v3 with: diff --git a/setup.py b/setup.py index f0d83c13..c1c80744 100644 --- a/setup.py +++ b/setup.py @@ -28,12 +28,17 @@ def get_tag(self): cmdclass = {} py_limited_api = {} +library_dir=os.path.join(mydir, 'local', 'openblas', 'lib') +if sys.platform == "win32": + libnames = [x for x in os.listdir(library_dir) if x.endswith(".lib")] +else: + libnames = [x for x in os.listdir(library_dir) if x.startswith("libopenblas")] setup( cmdclass=cmdclass, ext_modules=[Extension( "openblas._init_openblas", ["src/_init_openblas.c"], libraries=["openblas_python"], - library_dirs=[os.path.join(mydir, 'local', 'openblas', 'lib'),], + library_dirs=[library_dir], extra_link_args=["-Wl,-rpath,$ORIGIN/lib"], define_macros=macros, **py_limited_api diff --git a/tools/build_wheel_winbash.sh b/tools/build_wheel_winbash.sh new file mode 100644 index 00000000..15dbb031 --- /dev/null +++ b/tools/build_wheel_winbash.sh @@ -0,0 +1,18 @@ +# This will fail if there is more than one file in libs +unzip -d local/openblas libs/openblas*.zip +if [ -d local/openblas/64 ]; then + mv local/openblas/64/* local/openblas + rm -rf local/openblas/64 +else + mv local/openblas/32/* local/openblas + rm -rf local/openblas/32 +fi + +rm local/openblas/lib/*.a +rm local/openblas/lib/*.exp +rm local/openblas/lib/*.def +mv local/openblas/bin/* local/openblas/lib + +python3.7 -m pip install wheel auditwheel +python3.7 -m pip wheel -w /tmp/wheelhouse -vv . +auditwheel repair -w dist/ /tmp/wheelhouse/openblas-*.whl From 6b83b12e64d8712dbcc408f089f87ec7d043d532 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 16 Aug 2023 13:36:22 +0300 Subject: [PATCH 12/23] tweak for 32/64 bit wheels, fixes for windows --- .github/workflows/posix.yml | 8 ++++---- .github/workflows/windows.yml | 38 +++++++++++++++++++++++++++++++++-- local/openblas/__init__.py | 33 +++++++++++++++++++++--------- setup.py | 24 ++++++++++++---------- src/_init_openblas.c | 5 +++-- tools/build_wheel_winbash.sh | 18 ----------------- travis-ci/build_wheel.sh | 28 +++++++++++++++++++++----- 7 files changed, 103 insertions(+), 51 deletions(-) delete mode 100644 tools/build_wheel_winbash.sh diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index d6de5cf3..134264df 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -21,7 +21,7 @@ jobs: os: [ubuntu-latest, macos-11] PLAT: [i686, x86_64] INTERFACE64: ['0', '1'] - MB_ML_VER: [2014] + MB_ML_VER: ['2014'] include: - os: macos-11 PLAT: arm64 @@ -40,8 +40,8 @@ jobs: MB_ML_LIBC: musllinux MB_ML_VER: _1_1 exclude: - - os: macos-11 - MB_ML_VER: 2014 + - PLAT: i686 + os: macos-11 - PLAT: i686 INTERFACE64: '1' env: @@ -111,7 +111,7 @@ jobs: - name: Build and test wheel run: | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - source travis-ci/build_wheel.sh + source travis-ci/build_wheel.sh else libc=${MB_ML_LIBC:-manylinux} docker_image=quay.io/pypa/${libc}${MB_ML_VER}_${PLAT} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b016e2a2..6cac0d75 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,6 +10,7 @@ env: OPENBLAS_COMMIT: "c2f4bdb" OPENBLAS_ROOT: "c:\\opt" # Preserve working directory for calls into bash + # Without this, invoking bash will cd to the home directory CHERE_INVOKING: "yes" BASH_PATH: "c:\\rtools40\\usr\\bin\\bash.exe" @@ -38,7 +39,7 @@ jobs: echo "START_DIR=$PWD" >> $env:GITHUB_ENV # For interpretation of MSYSTEM, see: # https://sourceforge.net/p/msys2/discussion/general/thread/b7dfdac8/#3939 - if ( ${{ matrix.plat }} -eq x86) { + if ( "${{ matrix.plat }}" -eq "x86") { echo "PLAT=i686" >> $env:GITHUB_ENV echo "MSYSTEM=MINGW32" >> $env:GITHUB_ENV echo "LDFLAGS=-static -static-libgcc" >> $env:GITHUB_ENV @@ -78,13 +79,46 @@ jobs: - name: Build wheel + shell: bash run: | - & $env:BASH_PATH -lc tools/build_wheel_winbash.sh + set -xeo pipefail + python -m pip install wheel + # This will fail if there is more than one file in libs + unzip -d local/openblas builds/openblas*.zip + if [[ -d local/openblas/64 ]]; then + mv local/openblas/64/* local/openblas + rm -rf local/openblas/64 + else + mv local/openblas/32/* local/openblas + rm -rf local/openblas/32 + fi + mv local/openblas/bin/*.dll local/openblas/lib + rm local/openblas/lib/*.a + rm local/openblas/lib/*.exp + rm local/openblas/lib/*.def + python -m pip wheel -w dist -vv . + + - name: Set up different Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + architecture: ${{ matrix.plat }} + + - name: Test wheel + shell: bash + run: | + python -m pip install --no-index --find-links dist openblas + # XXX FIX THIS + python -m openblas || echo ignoring error - uses: actions/upload-artifact@v3 with: path: builds/openblas*.zip + - uses: actions/upload-artifact@v3 + with: + path: dist/openblas*.whl + - uses: conda-incubator/setup-miniconda@v2 with: activate-environment: upload diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py index de77fd4e..4939399c 100644 --- a/local/openblas/__init__.py +++ b/local/openblas/__init__.py @@ -1,7 +1,14 @@ +import os from pathlib import Path +import sys +from textwrap import dedent + + +if sys.platform == "win32": + os.add_dll_directory(get_lib_dir()) + from . import _init_openblas -from textwrap import dedent _HERE = Path(__file__).resolve().parent @@ -23,33 +30,41 @@ except importlib_metadata.PackageNotFoundError: __version__ = "0.0.0" + openblas_config = _init_openblas.get_config() def get_include_dir(): - return str(_HERE / "include") + return os.path.join(_HERE, "include") def get_lib_dir(): - return str(_HERE / "lib") + return os.path.join(_HERE, "lib") def get_library(): - return "openblas_python" + if sys.platform == "win32": + libs = [x for x in os.listdir(get_lib_dir()) if x.endswith(".lib")] + return os.path.splitext(libs[0])[0] + else: + return "openblas_python" def get_pkg_config(): + if sys.platform == "win32": + extralib = "-defaultlib:advapi32 -lgfortran -defaultlib:advapi32 -lgfortran" + else: + extralib = "-lm -lpthread -lgfortran -lm -lpthread -lgfortran" return f"""\ - libdir={_HERE}/lib - includedir={_HERE}/include + libdir={get_lib_dir()} + includedir={get_include_dir()} openblas_config= {openblas_config} version={openblas_config.split(" ")[1]} - extralib=-lm -lpthread -lgfortran -lm -lpthread -lgfortran + extralib={extralib} Name: openblas Description: OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version Version: ${{version}} URL: https://github.com/xianyi/OpenBLAS - Libs: -L${libdir} -lopenblas + Libs: -L${libdir} -l{get_library()} Libs.private: ${extralib} Cflags: -I${includedir} """ - diff --git a/setup.py b/setup.py index c1c80744..b63608a9 100644 --- a/setup.py +++ b/setup.py @@ -12,13 +12,19 @@ def get_tag(self): python, abi, plat = bdist_wheel.get_tag(self) return python, "abi3", plat +library_dir=os.path.join(mydir, 'local', 'openblas', 'lib') +inc_dir=os.path.join(mydir, 'local', 'openblas', 'include') -# TODO: determine if we are building 64- or 32- bit interfaces -use_64=True -if use_64: - macros = [("SUFFIX", "64_")] +if sys.platform == "win32": + # Get libopenblas*.lib + libnames = [os.path.splitext(x)[0] + for x in os.listdir(library_dir) if x.endswith(".lib")] else: - macros = [] + # Get openblas* + libnames = [os.path.splitext(x)[0][3:] + for x in os.listdir(library_dir) if x.startswith("libopenblas")] + +macros = [] if sys.implementation.name == "cpython": cmdclass = {"bdist_wheel": bdist_wheel_abi3} @@ -28,16 +34,12 @@ def get_tag(self): cmdclass = {} py_limited_api = {} -library_dir=os.path.join(mydir, 'local', 'openblas', 'lib') -if sys.platform == "win32": - libnames = [x for x in os.listdir(library_dir) if x.endswith(".lib")] -else: - libnames = [x for x in os.listdir(library_dir) if x.startswith("libopenblas")] setup( cmdclass=cmdclass, ext_modules=[Extension( "openblas._init_openblas", ["src/_init_openblas.c"], - libraries=["openblas_python"], + include_dirs=[inc_dir], + libraries=libnames, library_dirs=[library_dir], extra_link_args=["-Wl,-rpath,$ORIGIN/lib"], define_macros=macros, diff --git a/src/_init_openblas.c b/src/_init_openblas.c index 2145b9c2..d75e6c3a 100644 --- a/src/_init_openblas.c +++ b/src/_init_openblas.c @@ -1,10 +1,11 @@ #include +#include -#ifdef SUFFIX +#ifdef OPENBLAS_USE64BITINT #define openblas_get_config openblas_get_config64_ #endif -extern const char * openblas_get_config(); +extern char* openblas_get_config(void); PyObject * get_config(PyObject *self, PyObject *args) { diff --git a/tools/build_wheel_winbash.sh b/tools/build_wheel_winbash.sh deleted file mode 100644 index 15dbb031..00000000 --- a/tools/build_wheel_winbash.sh +++ /dev/null @@ -1,18 +0,0 @@ -# This will fail if there is more than one file in libs -unzip -d local/openblas libs/openblas*.zip -if [ -d local/openblas/64 ]; then - mv local/openblas/64/* local/openblas - rm -rf local/openblas/64 -else - mv local/openblas/32/* local/openblas - rm -rf local/openblas/32 -fi - -rm local/openblas/lib/*.a -rm local/openblas/lib/*.exp -rm local/openblas/lib/*.def -mv local/openblas/bin/* local/openblas/lib - -python3.7 -m pip install wheel auditwheel -python3.7 -m pip wheel -w /tmp/wheelhouse -vv . -auditwheel repair -w dist/ /tmp/wheelhouse/openblas-*.whl diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index b53173f7..5e9b33e0 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -6,19 +6,37 @@ if [ "$?" != "0" ]; then fi mkdir -p local/openblas +mkdir -p dist +python3.7 -m pip install wheel auditwheel + # This will fail if there is more than one file in libs tar -C local/openblas --strip-components=2 -xf libs/openblas*.tar.gz # do not package the static libs and symlinks, only take the shared object find local/openblas/lib -maxdepth 1 -type l -delete rm local/openblas/lib/*.a - mv local/openblas/lib/libopenblas* local/openblas/lib/libopenblas_python.so -patchelf --set-soname libopenblas_python.so local/openblas/lib/libopenblas_python.so -python3.7 -m pip install wheel auditwheel -python3.7 -m pip wheel -w /tmp/wheelhouse -vv . -auditwheel repair -w dist/ /tmp/wheelhouse/openblas-*.whl +if [ $(uname) != "Darwin" ]; then + patchelf --set-soname libopenblas_python.so local/openblas/lib/libopenblas_python.so +elif [ "{PLAT}" == "arm64" ]]; then + source multibuild/osx_utils.sh + macos_arm64_cross_build_setup +fi + +python3.7 -m pip wheel -w dist -vv . + +if [ $(uname) == "Darwin" ]; then + python3.7 -m pip install delocate + delocate-wheel dist/*.whl +else + auditwheel repair dist/*.whl +fi + +if [ "${PLAT}" == "arm64" ]; then + # Cannot test + exit 0 +fi # Test that the wheel works with a different python python3.11 -m pip install --no-index --find-links dist openblas python3.11 -m openblas From 0d9ec08c126495ec764402782b960f30fa753b3b Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 17 Aug 2023 12:35:34 +0300 Subject: [PATCH 13/23] fix windows --- .github/workflows/windows.yml | 3 +-- local/openblas/__init__.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 6cac0d75..a06ad619 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -108,8 +108,7 @@ jobs: shell: bash run: | python -m pip install --no-index --find-links dist openblas - # XXX FIX THIS - python -m openblas || echo ignoring error + python -m openblas - uses: actions/upload-artifact@v3 with: diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py index 4939399c..e060fb4f 100644 --- a/local/openblas/__init__.py +++ b/local/openblas/__init__.py @@ -68,3 +68,13 @@ def get_pkg_config(): Libs.private: ${extralib} Cflags: -I${includedir} """ + + +if sys.platform == "win32": + os.add_dll_directory(get_lib_dir()) + + +from . import _init_openblas + + +openblas_config = _init_openblas.get_config() From 5ba618ffb3f129a36ce090c9126dc1aa515d5dc6 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 17 Aug 2023 13:27:09 +0300 Subject: [PATCH 14/23] fix auditwheel location --- travis-ci/build_wheel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index 5e9b33e0..4ca30465 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -30,7 +30,7 @@ if [ $(uname) == "Darwin" ]; then python3.7 -m pip install delocate delocate-wheel dist/*.whl else - auditwheel repair dist/*.whl + auditwheel repair -w dist dist/*.whl fi if [ "${PLAT}" == "arm64" ]; then From b1449961dc40527922e2940f89e1e2aed289c9d8 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 17 Aug 2023 16:45:06 +0300 Subject: [PATCH 15/23] only create 64-bit interface wheels (where possible) --- .github/workflows/posix.yml | 2 ++ .github/workflows/windows.yml | 8 ++++++-- local/openblas/__init__.py | 10 ---------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 134264df..dfa49c76 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -109,6 +109,7 @@ jobs: fi - name: Build and test wheel + if: matrix.plat == 'i686' || matrix.INTERFACE64 == '1' run: | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then source travis-ci/build_wheel.sh @@ -123,6 +124,7 @@ jobs: path: libs/openblas*.tar.gz - uses: actions/upload-artifact@v3 + if: matrix.plat == 'i686' || matrix.INTERFACE64 == '1' with: path: dist/openblas*.whl diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a06ad619..88a0bccc 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -23,7 +23,7 @@ jobs: os: [windows-latest] exclude: - plat: x86 - INTERFACE64: 1 + INTERFACE64: '1' fail-fast: false runs-on: ${{ matrix.os }} @@ -50,7 +50,7 @@ jobs: echo "LDFLAGS=-lucrt -static -static-libgcc" >> $env:GITHUB_ENV echo "BUILD_BITS=64" >> $env:GITHUB_ENV } - if ( ${{ matrix.INTERFACE64 }} -eq 1 ) { + if ( ${{ matrix.INTERFACE64 }} -eq "1" ) { echo "INTERFACE64=1" >> $env:GITHUB_ENV } @@ -79,6 +79,7 @@ jobs: - name: Build wheel + if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' shell: bash run: | set -xeo pipefail @@ -99,12 +100,14 @@ jobs: python -m pip wheel -w dist -vv . - name: Set up different Python + if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' uses: actions/setup-python@v4 with: python-version: 3.11 architecture: ${{ matrix.plat }} - name: Test wheel + if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' shell: bash run: | python -m pip install --no-index --find-links dist openblas @@ -115,6 +118,7 @@ jobs: path: builds/openblas*.zip - uses: actions/upload-artifact@v3 + if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' with: path: dist/openblas*.whl diff --git a/local/openblas/__init__.py b/local/openblas/__init__.py index e060fb4f..e3a17bd3 100644 --- a/local/openblas/__init__.py +++ b/local/openblas/__init__.py @@ -4,13 +4,6 @@ from textwrap import dedent -if sys.platform == "win32": - os.add_dll_directory(get_lib_dir()) - - -from . import _init_openblas - - _HERE = Path(__file__).resolve().parent __all__ = ["get_include_dir", "get_lib_dir", "get_library", "get_pkg_config"] @@ -31,9 +24,6 @@ __version__ = "0.0.0" -openblas_config = _init_openblas.get_config() - - def get_include_dir(): return os.path.join(_HERE, "include") From 457886807cf548c5f5a467f483659cc2904209c1 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 11 Sep 2023 14:37:46 +0300 Subject: [PATCH 16/23] move name to scipy_openblas64, use ctypes --- .github/workflows/posix.yml | 5 +- .github/workflows/windows.yml | 59 ++++++++++++------- .gitignore | 12 ++-- local/openblas/__main__.py | 4 -- .../__init__.py | 21 +++++-- local/scipy_openblas64/__main__.py | 4 ++ pyproject.toml | 4 +- setup.py | 49 +-------------- travis-ci/build_wheel.sh | 39 +++++++++--- 9 files changed, 102 insertions(+), 95 deletions(-) delete mode 100644 local/openblas/__main__.py rename local/{openblas => scipy_openblas64}/__init__.py (75%) create mode 100644 local/scipy_openblas64/__main__.py diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index dfa49c76..496fddbb 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -109,14 +109,13 @@ jobs: fi - name: Build and test wheel - if: matrix.plat == 'i686' || matrix.INTERFACE64 == '1' run: | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then source travis-ci/build_wheel.sh else libc=${MB_ML_LIBC:-manylinux} docker_image=quay.io/pypa/${libc}${MB_ML_VER}_${PLAT} - docker run --rm -v $(pwd):/openblas $docker_image /bin/bash -xe /openblas/travis-ci/build_wheel.sh + docker run --rm -e INTERFACE64="${INTERFACE64}" -v $(pwd):/openblas $docker_image /bin/bash -xe /openblas/travis-ci/build_wheel.sh fi - uses: actions/upload-artifact@v3 @@ -126,7 +125,7 @@ jobs: - uses: actions/upload-artifact@v3 if: matrix.plat == 'i686' || matrix.INTERFACE64 == '1' with: - path: dist/openblas*.whl + path: dist/scipy_openblas*.whl - name: Upload run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 88a0bccc..04ca23f4 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -79,48 +79,65 @@ jobs: - name: Build wheel - if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' shell: bash run: | set -xeo pipefail python -m pip install wheel # This will fail if there is more than one file in libs - unzip -d local/openblas builds/openblas*.zip - if [[ -d local/openblas/64 ]]; then - mv local/openblas/64/* local/openblas - rm -rf local/openblas/64 + unzip -d local/scipy_openblas64 builds/openblas*.zip + if [[ -d local/scipy_openblas64/64 ]]; then + mv local/scipy_openblas64/64/* local/scipy_openblas64 else - mv local/openblas/32/* local/openblas - rm -rf local/openblas/32 + mv local/scipy_openblas64/32/* local/scipy_openblas64 fi - mv local/openblas/bin/*.dll local/openblas/lib - rm local/openblas/lib/*.a - rm local/openblas/lib/*.exp - rm local/openblas/lib/*.def + mv local/scipy_openblas64/bin/*.dll local/scipy_openblas64/lib + rm local/scipy_openblas64/lib/*.a + rm local/scipy_openblas64/lib/*.exp + rm local/scipy_openblas64/lib/*.def + if [[ -d local/scipy_openblas64/64 ]]; then + rm -rf local/scipy_openblas64/64 + else + rm -rf local/scipy_openblas64/32 + fi + if [[ "${INTERFACE64}" != "1" ]]; then + mv local/scipy_openblas64 local/scipy_openblas32 + # rewrite the name of the project to scipy_openblas32 + # this is a hack, but apparently there is no other way to change the name + # of a pyproject.toml project + sed -e "s/openblas64/openblas32/" -i pyproject.toml + sed -e "s/openblas_get_config64_/openblas_get_config/" -i local/scipy_openblas32/__init__.py + sed -e "s/openblas64/openblas32/" -i local/scipy_openblas32/__main__.py + fi + python -m pip wheel -w dist -vv . - name: Set up different Python - if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' uses: actions/setup-python@v4 with: python-version: 3.11 architecture: ${{ matrix.plat }} - - name: Test wheel - if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' - shell: bash - run: | - python -m pip install --no-index --find-links dist openblas - python -m openblas - - uses: actions/upload-artifact@v3 with: path: builds/openblas*.zip - uses: actions/upload-artifact@v3 - if: matrix.plat == 'x86' || matrix.INTERFACE64 == '1' with: - path: dist/openblas*.whl + path: dist/scipy_openblas*.whl + + - name: Test 64-bit interface wheel + if: matrix.INTERFACE64 == '1' + shell: bash + run: | + python -m pip install --no-index --find-links dist scipy_openblas64 + python -m scipy_openblas64 + + - name: Test 32-bit interface wheel + if: matrix.INTERFACE64 != '1' + shell: bash + run: | + python -m pip install --no-index --find-links dist scipy_openblas32 + python -m scipy_openblas32 - uses: conda-incubator/setup-miniconda@v2 with: diff --git a/.gitignore b/.gitignore index b93366d7..74bbc8c3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,9 @@ libs/ # These are artifacts when using editable builds local/lib local/include -local/openblas.egg-info -local/openblas/lib -local/openblas/include -local/openblas/*.so -local/openblas/*.pyd -local/openblas/*.dylib +local/scipy_openblas64.egg-info +local/scipy_openblas64/lib +local/scipy_openblas64/include +local/scipy_openblas64/*.so +local/scipy_openblas64/*.pyd +local/scipy_openblas64/*.dylib diff --git a/local/openblas/__main__.py b/local/openblas/__main__.py deleted file mode 100644 index eff65cab..00000000 --- a/local/openblas/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -import openblas - -if __name__ == "__main__": - print(f"OpenBLAS using '{openblas.openblas_config}'") diff --git a/local/openblas/__init__.py b/local/scipy_openblas64/__init__.py similarity index 75% rename from local/openblas/__init__.py rename to local/scipy_openblas64/__init__.py index e3a17bd3..acf85d5e 100644 --- a/local/openblas/__init__.py +++ b/local/scipy_openblas64/__init__.py @@ -1,3 +1,4 @@ +import ctypes import os from pathlib import Path import sys @@ -6,7 +7,7 @@ _HERE = Path(__file__).resolve().parent -__all__ = ["get_include_dir", "get_lib_dir", "get_library", "get_pkg_config"] +__all__ = ["get_include_dir", "get_lib_dir", "get_library", "get_pkg_config", "openblas_config"] # Use importlib.metadata to single-source the version @@ -64,7 +65,19 @@ def get_pkg_config(): os.add_dll_directory(get_lib_dir()) -from . import _init_openblas - -openblas_config = _init_openblas.get_config() +def _get_openblas_config(): + lib_dir = get_lib_dir() + if sys.platform == "win32": + # Get libopenblas*.lib + libnames = [x for x in os.listdir(lib_dir) if x.endswith(".dll")] + else: + # Get openblas* + libnames = [x for x in os.listdir(lib_dir) if x.startswith("libopenblas")] + + dll = ctypes.CDLL(os.path.join(lib_dir, libnames[0])) + openblas_config = dll.openblas_get_config64_ + openblas_config.restype = ctypes.c_char_p + return openblas_config + +openblas_config = _get_openblas_config() diff --git a/local/scipy_openblas64/__main__.py b/local/scipy_openblas64/__main__.py new file mode 100644 index 00000000..ec7c4e02 --- /dev/null +++ b/local/scipy_openblas64/__main__.py @@ -0,0 +1,4 @@ +import scipy_openblas64 + +if __name__ == "__main__": + print(f"OpenBLAS using '{scipy_openblas64.openblas_config}'") diff --git a/pyproject.toml b/pyproject.toml index b3385e29..67e6d729 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires = [ build-backend = "setuptools.build_meta" [project] -name = "openblas" +name = "scipy_openblas64" version = "0.3.23" requires-python = ">=3.7" description = "Provides OpenBLAS for python packaging" @@ -36,4 +36,4 @@ where = ["local"] install_requires = "importlib-metadata ~= 1.0 ; python_version < '3.8'" [tool.setuptools.package-data] -openblas = ["lib/*", "include/*", "lib/pkgconfig/*", "lib/cmake/openblas/*"] +scipy_openblas64 = ["lib/*", "include/*", "lib/pkgconfig/*", "lib/cmake/openblas/*"] diff --git a/setup.py b/setup.py index b63608a9..60684932 100644 --- a/setup.py +++ b/setup.py @@ -1,48 +1,3 @@ -import os -import sys -from setuptools import setup, Extension -from wheel.bdist_wheel import bdist_wheel +from setuptools import setup - -mydir = os.path.abspath(os.path.dirname(__file__)) - - -class bdist_wheel_abi3(bdist_wheel): - def get_tag(self): - python, abi, plat = bdist_wheel.get_tag(self) - return python, "abi3", plat - -library_dir=os.path.join(mydir, 'local', 'openblas', 'lib') -inc_dir=os.path.join(mydir, 'local', 'openblas', 'include') - -if sys.platform == "win32": - # Get libopenblas*.lib - libnames = [os.path.splitext(x)[0] - for x in os.listdir(library_dir) if x.endswith(".lib")] -else: - # Get openblas* - libnames = [os.path.splitext(x)[0][3:] - for x in os.listdir(library_dir) if x.startswith("libopenblas")] - -macros = [] - -if sys.implementation.name == "cpython": - cmdclass = {"bdist_wheel": bdist_wheel_abi3} - py_limited_api = {"py_limited_api": True} - macros.append(('Py_LIMITED_API', '0x03070000')) -else: - cmdclass = {} - py_limited_api = {} - -setup( - cmdclass=cmdclass, - ext_modules=[Extension( - "openblas._init_openblas", ["src/_init_openblas.c"], - include_dirs=[inc_dir], - libraries=libnames, - library_dirs=[library_dir], - extra_link_args=["-Wl,-rpath,$ORIGIN/lib"], - define_macros=macros, - **py_limited_api - )], -) +setup() diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index 4ca30465..a6364a0b 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -1,4 +1,10 @@ +# Needs: +# $INTERFACE64 ("1" or "0") +# $PLAT (x86_64, i686, arm64, aarch64, s390x, ppc64le) + + set -xe + ls libs/openblas* >/dev/null 2>&1 && true if [ "$?" != "0" ]; then # inside docker @@ -10,20 +16,32 @@ mkdir -p dist python3.7 -m pip install wheel auditwheel # This will fail if there is more than one file in libs -tar -C local/openblas --strip-components=2 -xf libs/openblas*.tar.gz +tar -C local/scipy_openblas64 --strip-components=2 -xf libs/openblas*.tar.gz # do not package the static libs and symlinks, only take the shared object -find local/openblas/lib -maxdepth 1 -type l -delete -rm local/openblas/lib/*.a -mv local/openblas/lib/libopenblas* local/openblas/lib/libopenblas_python.so +find local/scipy_openblas64/lib -maxdepth 1 -type l -delete +rm local/scipy_openblas64/lib/*.a +# cleanup from a possible earlier run of the script +rm -f local/scipy_openblas64/lib/libopenblas_python.so +mv local/scipy_openblas64/lib/libopenblas* local/scipy_openblas64/lib/libopenblas_python.so if [ $(uname) != "Darwin" ]; then - patchelf --set-soname libopenblas_python.so local/openblas/lib/libopenblas_python.so -elif [ "{PLAT}" == "arm64" ]]; then + patchelf --set-soname libopenblas_python.so local/scipy_openblas64/lib/libopenblas_python.so +elif [ "{PLAT}" == "arm64" ]; then source multibuild/osx_utils.sh macos_arm64_cross_build_setup fi +if [ "${INTERFACE64}" != "1" ]; then + # rewrite the name of the project to scipy_openblas32 + # this is a hack, but apparently there is no other way to change the name + # of a pyproject.toml project + sed -e "s/openblas64/openblas32/" -i pyproject.toml + mv local/scipy_openblas64 local/scipy_openblas32 + sed -e "s/openblas_get_config64_/openblas_get_config/" -i local/scipy_openblas32/__init__.py + sed -e "s/openblas64/openblas32/" -i local/scipy_openblas32/__main__.py +fi + python3.7 -m pip wheel -w dist -vv . if [ $(uname) == "Darwin" ]; then @@ -38,5 +56,10 @@ if [ "${PLAT}" == "arm64" ]; then exit 0 fi # Test that the wheel works with a different python -python3.11 -m pip install --no-index --find-links dist openblas -python3.11 -m openblas +if [ "${INTERFACE64}" != "1" ]; then + python3.11 -m pip install --no-index --find-links dist scipy_openblas32 + python3.11 -m scipy_openblas32 +else + python3.11 -m pip install --no-index --find-links dist scipy_openblas64 + python3.11 -m scipy_openblas64 +fi From bab388702d174444db1342246cf880083c20559d Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 12 Sep 2023 18:32:32 +0300 Subject: [PATCH 17/23] make sed work on BSD (macos) and linux both --- travis-ci/build_wheel.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index a6364a0b..8d5f4822 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -36,10 +36,14 @@ if [ "${INTERFACE64}" != "1" ]; then # rewrite the name of the project to scipy_openblas32 # this is a hack, but apparently there is no other way to change the name # of a pyproject.toml project - sed -e "s/openblas64/openblas32/" -i pyproject.toml + # + # use the BSD variant of sed -i and remove the backup + sed -e "s/openblas64/openblas32/" -i.bak pyproject.toml + rm *.bak mv local/scipy_openblas64 local/scipy_openblas32 - sed -e "s/openblas_get_config64_/openblas_get_config/" -i local/scipy_openblas32/__init__.py - sed -e "s/openblas64/openblas32/" -i local/scipy_openblas32/__main__.py + sed -e "s/openblas_get_config64_/openblas_get_config/" -i.bak local/scipy_openblas32/__init__.py + sed -e "s/openblas64/openblas32/" -i.bak local/scipy_openblas32/__main__.py + rm local/scipy_openblas32/*.bak fi python3.7 -m pip wheel -w dist -vv . From 7181789681a5a78158913e95f04d34b42471401f Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 13 Sep 2023 09:00:46 +0300 Subject: [PATCH 18/23] rename wheels --- .github/workflows/posix.yml | 3 ++- .github/workflows/windows.yml | 8 +++++++- pyproject.toml | 2 +- travis-ci/build_wheel.sh | 5 ++++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 496fddbb..8b728493 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -120,11 +120,12 @@ jobs: - uses: actions/upload-artifact@v3 with: + name: openblas path: libs/openblas*.tar.gz - uses: actions/upload-artifact@v3 - if: matrix.plat == 'i686' || matrix.INTERFACE64 == '1' with: + name: wheels path: dist/scipy_openblas*.whl - name: Upload diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 04ca23f4..c56dece3 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -41,11 +41,13 @@ jobs: # https://sourceforge.net/p/msys2/discussion/general/thread/b7dfdac8/#3939 if ( "${{ matrix.plat }}" -eq "x86") { echo "PLAT=i686" >> $env:GITHUB_ENV + echo "WHEEL_PLAT=win32" >> $env:GITHUB_ENV echo "MSYSTEM=MINGW32" >> $env:GITHUB_ENV echo "LDFLAGS=-static -static-libgcc" >> $env:GITHUB_ENV echo "BUILD_BITS=32" >> $env:GITHUB_ENV } else { echo "PLAT=x86_64" >> $env:GITHUB_ENV + echo "WHEEL_PLAT=x86_64" >> $env:GITHUB_ENV echo "MSYSTEM=UCRT64" >> $env:GITHUB_ENV echo "LDFLAGS=-lucrt -static -static-libgcc" >> $env:GITHUB_ENV echo "BUILD_BITS=64" >> $env:GITHUB_ENV @@ -108,8 +110,10 @@ jobs: sed -e "s/openblas_get_config64_/openblas_get_config/" -i local/scipy_openblas32/__init__.py sed -e "s/openblas64/openblas32/" -i local/scipy_openblas32/__main__.py fi - + python -m pip wheel -w dist -vv . + # move the mis-named scipy_openblas64-none-any.whl to a platform-specific name + for f in dist/*.whl; do mv $f "${f/%any.whl/$WHEEL_PLAT.whl}"; done - name: Set up different Python uses: actions/setup-python@v4 @@ -119,10 +123,12 @@ jobs: - uses: actions/upload-artifact@v3 with: + name: openblas path: builds/openblas*.zip - uses: actions/upload-artifact@v3 with: + name: wheels path: dist/scipy_openblas*.whl - name: Test 64-bit interface wheel diff --git a/pyproject.toml b/pyproject.toml index 67e6d729..2fcfacdc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [project] name = "scipy_openblas64" -version = "0.3.23" +version = "0.3.23.293" requires-python = ">=3.7" description = "Provides OpenBLAS for python packaging" readme = "README.md" diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index 8d5f4822..4a2ff3bc 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -50,9 +50,12 @@ python3.7 -m pip wheel -w dist -vv . if [ $(uname) == "Darwin" ]; then python3.7 -m pip install delocate - delocate-wheel dist/*.whl + # move the mis-named scipy_openblas64-none-any.whl to a platform-specific name + for f in dist/*.whl; do mv $f "${f/%any.whl/macosx_10_9_$PLAT.whl}"; done + delocate-wheel -v dist/*.whl else auditwheel repair -w dist dist/*.whl + rm dist/scipy_openblas*-none-any.whl fi if [ "${PLAT}" == "arm64" ]; then From c62d943d95142bd103ecc757e06685e0910b7d42 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 13 Sep 2023 13:52:40 +0300 Subject: [PATCH 19/23] improve README.md, from review --- .github/workflows/windows.yml | 2 +- README.md | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c56dece3..49e99a49 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -47,7 +47,7 @@ jobs: echo "BUILD_BITS=32" >> $env:GITHUB_ENV } else { echo "PLAT=x86_64" >> $env:GITHUB_ENV - echo "WHEEL_PLAT=x86_64" >> $env:GITHUB_ENV + echo "WHEEL_PLAT=win_amd64" >> $env:GITHUB_ENV echo "MSYSTEM=UCRT64" >> $env:GITHUB_ENV echo "LDFLAGS=-lucrt -static -static-libgcc" >> $env:GITHUB_ENV echo "BUILD_BITS=64" >> $env:GITHUB_ENV diff --git a/README.md b/README.md index da70aadf..bf67d285 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,12 @@ A project using the tarball, for Manylinux or macOS, will need the ``gfortran-install`` submodule used here, from https://github.com/MacPython/gfortran-install -We also build and upload a pip-installable wheel. The wheel is self-contianed, -no additional fortran support installations are needed. The wheel supplies -interfaces for building and using OpenBLAS in a python project like SciPy or -NumPy: +We also build and upload a pip-installable wheel. The wheel is self-contained, +it includes all needed gfortran support libraries. On windows, this is a single +DLL. On linux we use `auditwheel repair` to mangle the shared object names. + +The wheel supplies interfaces for building and using OpenBLAS in a python +project like SciPy or NumPy: ## Buildtime @@ -28,6 +30,5 @@ NumPy: ## Runtime -- `open_so()` will load openblas into the executable and provide the openblas - symbols linked in from the `get_include_dir()` includes (on windows linking - with `get_lib_dir()`/`get_libarary()` is required). +- importing will load openblas into the executable and provide the openblas + symbols. From faa9a55c2a6827b275840dc073c6b571f386db16 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 13 Sep 2023 23:16:28 +0300 Subject: [PATCH 20/23] add aarch64 wheel build, fix python-level functions --- .travis.yml | 1 + OpenBLAS | 2 +- local/scipy_openblas64/__init__.py | 38 ++++++++++++++++++++++++--- src/_init_openblas.c | 41 ------------------------------ travis-ci/build_steps.sh | 5 +++- travis-ci/build_wheel.sh | 2 +- 6 files changed, 41 insertions(+), 48 deletions(-) delete mode 100644 src/_init_openblas.c diff --git a/.travis.yml b/.travis.yml index bb04b5b1..40b89dde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -86,6 +86,7 @@ install: script: # Build library and collect into libs subdirectory - build_lib "$PLAT" "$INTERFACE64" + - source travis-ci/build_wheel.sh after_success: # Upload libraries to the shared staging area on anaconda.org diff --git a/OpenBLAS b/OpenBLAS index 2183dbcf..9f815cf1 160000 --- a/OpenBLAS +++ b/OpenBLAS @@ -1 +1 @@ -Subproject commit 2183dbcfe245f20bd5a6c90f3df2c402b78453bb +Subproject commit 9f815cf1bf16b4e64d4aee681b33558fc090b62a diff --git a/local/scipy_openblas64/__init__.py b/local/scipy_openblas64/__init__.py index acf85d5e..752569a1 100644 --- a/local/scipy_openblas64/__init__.py +++ b/local/scipy_openblas64/__init__.py @@ -1,3 +1,7 @@ +""" + +""" + import ctypes import os from pathlib import Path @@ -26,14 +30,20 @@ def get_include_dir(): + """Return the include directory needed for compilation + """ return os.path.join(_HERE, "include") def get_lib_dir(): + """Return the lib directory needed for linking + """ return os.path.join(_HERE, "lib") def get_library(): + """Return the lib name needed for linking + """ if sys.platform == "win32": libs = [x for x in os.listdir(get_lib_dir()) if x.endswith(".lib")] return os.path.splitext(libs[0])[0] @@ -41,11 +51,14 @@ def get_library(): return "openblas_python" def get_pkg_config(): + """Return a multi-line string that, when saved to a file, can be used with + pkg-config for build systems like meson + """ if sys.platform == "win32": extralib = "-defaultlib:advapi32 -lgfortran -defaultlib:advapi32 -lgfortran" else: extralib = "-lm -lpthread -lgfortran -lm -lpthread -lgfortran" - return f"""\ + return dedent(f"""\ libdir={get_lib_dir()} includedir={get_include_dir()} openblas_config= {openblas_config} @@ -58,15 +71,31 @@ def get_pkg_config(): Libs: -L${libdir} -l{get_library()} Libs.private: ${extralib} Cflags: -I${includedir} - """ + """) if sys.platform == "win32": os.add_dll_directory(get_lib_dir()) - +def write__distributor_init(target): + """Accepts a Pathlib or string of a directory. + Write a pre-import file that will import scipy_openblas64 before + continuing to import the library. This will load OpenBLAS into the + executable's namespace and make the functions available for use. + """ + fname = os.path.join(target, "_distributor_init.py") + with open(fname, "wt", encoding="utf8") as fid: + fid.write(dedent(f"""\ + ''' + Helper to preload OpenBLAS from scipy_openblas64 + ''' + import scipy_openblas64 + """)) def _get_openblas_config(): + """Use ctypes to pull out the config string from the OpenBLAS library. + It will be available as `openblas_config` + """ lib_dir = get_lib_dir() if sys.platform == "win32": # Get libopenblas*.lib @@ -78,6 +107,7 @@ def _get_openblas_config(): dll = ctypes.CDLL(os.path.join(lib_dir, libnames[0])) openblas_config = dll.openblas_get_config64_ openblas_config.restype = ctypes.c_char_p - return openblas_config + return openblas_config() +# This global will keep the shared object in memory openblas_config = _get_openblas_config() diff --git a/src/_init_openblas.c b/src/_init_openblas.c deleted file mode 100644 index d75e6c3a..00000000 --- a/src/_init_openblas.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -#ifdef OPENBLAS_USE64BITINT - #define openblas_get_config openblas_get_config64_ -#endif - -extern char* openblas_get_config(void); - -PyObject * -get_config(PyObject *self, PyObject *args) { - const char * config = openblas_get_config(); - return PyUnicode_FromString(config); -} - -static PyMethodDef InitMethods[] = { - {"get_config", get_config, METH_NOARGS, - "Return openblas_get_config(), see https://github.com/xianyi/OpenBLAS/wiki/OpenBLAS-Extensions"}, - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - -static struct PyModuleDef initmodule = { - PyModuleDef_HEAD_INIT, - "_init_openblas", /* name of module */ - NULL, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module, - or -1 if the module keeps state in global variables. */ - InitMethods -}; - -PyMODINIT_FUNC -PyInit__init_openblas(void) -{ - PyObject *m; - - m = PyModule_Create(&initmodule); - if (m == NULL) - return NULL; - - return m; -} diff --git a/travis-ci/build_steps.sh b/travis-ci/build_steps.sh index 934975a3..9a2b9127 100644 --- a/travis-ci/build_steps.sh +++ b/travis-ci/build_steps.sh @@ -165,7 +165,10 @@ function do_build_lib { git config --global --add safe.directory '*' pushd OpenBLAS patch_source - CFLAGS="$CFLAGS -fvisibility=protected" make BUFFERSIZE=20 DYNAMIC_ARCH=1 USE_OPENMP=0 NUM_THREADS=64 BINARY=$bitness $interface64_flags $target_flags > /dev/null + CFLAGS="$CFLAGS -fvisibility=protected" \ + make BUFFERSIZE=20 DYNAMIC_ARCH=1 \ + USE_OPENMP=0 NUM_THREADS=64 \ + BINARY=$bitness $interface64_flags $target_flags > /dev/null make PREFIX=$BUILD_PREFIX $interface64_flags install popd stop_spinner diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index 4a2ff3bc..5b7a5d1a 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -54,7 +54,7 @@ if [ $(uname) == "Darwin" ]; then for f in dist/*.whl; do mv $f "${f/%any.whl/macosx_10_9_$PLAT.whl}"; done delocate-wheel -v dist/*.whl else - auditwheel repair -w dist dist/*.whl + auditwheel repair -w dist --lib-sdir /lib dist/*.whl rm dist/scipy_openblas*-none-any.whl fi From 6be4a46485d5140ec95ec8ef069c90f2cf17a775 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 14 Sep 2023 12:28:38 +0300 Subject: [PATCH 21/23] more tweaks to globally load the dll, run aarch64 wheel build inside docker --- .travis.yml | 4 ++- local/scipy_openblas64/__init__.py | 45 +++++++++++++++++------------- local/scipy_openblas64/__main__.py | 2 +- travis-ci/build_wheel.sh | 6 ++++ 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 40b89dde..c351ab50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -86,7 +86,9 @@ install: script: # Build library and collect into libs subdirectory - build_lib "$PLAT" "$INTERFACE64" - - source travis-ci/build_wheel.sh + - libc=${MB_ML_LIBC:-manylinux} + - docker_image=quay.io/pypa/${libc}${MB_ML_VER}_${PLAT} + - docker run --rm -e INTERFACE64="${INTERFACE64}" -v $(pwd):/openblas $docker_image /bin/bash -xe /openblas/travis-ci/build_wheel.sh after_success: # Upload libraries to the shared staging area on anaconda.org diff --git a/local/scipy_openblas64/__init__.py b/local/scipy_openblas64/__init__.py index 752569a1..a870fc5a 100644 --- a/local/scipy_openblas64/__init__.py +++ b/local/scipy_openblas64/__init__.py @@ -11,7 +11,8 @@ _HERE = Path(__file__).resolve().parent -__all__ = ["get_include_dir", "get_lib_dir", "get_library", "get_pkg_config", "openblas_config"] +__all__ = ["get_include_dir", "get_lib_dir", "get_library", "get_pkg_config", + "get_openblas_config"] # Use importlib.metadata to single-source the version @@ -61,16 +62,16 @@ def get_pkg_config(): return dedent(f"""\ libdir={get_lib_dir()} includedir={get_include_dir()} - openblas_config= {openblas_config} - version={openblas_config.split(" ")[1]} + openblas_config= {get_openblas_config()} + version={get_openblas_config().split(" ")[1]} extralib={extralib} Name: openblas Description: OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version Version: ${{version}} URL: https://github.com/xianyi/OpenBLAS - Libs: -L${libdir} -l{get_library()} - Libs.private: ${extralib} - Cflags: -I${includedir} + Libs: -L${{libdir}} -l{get_library()} + Libs.private: ${{extralib}} + Cflags: -I${{includedir}} """) @@ -92,22 +93,26 @@ def write__distributor_init(target): import scipy_openblas64 """)) -def _get_openblas_config(): +dll = None +def get_openblas_config(): """Use ctypes to pull out the config string from the OpenBLAS library. - It will be available as `openblas_config` """ - lib_dir = get_lib_dir() - if sys.platform == "win32": - # Get libopenblas*.lib - libnames = [x for x in os.listdir(lib_dir) if x.endswith(".dll")] - else: - # Get openblas* - libnames = [x for x in os.listdir(lib_dir) if x.startswith("libopenblas")] + # Keep the dll alive + global dll + if not dll: + lib_dir = get_lib_dir() + if sys.platform == "win32": + # Get libopenblas*.lib + libnames = [x for x in os.listdir(lib_dir) if x.endswith(".dll")] + else: + # Get openblas* + libnames = [x for x in os.listdir(lib_dir) if x.startswith("libopenblas")] - dll = ctypes.CDLL(os.path.join(lib_dir, libnames[0])) + dll = ctypes.CDLL(os.path.join(lib_dir, libnames[0])) openblas_config = dll.openblas_get_config64_ openblas_config.restype = ctypes.c_char_p - return openblas_config() - -# This global will keep the shared object in memory -openblas_config = _get_openblas_config() + bytes = openblas_config() + return bytes.decode("utf8") + +# Import the DLL which will make the namespace available to NumPy/SciPy +get_openblas_config() diff --git a/local/scipy_openblas64/__main__.py b/local/scipy_openblas64/__main__.py index ec7c4e02..f35d32ef 100644 --- a/local/scipy_openblas64/__main__.py +++ b/local/scipy_openblas64/__main__.py @@ -1,4 +1,4 @@ import scipy_openblas64 if __name__ == "__main__": - print(f"OpenBLAS using '{scipy_openblas64.openblas_config}'") + print(f"OpenBLAS using '{scipy_openblas64.get_openblas_config()}'") diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index 5b7a5d1a..a9db9715 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -46,6 +46,7 @@ if [ "${INTERFACE64}" != "1" ]; then rm local/scipy_openblas32/*.bak fi +rm -rf dist/* python3.7 -m pip wheel -w dist -vv . if [ $(uname) == "Darwin" ]; then @@ -56,6 +57,11 @@ if [ $(uname) == "Darwin" ]; then else auditwheel repair -w dist --lib-sdir /lib dist/*.whl rm dist/scipy_openblas*-none-any.whl + # Add an RPATH to libgfortran: + # https://github.com/pypa/auditwheel/issues/451 + unzip dist/*.whl "*libgfortran*" + patchelf --force-rpath --set-rpath '$ORIGIN' */lib/libgfortran* + zip dist/*.whl */lib/libgfortran* fi if [ "${PLAT}" == "arm64" ]; then From 14d3cbfb5b4d72301ca95c069b69d638f1df98e1 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 14 Sep 2023 13:06:57 +0300 Subject: [PATCH 22/23] install zip for rpath mangling --- .github/workflows/posix.yml | 5 ++++- travis-ci/build_wheel.sh | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 8b728493..16ce6f69 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -115,7 +115,10 @@ jobs: else libc=${MB_ML_LIBC:-manylinux} docker_image=quay.io/pypa/${libc}${MB_ML_VER}_${PLAT} - docker run --rm -e INTERFACE64="${INTERFACE64}" -v $(pwd):/openblas $docker_image /bin/bash -xe /openblas/travis-ci/build_wheel.sh + docker run --rm -e INTERFACE64="${INTERFACE64}" \ + -e MB_ML_LIBC="${MB_ML_LIBC}" \ + -v $(pwd):/openblas $docker_image \ + /bin/bash -xe /openblas/travis-ci/build_wheel.sh fi - uses: actions/upload-artifact@v3 diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index a9db9715..1f26a22f 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -59,6 +59,11 @@ else rm dist/scipy_openblas*-none-any.whl # Add an RPATH to libgfortran: # https://github.com/pypa/auditwheel/issues/451 + if [ "$MB_ML_LIBC" == "musllinux" ]; then + apk add zip + else + yum install -y zip + fi unzip dist/*.whl "*libgfortran*" patchelf --force-rpath --set-rpath '$ORIGIN' */lib/libgfortran* zip dist/*.whl */lib/libgfortran* From f76e4c29cd7983c6f8ae2e41e8bdd5669dda60d8 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 14 Sep 2023 18:40:04 +0300 Subject: [PATCH 23/23] fixes for openblas32 and make macos min version 11.0 on arm64 --- travis-ci/build_wheel.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/travis-ci/build_wheel.sh b/travis-ci/build_wheel.sh index 1f26a22f..c8151702 100644 --- a/travis-ci/build_wheel.sh +++ b/travis-ci/build_wheel.sh @@ -43,6 +43,7 @@ if [ "${INTERFACE64}" != "1" ]; then mv local/scipy_openblas64 local/scipy_openblas32 sed -e "s/openblas_get_config64_/openblas_get_config/" -i.bak local/scipy_openblas32/__init__.py sed -e "s/openblas64/openblas32/" -i.bak local/scipy_openblas32/__main__.py + sed -e "s/openblas64/openblas32/" -i.bak local/scipy_openblas32/__init__.py rm local/scipy_openblas32/*.bak fi @@ -52,7 +53,11 @@ python3.7 -m pip wheel -w dist -vv . if [ $(uname) == "Darwin" ]; then python3.7 -m pip install delocate # move the mis-named scipy_openblas64-none-any.whl to a platform-specific name - for f in dist/*.whl; do mv $f "${f/%any.whl/macosx_10_9_$PLAT.whl}"; done + if [ "{PLAT}" == "arm64" ]; then + for f in dist/*.whl; do mv $f "${f/%any.whl/macosx_11_0_$PLAT.whl}"; done + else + for f in dist/*.whl; do mv $f "${f/%any.whl/macosx_10_9_$PLAT.whl}"; done + fi delocate-wheel -v dist/*.whl else auditwheel repair -w dist --lib-sdir /lib dist/*.whl