-
Notifications
You must be signed in to change notification settings - Fork 7
Setup cibuildwheel with Linux, macOS, Windows wheels #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,36 +4,149 @@ on: | |
release: | ||
types: [created] | ||
|
||
# Enable Run Workflow button in GitHub UI | ||
workflow_dispatch: | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
wheels: | ||
build_sdist: | ||
name: Build SDist | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Build SDist | ||
run: pipx run build --sdist | ||
|
||
- name: Check metadata | ||
run: pipx run twine check dist/* | ||
Comment on lines
+21
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the versions of python -m pip install --upgrade pip
python -m pip install build twine or the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK you always get the latest. |
||
|
||
- uses: actions/upload-artifact@v3 | ||
with: | ||
path: dist/*.tar.gz | ||
|
||
|
||
build_wheels: | ||
name: Wheels on ${{ matrix.platform_id }} - ${{ matrix.os }} | ||
runs-on: ${{ matrix.os }} | ||
defaults: | ||
run: | ||
shell: bash -l {0} | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: ["ubuntu-latest"] | ||
# Loosely based on scikit-learn's config: | ||
# https://github.com/scikit-learn/scikit-learn/blob/main/.github/workflows/wheels.yml | ||
include: | ||
- os: windows-latest | ||
python-version: "3.8" | ||
platform_id: win_amd64 | ||
|
||
- os: ubuntu-latest | ||
python-version: "3.8" | ||
platform_id: manylinux_x86_64 | ||
manylinux_image: manylinux2014 | ||
- os: ubuntu-latest | ||
python-version: "3.8" | ||
platform_id: manylinux_aarch64 | ||
manylinux_image: manylinux2014 | ||
|
||
# Use x86 macOS runner to build both x86 and ARM. GitHub does not offer M1/M2 yet (only self-hosted). | ||
- os: macos-latest | ||
python-version: "3.8" | ||
platform_id: macosx_x86_64 | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
- name: Set up Python | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: '3.8' | ||
- name: Upgrade pip | ||
run: | | ||
python -m pip install --upgrade pip | ||
- name: Build manylinux Python wheels | ||
uses: RalfG/python-wheels-manylinux-build@v0.4.2-manylinux2014_x86_64 | ||
with: | ||
python-versions: 'cp38-cp38 cp39-cp39' | ||
build-requirements: 'cffi numpy>=1.19,<1.20 cython' | ||
pre-build-command: ${{ format('sh suitesparse.sh {0}', github.ref) }} | ||
- name: Publish wheels to PyPI | ||
env: | ||
TWINE_USERNAME: __token__ | ||
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} | ||
run: | | ||
pip install twine | ||
twine upload dist/*-manylinux*.whl | ||
- uses: actions/checkout@v3 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here: with:
fetch-depth: 0 |
||
|
||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
|
||
- name: Install tools (macOS) | ||
if: contains(matrix.os, 'macos') | ||
# * install coreutils which includes `nproc` used by `make -j` in suitesparse.sh | ||
# * GitHub actions comes with libomp already installed. It's listed here to explicitly list this requirement. | ||
run: | | ||
brew install coreutils | ||
brew install libomp | ||
|
||
- name: Build Wheels | ||
env: | ||
# very verbose | ||
CIBW_BUILD_VERBOSITY: 3 | ||
|
||
# Build SuiteSparse | ||
CIBW_BEFORE_ALL: bash suitesparse.sh ${{ github.ref }} | ||
# CIBW_BEFORE_ALL: bash suitesparse.sh refs/tags/7.4.3.0 | ||
|
||
# Ask suitesparse.sh to build libraries in MSVC style on Windows. | ||
CIBW_ENVIRONMENT_WINDOWS: CMAKE_GNUtoMS=ON | ||
|
||
# macOS libomp setup. | ||
# FindOpenMP doesn't find brew's libomp, so set the necessary configs manually. | ||
# The OpenMP_* variables need to be passed to CMake as -D defines, that is done by suitesparse.sh | ||
CIBW_ENVIRONMENT_MACOS: LDFLAGS="-L$(brew --prefix libomp)/lib" OpenMP_C_FLAGS="-Xclang -fopenmp -I$(brew --prefix libomp)/include" OpenMP_C_LIB_NAMES="libomp" OpenMP_libomp_LIBRARY="omp" | ||
|
||
# Uncomment to only build CPython wheels | ||
# CIBW_BUILD: "cp*" | ||
|
||
# macOS: build x86_64 and arm64 | ||
CIBW_ARCHS_MACOS: "x86_64 arm64" | ||
|
||
# No 32-bit builds | ||
CIBW_SKIP: "*-win32 *_i686" | ||
|
||
# Use delvewheel on Windows. | ||
# This copies graphblas.dll into the wheel. "repair" in cibuildwheel parlance includes copying any shared | ||
# libraries from the build host into the wheel to make the wheel self-contained. | ||
# Cibuildwheel includes tools for this for Linux and macOS, and they recommend delvewheel for Windows. | ||
CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel" | ||
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path \"C:\\Program Files (x86)\\bin\" --no-mangle \"libgomp-1.dll;libgcc_s_seh-1.dll\" -w {dest_dir} {wheel}" | ||
|
||
# Test dependencies | ||
CIBW_TEST_REQUIRES: "pytest" | ||
|
||
# run tests | ||
CIBW_TEST_COMMAND: "pytest {project}/suitesparse_graphblas/tests" | ||
|
||
# GitHub Actions macOS Intel runner cannot run ARM tests. | ||
CIBW_TEST_SKIP: "*-macosx_arm64" | ||
|
||
run: | | ||
python -m pip install cibuildwheel | ||
python -m cibuildwheel --output-dir wheelhouse . | ||
shell: bash | ||
|
||
- uses: actions/upload-artifact@v3 | ||
with: | ||
path: wheelhouse/*.whl | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For sanity check, maybe add if-no-files-found: error |
||
|
||
upload_all: | ||
name: Upload to PyPI | ||
needs: [build_wheels, build_sdist] | ||
runs-on: ubuntu-latest | ||
# if: github.event_name == 'release' && github.event.action == 'published' | ||
|
||
steps: | ||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: "3.x" | ||
|
||
- uses: actions/download-artifact@v3 | ||
with: | ||
name: artifact | ||
path: dist | ||
|
||
- uses: pypa/gh-action-pypi-publish@release/v1 | ||
with: | ||
# PyPI does not allow replacing a file. Without this flag the entire action fails if even a single duplicate exists. | ||
skip_existing: true | ||
verbose: true | ||
# Real PyPI: | ||
# password: ${{ secrets.PYPI_TOKEN }} | ||
|
||
# Test PyPI: | ||
password: ${{ secrets.TEST_PYPI_API_TOKEN }} | ||
repository_url: https://test.pypi.org/legacy/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,68 @@ | ||
#!/bin/bash | ||
|
||
# parse SuiteSparse version from first argument, a git tag that ends in the version (no leading v) | ||
if [[ $1 =~ refs/tags/([0-9]*\.[0-9]*\.[0-9]*)\..*$ ]]; | ||
then | ||
VERSION=${BASH_REMATCH[1]} | ||
else | ||
echo "Specify a SuiteSparse version, such as: $0 refs/tags/7.4.3.0" | ||
exit -1 | ||
fi | ||
echo VERSION: $VERSION | ||
|
||
NPROC="$(nproc)" | ||
if [ -z "${NPROC}" ]; then | ||
# Default for platforms that don't have nproc. Mostly Windows. | ||
NPROC="2" | ||
fi | ||
|
||
cmake_params=() | ||
if [ -n "${OpenMP_C_FLAGS}" ]; then | ||
# macOS OpenMP flags. | ||
# wheels.yml sets them as env vars, but CMake needs them as -D defs. | ||
cmake_params+=(-DOpenMP_C_FLAGS="${OpenMP_C_FLAGS}") | ||
cmake_params+=(-DOpenMP_C_LIB_NAMES="${OpenMP_C_LIB_NAMES}") | ||
cmake_params+=(-DOpenMP_libomp_LIBRARY="${OpenMP_libomp_LIBRARY}") | ||
fi | ||
|
||
if [ -n "${CMAKE_GNUtoMS}" ]; then | ||
# Windows needs .lib libraries, not .a | ||
cmake_params+=(-DCMAKE_GNUtoMS=ON) | ||
# Windows expects 'graphblas.lib', not 'libgraphblas.lib' | ||
cmake_params+=(-DCMAKE_SHARED_LIBRARY_PREFIX=) | ||
cmake_params+=(-DCMAKE_STATIC_LIBRARY_PREFIX=) | ||
fi | ||
|
||
curl -L https://github.com/DrTimothyAldenDavis/GraphBLAS/archive/refs/tags/v${VERSION}.tar.gz | tar xzf - | ||
cd GraphBLAS-${VERSION}/build | ||
cmake .. -DCMAKE_BUILD_TYPE=Release | ||
make -j$(nproc) | ||
|
||
# Disable optimizing some rarely-used types for significantly faster builds and significantly smaller wheel size. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If experimenting with the workflow I recommend disabling all the types. That brings the GraphBLAS build times into the 15 minute range on GitHub Actions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a non-documented feature that you can use for this. Turn on the CMAKE_CUDA_DEV flag in the GraphBLAS CmakeLists.txt. That disables all compilation of the kernels in Source/Generated2. I don't recommend that for production so I don't document it. The resulting GraphBLAS will be pretty slow. But it's nice for development. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DrTimothyAldenDavis I thought I was going crazy because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DrTimothyAldenDavis Just FYI, compiling that combinatorial explosion of types really does make working with GraphBLAS very difficult. This PR would not happen if GitHub's accounting wasn't broken, as the CI time should have cost me several hundred dollars. With the types disabled as seen here, building just the macOS wheels one time costs about $3.50 according to GitHub's published price list ($5 for all OSes). I'm estimating well over $20/run for all types enabled. I don't mind because GitHub doesn't have my credit card and they aren't counting anything against my free quota, but that's just luck on our part. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's intentional. It is not meant for anyone else to use but me. It is supposed be very hard to turn on GBCUDA_DEV, because turning it on slows down GraphBLAS immensely (run time, not compile time). If it's easy to turn on GBCUDA_DEV, then I worry that it would be compiled that way for production and distribution, as in a linux distro or conda package. That would be awful. If you like, you could instead compile with
I do not recommend that for a production build. See GraphBLAS/Source/GB_control.h: GraphBLAS requires a surprisingly large amount of semirings and operators when used in production. I'm working on a JIT where I can compile these at run-time, however. That will keep the performance up (and even improve it) while at the same time reducing the initial compile time. Distros will have to package my source code for that to work, however. |
||
# Also the build with all types enabled sometimes stalls on GitHub Actions. Probably due to exceeded resource limits. | ||
# These can still be used, they'll just have reduced performance (AFAIK similar to UDTs). | ||
#echo "#define GxB_NO_BOOL 1" >> ../Source/GB_control.h # | ||
#echo "#define GxB_NO_FP32 1" >> ../Source/GB_control.h # | ||
#echo "#define GxB_NO_FP64 1" >> ../Source/GB_control.h # | ||
#echo "#define GxB_NO_FC32 1" >> ../Source/GB_control.h # | ||
#echo "#define GxB_NO_FC64 1" >> ../Source/GB_control.h # | ||
echo "#define GxB_NO_INT16 1" >> ../Source/GB_control.h | ||
echo "#define GxB_NO_INT32 1" >> ../Source/GB_control.h | ||
#echo "#define GxB_NO_INT64 1" >> ../Source/GB_control.h # | ||
echo "#define GxB_NO_INT8 1" >> ../Source/GB_control.h | ||
echo "#define GxB_NO_UINT16 1" >> ../Source/GB_control.h | ||
echo "#define GxB_NO_UINT32 1" >> ../Source/GB_control.h | ||
echo "#define GxB_NO_UINT64 1" >> ../Source/GB_control.h | ||
echo "#define GxB_NO_UINT8 1" >> ../Source/GB_control.h | ||
|
||
cmake .. -DCMAKE_BUILD_TYPE=Release -G 'Unix Makefiles' "${cmake_params[@]}" | ||
make -j$NPROC | ||
make install | ||
|
||
if [ -n "${CMAKE_GNUtoMS}" ]; then | ||
# Windows: | ||
# CMAKE_STATIC_LIBRARY_PREFIX is sometimes ignored, possibly when the MinGW toolchain is selected. | ||
# Drop the 'lib' prefix manually. | ||
echo "manually removing lib prefix" | ||
mv "C:/Program Files (x86)/lib/libgraphblas.lib" "C:/Program Files (x86)/lib/graphblas.lib" | ||
mv "C:/Program Files (x86)/lib/libgraphblas.dll.a" "C:/Program Files (x86)/lib/graphblas.dll.a" | ||
cp "C:/Program Files (x86)/bin/libgraphblas.dll" "C:/Program Files (x86)/bin/graphblas.dll" | ||
fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add
to make sure it can always find a tag to use as the version.