Skip to content

Python Wheels

Python Wheels #228

Workflow file for this run

name: 'Python Wheels'
on:
workflow_dispatch:
release:
types: ['released', 'prereleased']
env:
PACKAGE_VERSION: "1.0.0a18"
PACKAGE_NAME: alpaqa
C_EXTENSIONS: _alpaqa
jobs:
generate-stubs:
runs-on: ubuntu-latest
container:
image: ubuntu:jammy
env:
HOST: 'x86_64-centos7-linux-gnu'
PYTHON_VERSION: '3.11'
CMAKE_C_COMPILER_LAUNCHER: ccache
CMAKE_CXX_COMPILER_LAUNCHER: ccache
CCACHE_DIR: /root/.ccache
steps:
# Git clone
- name: Install git
run: apt -y update && apt -y install --no-install-recommends git ca-certificates
- uses: actions/checkout@v4
with:
submodules: recursive
# Tools
- name: Install tools
uses: ./.github/workflows/toolchain
with:
host: ${{ env.HOST }}
python-version: ${{ env.PYTHON_VERSION }}
pypy: ''
# Ccache
- name: Prepare ccache directory
run: mkdir -p "${{ env.CCACHE_DIR }}"
- name: Cache ccache
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.HOST }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ env.HOST }}-ccache
# Pip install dependencies
- name: Install Python dependencies
run: python${{ env.PYTHON_VERSION }} -m pip install -U 'pip' 'build' 'pybind11-stubgen~=2.5' 'numpy<2' 'py-build-cmake~=0.2.0a12'
# Build
- name: Native build
run: |
host="${{ env.HOST }}"
staging="/opt/$host"
pbc_cli="python${{ env.PYTHON_VERSION }} -m py_build_cmake.cli"
$pbc_cli -B native-build configure -- \
-D CMAKE_C_COMPILER="$staging/x-tools/$host/bin/$host-gcc" \
-D CMAKE_CXX_COMPILER="$staging/x-tools/$host/bin/$host-g++" \
-D CMAKE_Fortran_COMPILER="$staging/x-tools/$host/bin/$host-gfortran" \
-D USE_GLOBAL_PYBIND11=On \
-D ALPAQA_WITH_CUTEST=On \
-D ALPAQA_WITH_EXTERNAL_CASADI=On \
-D CMAKE_FIND_ROOT_PATH="$staging/pybind11;$staging/eigen-master;$staging/casadi"
$pbc_cli -B native-build build -- -t ${{ env.C_EXTENSIONS }}
$pbc_cli -B native-build install --component python_stubs -- --prefix "$PWD/staging/python"
tar cf stubs.tar -C "$PWD/staging" python
# Upload
- name: Upload stubs
uses: actions/upload-artifact@v4
with:
name: stubs
retention-days: 1
path: stubs.tar
build-linux:
needs: [generate-stubs]
runs-on: ubuntu-latest
container:
image: ubuntu:jammy
strategy:
matrix:
pypy: ['', pypy]
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
host: [x86_64-centos7-linux-gnu, armv7-neon-linux-gnueabihf, armv6-rpi-linux-gnueabihf, aarch64-rpi3-linux-gnu]
include:
- python-version: '3.8'
pypy-version: '7.3.11'
- python-version: '3.9'
pypy-version: '7.3.15'
- python-version: '3.10'
pypy-version: '7.3.15'
exclude:
- pypy: pypy
python-version: '3.11'
- pypy: pypy
python-version: '3.12'
- pypy: pypy
host: armv7-neon-linux-gnueabihf
- pypy: pypy
host: armv6-rpi-linux-gnueabihf
env:
CMAKE_C_COMPILER_LAUNCHER: ccache
CMAKE_CXX_COMPILER_LAUNCHER: ccache
CCACHE_DIR: /root/.ccache
steps:
# Git clone
- name: Install git
run: apt -y update && apt -y install --no-install-recommends git ca-certificates
- uses: actions/checkout@v4
with:
submodules: recursive
# Tools
- name: Install tools
uses: ./.github/workflows/toolchain
with:
host: ${{ matrix.host }}
python-version: ${{ matrix.python-version }}
pypy: ${{ matrix.pypy }}
pypy-version: ${{ matrix.pypy-version }}
# Ccache
- name: Prepare ccache directory
run: mkdir -p "${{ env.CCACHE_DIR }}"
- name: Cache ccache
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-${{ matrix.pypy }}${{ matrix.python-version }}-${{ matrix.host }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ matrix.pypy }}${{ matrix.python-version }}-${{ matrix.host }}-ccache
# Pip install dependencies
- name: Install Python dependencies
run: python${{ matrix.python-version }} -m pip install -U 'pip' 'build' 'pybind11-stubgen~=2.5' 'numpy<2' 'py-build-cmake~=0.2.0a12'
# Download stubs
- name: Download stubs
uses: actions/download-artifact@v4
with:
name: stubs
- name: Extract stubs
run: tar xf stubs.tar
# Build
- name: Build wheels
run: |
host="${{ matrix.host }}"
staging="/opt/$host"
cat > ninja-debug-release.cross.toml <<- EOF
[cmake]
build_args = ["1"]
config = ["Debug", "Release"]
generator = "Ninja Multi-Config"
[cmake.options]
CMAKE_FIND_ROOT_PATH = "$staging/pybind11-2.11.1;$staging/eigen-master;$staging/casadi"
USE_GLOBAL_PYBIND11 = "On"
ALPAQA_WITH_CUTEST = "On"
ALPAQA_WITH_EXTERNAL_CASADI = "On"
EOF
python${{ matrix.python-version }} -m build -w . \
-C--cross="$PWD/ninja-debug-release.cross.toml" \
-C--cross="$staging/$host.py-build-cmake.cross.toml"
env:
CXXFLAGS: '-static-libstdc++'
- name: Build debug wheels
if: ${{ matrix.host == 'x86_64-centos7-linux-gnu' }}
run: |
host="${{ matrix.host }}"
staging="/opt/$host"
python${{ matrix.python-version }} -m build -w python/alpaqa-debug \
-C--cross="$PWD/ninja-debug-release.cross.toml" \
-C--cross="$staging/$host.py-build-cmake.cross.toml" \
-o dist-debug
env:
CXXFLAGS: '-static-libstdc++'
# Upload
- name: Upload Wheels
uses: actions/upload-artifact@v4
with:
name: whl-linux-${{ matrix.pypy }}${{ matrix.python-version }}-${{ matrix.host }}
retention-days: 1
path: dist/*.whl
- name: Upload debug Wheels
if: ${{ matrix.host == 'x86_64-centos7-linux-gnu' }}
uses: actions/upload-artifact@v4
with:
name: whl-debug-linux-${{ matrix.pypy }}${{ matrix.python-version }}-${{ matrix.host }}
retention-days: 1
path: dist-debug/*.whl
build-linux-src:
runs-on: ubuntu-latest
container:
image: ubuntu:jammy
env:
HOST: 'x86_64-centos7-linux-gnu'
PYTHON_VERSION: '3.11'
steps:
# Git clone
- name: Install git
run: apt -y update && apt -y install --no-install-recommends git ca-certificates
- uses: actions/checkout@v4
with:
submodules: recursive
# Tools
- name: Install tools
uses: ./.github/workflows/toolchain
with:
host: ${{ env.HOST }}
python-version: ${{ env.PYTHON_VERSION }}
pypy: ''
# Pip install dependencies
- name: Install Python dependencies
run: python${{ env.PYTHON_VERSION }} -m pip install -U pip build
# Build
- name: Build wheels
run: |
host="${{ env.HOST }}"
staging="/opt/$host"
cat > ninja-debug.cross.toml <<- EOF
[cmake]
build_args = ["1"]
config = ["Debug"]
generator = "Ninja Multi-Config"
[cmake.options]
CMAKE_FIND_ROOT_PATH = "$staging/pybind11-2.11.1;$staging/eigen-master;$staging/casadi"
USE_GLOBAL_PYBIND11 = "On"
ALPAQA_WITH_CUTEST = "On"
ALPAQA_WITH_EXTERNAL_CASADI = "On"
EOF
python${{ env.PYTHON_VERSION }} -m build . \
-C--cross="$PWD/ninja-debug.cross.toml" \
-C--cross="$staging/$host.py-build-cmake.cross.toml"
env:
CXXFLAGS: '-static-libstdc++'
# Upload
- name: Upload source
uses: actions/upload-artifact@v4
with:
name: src-dist
retention-days: 1
path: dist/*.tar.gz
test-linux:
needs: [build-linux]
runs-on: ubuntu-latest
container: python:${{ matrix.python-version }}-bullseye
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/download-artifact@v4
with:
pattern: whl-linux-*
merge-multiple: true
path: dist
- name: Test
run: |
python3 -m pip install -U pip cmake ninja
python3 -m pip install --find-links=dist "${PACKAGE_NAME}[test]==${PACKAGE_VERSION}"
pytest -rP
build-windows:
needs: [generate-stubs]
runs-on: windows-2022
strategy:
matrix:
arch: ['AMD64', 'ARM64', 'x86']
python-id: ['cp38-', 'cp39-', 'cp310-', 'cp311-', 'cp312-']
include:
- arch: 'AMD64'
python-id: 'pp38-'
- arch: 'AMD64'
python-id: 'pp39-'
- arch: 'AMD64'
python-id: 'pp310-'
exclude:
- arch: 'ARM64'
python-id: 'cp38-'
env:
CXXFLAGS: "/bigobj"
CFLAGS: "/bigobj"
PYTHONUTF8: 1
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Cache dependencies
id: cache-dep
uses: actions/cache@v4
with:
path: deps
key: deps-${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('scripts/install-eigen.ps1', 'scripts/install-casadi-static.ps1') }}
- name: Install Python dependencies
if: steps.cache-dep.outputs.cache-hit != 'true'
shell: powershell
run: |
mkdir $env:VIRTUAL_ENV
./scripts/install-eigen.ps1
./scripts/install-casadi-static.ps1
env:
VIRTUAL_ENV: ${{ github.workspace }}/deps
CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/scripts/toolchains/Win-${{ matrix.arch }}.cmake
# Download stubs
- name: Download stubs
if: ${{ matrix.arch == 'ARM64' }}
uses: actions/download-artifact@v4
with:
name: stubs
- name: Extract stubs
if: ${{ matrix.arch == 'ARM64' }}
run: tar xf stubs.tar
- name: Disable Fortran
run: |
cat > py-build-cmake.local.toml <<- EOF
[cmake.options]
CMAKE_Fortran_COMPILER = "NOTFOUND"
ALPAQA_WITH_EXTERNAL_CASADI = "On"
EOF
shell: bash
- name: Build wheels
uses: pypa/cibuildwheel@8d945475ac4b1aac4ae08b2fd27db9917158b6ce
with:
output-dir: dist
env:
CIBW_BUILD: "${{ matrix.python-id }}*"
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_TEST_SKIP: "*-{win32,win_arm64} pp*" # no CasADi binaries
CMAKE_PREFIX_PATH: ${{ github.workspace }}/deps
- name: Upload
uses: actions/upload-artifact@v4
with:
name: whl-windows-${{ matrix.python-id }}-${{ matrix.arch }}
retention-days: 1
path: dist/*.whl
build-macos:
runs-on: macos-13
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
env:
CMAKE_C_COMPILER_LAUNCHER: ccache
CMAKE_CXX_COMPILER_LAUNCHER: ccache
CCACHE_DIR: /tmp/.ccache
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
MACOSX_DEPLOYMENT_TARGET: '10.15'
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
id: python
name: Install Python
with:
python-version: ${{ matrix.python-version }}
- name: Install ccache
run: brew install ccache && ccache --version
- name: Prepare ccache directory
run: mkdir -p "${{ env.CCACHE_DIR }}"
- name: Cache ccache
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-${{ matrix.python-version }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ matrix.python-version }}-ccache
- name: Cache Virtual Environment
id: cache-venv
uses: actions/cache@v4
with:
path: py-venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ hashFiles('scripts/install-eigen.sh', 'scripts/install-casadi-static.sh') }}
- name: Install Python dependencies
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv py-venv
source ./py-venv/bin/activate
python -m pip install -U pip build cmake ninja
./scripts/install-eigen.sh
./scripts/install-casadi-static.sh
- name: Disable Fortran
run: |
cat > py-build-cmake.local.toml <<- EOF
[cmake.options]
CMAKE_Fortran_COMPILER = "NOTFOUND"
ALPAQA_WITH_EXTERNAL_CASADI = "On"
EOF
shell: bash
- name: Build
run: |
source ./py-venv/bin/activate
CMAKE_PREFIX_PATH="$VIRTUAL_ENV:$CMAKE_PREFIX_PATH" \
_PYTHON_HOST_PLATFORM='macosx-10.15-universal2' \
ARCHFLAGS='-arch arm64 -arch x86_64' \
python -m build -w .
- name: Upload
uses: actions/upload-artifact@v4
with:
name: whl-macos-${{ matrix.python-version }}
retention-days: 1
path: dist/*.whl
test-macos:
needs: [build-macos]
runs-on: macos-12
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
name: Install Python
with:
python-version: ${{ matrix.python-version }}
- uses: actions/download-artifact@v4
with:
name: whl-macos-${{ matrix.python-version }}
path: dist
- name: Test
run: |
python3 -m pip install -U pip cmake ninja
python3 -m pip install --find-links=dist "${PACKAGE_NAME}[test]==${PACKAGE_VERSION}"
pytest -rP
check-release:
if: ${{ github.event.action == 'released' || github.event.action == 'prereleased' }}
needs: [test-linux, build-linux-src, build-windows, test-macos]
runs-on: ubuntu-latest
container: python:3.11-bullseye
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
pattern: whl-linux-*
merge-multiple: true
path: dist
- name: Install package
run: python -m pip install --no-deps --no-index --find-links=dist ${PACKAGE_NAME}==${PACKAGE_VERSION}
- name: Check package version
run: |
[ "${{ github.event.release.tag_name }}" == $(python -c 'from importlib.metadata import version as v; print(v("${{ env.PACKAGE_NAME }}"))') ]
shell: bash
release:
needs: [check-release]
if: ${{ github.event.action == 'released' || github.event.action == 'prereleased' }}
runs-on: ubuntu-latest
environment:
name: release
url: https://pypi.org/p/alpaqa
permissions:
id-token: write # mandatory for trusted publishing
steps:
- uses: actions/download-artifact@v4
with:
pattern: whl-linux-*
merge-multiple: true
path: dist
- uses: actions/download-artifact@v4
with:
pattern: whl-debug-linux-*
merge-multiple: true
path: dist
- uses: actions/download-artifact@v4
with:
pattern: whl-windows-*
merge-multiple: true
path: dist
- uses: actions/download-artifact@v4
with:
pattern: whl-macos-*
merge-multiple: true
path: dist
- uses: actions/download-artifact@v4
with:
name: src-dist
path: dist
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@2f6f737ca5f74c637829c0f5c3acd0e29ea5e8bf