|
| 1 | +# SPDX-FileCopyrightText: 2026 The RISE Project |
| 2 | +# SPDX-License-Identifier: MIT |
| 3 | +# |
| 4 | +# This workflow is based on: https://github.com/apple/coremltools/blob/main/scripts/build.sh |
| 5 | +name: Build coremltools wheels (riscv64) |
| 6 | + |
| 7 | +on: |
| 8 | + workflow_dispatch: |
| 9 | + inputs: |
| 10 | + version: |
| 11 | + description: 'Version glob to (re)build; empty builds every version of docs/packages/coremltools.yaml not released yet' |
| 12 | + required: false |
| 13 | + default: '' |
| 14 | + pull_request: |
| 15 | + branches: [main] |
| 16 | + paths: |
| 17 | + - '.github/workflows/build-coremltools.yml' |
| 18 | + - 'docs/packages/coremltools.yaml' |
| 19 | + - 'patches/coremltools/**' |
| 20 | + push: |
| 21 | + branches: [main] |
| 22 | + paths: |
| 23 | + - '.github/workflows/build-coremltools.yml' |
| 24 | + - 'docs/packages/coremltools.yaml' |
| 25 | + - 'patches/coremltools/**' |
| 26 | + |
| 27 | +concurrency: |
| 28 | + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} |
| 29 | + cancel-in-progress: true |
| 30 | + |
| 31 | +permissions: |
| 32 | + contents: read |
| 33 | + |
| 34 | +env: |
| 35 | + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 |
| 36 | + PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ |
| 37 | + |
| 38 | +jobs: |
| 39 | + setup: |
| 40 | + uses: $/.github/workflows/_setup.yml |
| 41 | + with: |
| 42 | + package: coremltools |
| 43 | + version: ${{ inputs.version }} |
| 44 | + |
| 45 | + build_wheels: |
| 46 | + needs: [setup] |
| 47 | + if: needs.setup.outputs.versions != '[]' |
| 48 | + name: Build coremltools ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 |
| 49 | + runs-on: ubuntu-24.04-riscv |
| 50 | + timeout-minutes: 720 |
| 51 | + strategy: |
| 52 | + fail-fast: false |
| 53 | + matrix: |
| 54 | + version: ${{ fromJSON(needs.setup.outputs.versions) }} |
| 55 | + # Upstream stops at 3.13, and the vendored pybind11 2.13.1 predates 3.14. |
| 56 | + python: [cp312-cp312, cp313-cp313] |
| 57 | + |
| 58 | + env: |
| 59 | + COREMLTOOLS_VERSION: ${{ matrix.version }} |
| 60 | + |
| 61 | + steps: |
| 62 | + - name: Checkout apple/coremltools ${{ env.COREMLTOOLS_VERSION }} |
| 63 | + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 64 | + with: |
| 65 | + repository: apple/coremltools |
| 66 | + ref: ${{ env.COREMLTOOLS_VERSION }} |
| 67 | + path: coremltools |
| 68 | + persist-credentials: false |
| 69 | + |
| 70 | + - name: Checkout python-wheels |
| 71 | + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 72 | + with: |
| 73 | + path: python-wheels |
| 74 | + persist-credentials: false |
| 75 | + |
| 76 | + - name: Patch coremltools source |
| 77 | + working-directory: coremltools |
| 78 | + run: git apply ../python-wheels/patches/coremltools/${{ env.COREMLTOOLS_VERSION }}/00*.patch |
| 79 | + |
| 80 | + - name: Build the C++ libraries and the wheel |
| 81 | + run: | |
| 82 | + mkdir -p output "$HOME/.cache/coremltools-ccache" |
| 83 | + docker run -i --rm \ |
| 84 | + -v "$PWD/coremltools:/coremltools" \ |
| 85 | + -v "$PWD/output:/output" \ |
| 86 | + -v "$HOME/.cache/coremltools-ccache:/ccache" \ |
| 87 | + -e CCACHE_DIR=/ccache \ |
| 88 | + -e COREMLTOOLS_VERSION \ |
| 89 | + "$MANYLINUX_RISCV64_IMAGE" bash -s <<'COREMLTOOLS_BUILD_EOF' |
| 90 | + #!/usr/bin/env bash |
| 91 | + set -euxo pipefail |
| 92 | +
|
| 93 | + COREMLTOOLS_VERSION="${COREMLTOOLS_VERSION:?must be set, e.g. 9.0}" |
| 94 | + PYBIN=/opt/python/${{ matrix.python }}/bin |
| 95 | + # CMakeLists.txt builds the vendored kmeans1d with a bare `python3`, so the |
| 96 | + # interpreter this wheel is for has to be the one that wins on PATH. |
| 97 | + export PATH="$PYBIN:$PATH" |
| 98 | + # The vendored protobuf 3.19 declares cmake_minimum_required(VERSION 3.0.0). |
| 99 | + export CMAKE_POLICY_VERSION_MINIMUM=3.5 |
| 100 | +
|
| 101 | + dnf install -y --setopt=install_weak_deps=False libuuid-devel |
| 102 | +
|
| 103 | + python3 -m pip install -U setuptools wheel auditwheel |
| 104 | +
|
| 105 | + # Upstream's NOTICE.txt covers only kmeans1d; the rest of deps/ is compiled |
| 106 | + # into the shipped .so files, and auditwheel grafts in libuuid. |
| 107 | + cp /coremltools/deps/protobuf/LICENSE /coremltools/LICENSE.protobuf |
| 108 | + cp /coremltools/deps/pybind11/LICENSE /coremltools/LICENSE.pybind11 |
| 109 | + cp /coremltools/deps/nlohmann/LICENSE.MIT /coremltools/LICENSE.nlohmann-json |
| 110 | + cp /coremltools/deps/FP16/LICENSE /coremltools/LICENSE.FP16 |
| 111 | + uuid_pkg=$(rpm -qf --qf '%{NAME}\n' "$(ldconfig -p | awk '/libuuid\.so\.1 /{print $NF; exit}')") |
| 112 | + dnf reinstall -y --setopt=tsflags= "$uuid_pkg" || true |
| 113 | + cat /usr/share/licenses/"$uuid_pkg"/* > /coremltools/LICENSE.libuuid 2>/dev/null \ |
| 114 | + || rpm -q --qf '%{NAME} %{VERSION}: %{LICENSE}\n' "$uuid_pkg" > /coremltools/LICENSE.libuuid |
| 115 | +
|
| 116 | + CCACHE_ARGS="" |
| 117 | + command -v ccache >/dev/null 2>&1 && \ |
| 118 | + CCACHE_ARGS="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" |
| 119 | +
|
| 120 | + # FindPythonLibs searches standard prefixes and would find the image's own |
| 121 | + # /usr/local interpreter instead of /opt/python/<tag>, so pin it the way |
| 122 | + # scripts/env_activate.sh pins it for upstream's conda env. |
| 123 | + py_inc=$(python3 -c 'import sysconfig; print(sysconfig.get_path("include"))') |
| 124 | + py_lib=$(python3 -c 'import os, sysconfig; print(os.path.join(sysconfig.get_config_var("LIBDIR"), sysconfig.get_config_var("LIBRARY")))') |
| 125 | +
|
| 126 | + cmake -S /coremltools -B /tmp/build \ |
| 127 | + -DCMAKE_BUILD_TYPE=Release \ |
| 128 | + -DPYTHON_EXECUTABLE:FILEPATH="$PYBIN/python3" \ |
| 129 | + -DPYTHON_INCLUDE_DIR="$py_inc" \ |
| 130 | + -DPYTHON_LIBRARY="$py_lib" \ |
| 131 | + -DOVERWRITE_PB_SOURCE=0 \ |
| 132 | + ${CCACHE_ARGS} |
| 133 | + cmake --build /tmp/build -j "$(nproc)" |
| 134 | + cmake --build /tmp/build --target dist |
| 135 | +
|
| 136 | + auditwheel repair --strip /tmp/build/dist/coremltools-*.whl -w /output |
| 137 | + ls -la /output |
| 138 | + COREMLTOOLS_BUILD_EOF |
| 139 | +
|
| 140 | + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 |
| 141 | + with: |
| 142 | + name: coremltools-${{ env.COREMLTOOLS_VERSION }}-${{ matrix.python }}-manylinux_riscv64 |
| 143 | + path: output/*.whl |
| 144 | + if-no-files-found: error |
| 145 | + |
| 146 | + - name: Test coremltools wheel |
| 147 | + run: | |
| 148 | + docker run -i --rm \ |
| 149 | + -v "$PWD/output:/output" \ |
| 150 | + -e PIP_EXTRA_INDEX_URL \ |
| 151 | + -e PIP_ONLY_BINARY=numpy,pillow \ |
| 152 | + "$MANYLINUX_RISCV64_IMAGE" bash -s <<'COREMLTOOLS_TEST_EOF' |
| 153 | + #!/usr/bin/env bash |
| 154 | + set -euxo pipefail |
| 155 | +
|
| 156 | + PYBIN=/opt/python/${{ matrix.python }}/bin |
| 157 | +
|
| 158 | + "$PYBIN/pip" install -U pytest pytest-timeout parameterized pillow |
| 159 | + "$PYBIN/pip" install /output/coremltools-*.whl |
| 160 | +
|
| 161 | + "$PYBIN/python3" -c " |
| 162 | + from coremltools import libmilstoragepython, libmodelpackage |
| 163 | + assert libmilstoragepython.__file__.endswith('.so'), libmilstoragepython.__file__ |
| 164 | + assert libmodelpackage.__file__.endswith('.so'), libmodelpackage.__file__ |
| 165 | + " |
| 166 | +
|
| 167 | + # Upstream's scripts/test.sh runs the suite out of the installed wheel with |
| 168 | + # --pyargs, from a directory that is not the checkout. torch, tensorflow, |
| 169 | + # scikit-learn and xgboost have no riscv64 wheels, so this is the subset of |
| 170 | + # upstream's coremltools.test / mil jobs that collects without them; the two |
| 171 | + # -k exclusions are tests that import torch inside the test body. |
| 172 | + mkdir -p /tmp/testrun && cd /tmp/testrun |
| 173 | + "$PYBIN/python3" -m pytest -v -ra --timeout=600 \ |
| 174 | + -k "not (TestApiVisibilities and test_optimize) and not test_model_save_no_extension" \ |
| 175 | + --pyargs \ |
| 176 | + coremltools.test.api \ |
| 177 | + coremltools.test.blob \ |
| 178 | + coremltools.test.modelpackage.test_modelpackage \ |
| 179 | + coremltools.converters.mil.backend \ |
| 180 | + coremltools.converters.mil.mil.tests.test_types |
| 181 | + COREMLTOOLS_TEST_EOF |
| 182 | +
|
| 183 | + publish: |
| 184 | + name: Publish coremltools ${{ matrix.version }} |
| 185 | + needs: [setup, build_wheels] |
| 186 | + if: needs.setup.outputs.versions != '[]' |
| 187 | + strategy: |
| 188 | + fail-fast: false |
| 189 | + matrix: |
| 190 | + version: ${{ fromJSON(needs.setup.outputs.versions) }} |
| 191 | + permissions: |
| 192 | + contents: write |
| 193 | + pull-requests: write |
| 194 | + uses: $/.github/workflows/_publish-wheel.yml |
| 195 | + secrets: |
| 196 | + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} |
| 197 | + with: |
| 198 | + artifact-pattern: coremltools-${{ matrix.version }}-*-manylinux_riscv64 |
0 commit comments