Python Wheels #228
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |