Build Pip Wheels #464
This file contains hidden or 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: Build Pip Wheels | |
| # When ran from the github UI, we build the target commit exactly. | |
| # When ran on release, we use the latest tagged commit in the `master` branch. | |
| # This doesn't run directly on pull request, because it's impossible to disable the whole file | |
| # with a single condition (specific label present). Because of that, we conditionally run this from a separate `.yml` file. | |
| on: | |
| release: | |
| types: [ published ] | |
| # This is the manual run from the UI. | |
| workflow_dispatch: | |
| inputs: | |
| vcpkg_docker_image_tag: | |
| # Empty string means the same thing as "latest", but we use an empty string here to ensure this works, | |
| # because `types: [published]` can't have any inputs, so there we are forced to use an empty string, so it needs to work. | |
| default: "" | |
| required: false | |
| type: string | |
| publish: | |
| default: false | |
| required: false | |
| type: boolean | |
| # This is the `uses:` call from other `.yml` files. | |
| workflow_call: | |
| inputs: | |
| vcpkg_docker_image_tag: | |
| required: true | |
| type: string | |
| publish: | |
| default: false | |
| required: false | |
| type: boolean | |
| disable_ubuntu_x64: | |
| default: false | |
| required: false | |
| type: boolean | |
| disable_ubuntu_arm64: | |
| default: false | |
| required: false | |
| type: boolean | |
| disable_macos: | |
| default: false | |
| required: false | |
| type: boolean | |
| disable_windows: | |
| default: false | |
| required: false | |
| type: boolean | |
| jobs: | |
| setup: | |
| timeout-minutes: 5 | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version_tag: ${{ steps.get-latest-tag.outputs.tag }} | |
| build-matrix: ${{ steps.build-matrix.outputs.matrix }} | |
| test-matrix: ${{ steps.test-matrix.outputs.matrix }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| # Disabling this with an `if:` results in `steps.get-latest-tag.outputs.tag` being empty. | |
| # Passing that to `ref:` makes it default to the current commit, which is exactly what we need. | |
| - uses: actions-ecosystem/action-get-latest-tag@v1 | |
| if: ${{ github.event_name == 'release' || inputs.publish }} | |
| id: get-latest-tag | |
| - id: build-matrix | |
| uses: ./.github/actions/matrix-builder | |
| with: | |
| matrix: | | |
| platform: | |
| - x86_64 | |
| - aarch64 | |
| rules: | | |
| - extend: | |
| - platform: x86_64 | |
| os: rockylinux8-vcpkg-x64 | |
| container-options: "--user root" | |
| runner: ubuntu-latest | |
| compiler: /usr/bin/clang++ | |
| container-prefix: "" | |
| - platform: aarch64 | |
| os: rockylinux8-vcpkg-arm64 | |
| container-options: " " | |
| runner: ubuntu-24.04-arm | |
| compiler: /usr/bin/clang++ | |
| container-prefix: arm64v8/ | |
| - if: ${{ inputs.disable_ubuntu_x64 }} | |
| exclude: | |
| platform: x86_64 | |
| - if: ${{ inputs.disable_ubuntu_arm64 }} | |
| exclude: | |
| platform: aarch64 | |
| - id: test-matrix | |
| uses: ./.github/actions/matrix-builder | |
| with: | |
| matrix: | | |
| platform: | |
| - x86_64 | |
| - aarch64 | |
| py-version: | |
| - "3.8" | |
| - "3.9" | |
| - "3.10" | |
| - "3.11" | |
| - "3.12" | |
| - "3.13" | |
| - "3.14" | |
| rules: | | |
| - extend: | |
| - platform: x86_64 | |
| container-options: "--user root" | |
| runner: ubuntu-latest | |
| compiler: /usr/bin/clang++ | |
| container-prefix: "" | |
| - platform: aarch64 | |
| container-options: " " | |
| runner: ubuntu-24.04-arm | |
| compiler: /usr/bin/clang++ | |
| container-prefix: arm64v8/ | |
| - extend: | |
| - py-version: "3.8" | |
| os: "rockylinux:8" | |
| - py-version: "3.9" | |
| os: "debian:11-slim" | |
| - py-version: "3.10" | |
| os: "ubuntu:22.04" | |
| - py-version: "3.11" | |
| os: "fedora:37" | |
| - py-version: "3.12" | |
| os: "fedora:39" | |
| - py-version: "3.13" | |
| os: "fedora:42" | |
| - py-version: "3.14" | |
| os: "ubuntu:25.10" | |
| - if: ${{ inputs.disable_ubuntu_x64 }} | |
| exclude: | |
| platform: x86_64 | |
| - if: ${{ inputs.disable_ubuntu_arm64 }} | |
| exclude: | |
| platform: aarch64 | |
| generate-c-bindings: | |
| needs: setup | |
| uses: ./.github/workflows/generate-c-bindings.yml | |
| with: | |
| docker_image_tag: ${{ inputs.vcpkg_docker_image_tag }} | |
| version_tag: ${{needs.setup.outputs.version_tag}} | |
| manylinux-pip-build: | |
| needs: setup | |
| # Skip entirely when both platforms are disabled (empty matrix would | |
| # otherwise error out on GitHub Actions). | |
| if: ${{ needs.setup.outputs.build-matrix != '[]' }} | |
| timeout-minutes: 80 | |
| runs-on: ${{ matrix.runner }} | |
| container: | |
| image: meshlib/meshlib-${{ matrix.os }}:${{ inputs.vcpkg_docker_image_tag || 'latest' }} | |
| options: ${{ matrix.container-options }} | |
| strategy: | |
| fail-fast: false | |
| # `include` enumerates the per-platform combos, surviving platforms | |
| # only. See `setup.matrix` step for the include/exclude logic. | |
| matrix: | |
| include: ${{ fromJSON(needs.setup.outputs.build-matrix) }} | |
| steps: | |
| - name: Work-around possible permission issues | |
| shell: bash | |
| run: | | |
| # NOTE: {GITHUB_WORKSPACE} != {{ github.workspace }} | |
| # Related issue: https://github.com/actions/runner/issues/2058 | |
| if test -d $GITHUB_WORKSPACE && test -n "$(find ${GITHUB_WORKSPACE} -user root)" ; then | |
| mv ${GITHUB_WORKSPACE} ${GITHUB_WORKSPACE}_${RANDOM} | |
| mkdir ${GITHUB_WORKSPACE} | |
| fi | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: ${{needs.setup.outputs.version_tag}} | |
| - name: Checkout third-party submodules | |
| # Some of those safe.directory rules could be redudant. | |
| run: | | |
| # have to checkout selective submodules by our own | |
| # related issue: https://github.com/actions/checkout/issues/1779 | |
| export HOME=${RUNNER_TEMP} | |
| echo ${GITHUB_WORKSPACE} | |
| git config --global --add safe.directory ${GITHUB_WORKSPACE} | |
| git config --global --add safe.directory ${GITHUB_WORKSPACE}/thirdparty/imgui | |
| git config --global --add safe.directory ${GITHUB_WORKSPACE}/thirdparty/parallel-hashmap | |
| git config --global --add safe.directory ${GITHUB_WORKSPACE}/thirdparty/mrbind-pybind11 | |
| git config --global --add safe.directory ${GITHUB_WORKSPACE}/thirdparty/mrbind | |
| git config --global --add safe.directory ${GITHUB_WORKSPACE}/thirdparty/mrbind/deps/cppdecl | |
| # Retried via retry.sh: submodule endpoints occasionally 500. | |
| bash scripts/retry.sh -- git submodule update --init --depth 1 \ | |
| thirdparty/imgui \ | |
| thirdparty/parallel-hashmap \ | |
| thirdparty/mrbind-pybind11 \ | |
| thirdparty/mrbind | |
| # mrbind needs deps/cppdecl; recurse only there | |
| bash scripts/retry.sh -- git -C thirdparty/mrbind submodule update --init --depth 1 deps/cppdecl | |
| - name: Install mrbind | |
| uses: ./.github/actions/build-mrbind | |
| with: | |
| # Prefix is shared with build-test-linux-vcpkg.yml, which uses the same | |
| # image and script. The Dockerfile hash in extra-cache-key busts the cache | |
| # whenever the toolchain inside the image changes (e.g. clang upgrade). | |
| cache-key-prefix: ${{ matrix.os }} | |
| build-script: scripts/mrbind/install_mrbind_rockylinux.sh | |
| extra-cache-key: ${{ hashFiles('docker/rockylinux8-vcpkgDockerfile') }} | |
| - name: Print RAM | |
| # If there's not enough RAM, building MRBind bindings can fail. Not running this in the mrbind step itself, because OOM fails can erase logs from the current step. | |
| run: free -h | |
| - name: Build | |
| run: ./scripts/build_source.sh | |
| env: | |
| MESHLIB_BUILD_RELEASE: "ON" | |
| MESHLIB_BUILD_DEBUG: "OFF" | |
| CMAKE_CXX_COMPILER: ${{ matrix.compiler }} | |
| MR_CMAKE_OPTIONS: > | |
| -DMRVIEWER_NO_GTK=ON | |
| -DMR_PCH_USE_EXTRA_HEADERS=ON | |
| -DCMAKE_CUDA_HOST_COMPILER=/opt/rh/gcc-toolset-11/root/usr/bin/g++ | |
| - name: Generate and build MRBind bindings | |
| run: | | |
| make -f scripts/mrbind/generate.mk -B --trace \ | |
| FOR_WHEEL=1 \ | |
| CXX_FOR_ABI=${{ matrix.compiler }} \ | |
| CXX_FOR_BINDINGS=${{ matrix.compiler }} \ | |
| DEPS_BASE_DIR=${VCPKG_INSTALLED_DIR}/${VCPKG_TRIPLET} | |
| # install helper utility for Python version management | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 | |
| - name: Build Python shim libs | |
| run: | | |
| PYTHON_VERSIONS=$(cat scripts/mrbind-pybind11/python_versions.txt | xargs) | |
| GET_SYSCONFIG_VAR=${PWD}/scripts/wheel/get_sysconfig_var.py | |
| for PYTHON_VER in ${PYTHON_VERSIONS} ; do | |
| export PKG_CONFIG_PATH=$(uv run --python ${PYTHON_VER} ${GET_SYSCONFIG_VAR} LIBPC) | |
| make shims -f scripts/mrbind/generate.mk -B --trace \ | |
| FOR_WHEEL=1 \ | |
| CXX_FOR_ABI=${{ matrix.compiler }} \ | |
| CXX_FOR_BINDINGS=${{ matrix.compiler }} \ | |
| DEPS_BASE_DIR=${VCPKG_INSTALLED_DIR}/${VCPKG_TRIPLET} \ | |
| PYTHON_VERSIONS=${PYTHON_VER} | |
| done | |
| - name: Run Tests | |
| run: xvfb-run -a ./build/Release/bin/MeshViewer -hidden -noEventLoop -unloadPluginsAtEnd | |
| - name: Verify meshlib.mrmeshpy import | |
| timeout-minutes: 3 | |
| uses: ./.github/actions/verify-meshlib-python-import | |
| with: | |
| build-bin-dir: ./build/Release/bin | |
| - name: Unit Tests | |
| timeout-minutes: 10 | |
| run: build/Release/bin/MRTest | |
| - name: Python Tests | |
| run: | | |
| PYTHON_VERSIONS=$(cat scripts/mrbind-pybind11/python_versions.txt | xargs) | |
| REQUIREMENTS_FILE=${PWD}/requirements/python/requirements.txt | |
| GET_SYSCONFIG_VAR=${PWD}/scripts/wheel/get_sysconfig_var.py | |
| cd build/Release/bin | |
| for PYTHON_VER in ${PYTHON_VERSIONS} ; do | |
| PYTHON_LIB_DIR=$(uv run --python ${PYTHON_VER} ${GET_SYSCONFIG_VAR} LIBDIR) | |
| LD_LIBRARY_PATH=${PYTHON_LIB_DIR} \ | |
| uv run \ | |
| --python ${PYTHON_VER} \ | |
| --with-requirements ${REQUIREMENTS_FILE} \ | |
| --with pytest \ | |
| python3 -u ./../../../scripts/run_python_test_script.py -d '../test_python' | |
| done | |
| - name: Create and fix Wheel | |
| run: | | |
| python3.12 -m venv ./wheel_venv | |
| source ./wheel_venv/bin/activate | |
| python3.12 -m pip install patchelf | |
| python3.12 ./scripts/wheel/build_wheel.py --version ${{needs.setup.outputs.version_tag || '0'}} | |
| - name: Upload Python Stubs | |
| if: ${{ (github.event_name == 'release' || inputs.publish) && matrix.platform == 'aarch64' }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: PythonStubs | |
| path: ./scripts/wheel/meshlib/meshlib/*.pyi | |
| retention-days: 1 | |
| - name: Wait for C bindings | |
| if: ${{ inputs.mrbind_c || env.BUILD_C_SHARP == 'true' }} | |
| uses: ./.github/actions/wait-for-job | |
| with: | |
| job-name: generate-c-bindings | |
| - name: Download C bindings | |
| if: ${{ (github.event_name == 'release' || inputs.publish) && matrix.platform == 'aarch64' }} | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: CBindings | |
| path: MeshLib/CbindingsTmp | |
| - name: Prepare C bindings folders | |
| if: ${{ (github.event_name == 'release' || inputs.publish) && matrix.platform == 'aarch64' }} | |
| run: | | |
| rm -rf source/MeshLibC2 source/MeshLibC2Cuda | |
| mv MeshLib/CbindingsTmp/MeshLibC2 source | |
| mv MeshLib/CbindingsTmp/MeshLibC2Cuda source | |
| - name: Upload C bindings headers | |
| if: ${{ (github.event_name == 'release' || inputs.publish) && matrix.platform == 'aarch64' }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: CBindings | |
| path: | | |
| ./source/MeshLibC2/include | |
| ./source/MeshLibC2Cuda/include | |
| retention-days: 1 | |
| - name: Generate C# bindings # generate only sources | |
| if: ${{ (github.event_name == 'release' || inputs.publish) && matrix.platform == 'aarch64' }} | |
| run: make -f scripts/mrbind/generate.mk TARGET=csharp -B --trace generate | |
| - name: Upload C# bindings headers | |
| if: ${{ (github.event_name == 'release' || inputs.publish) && matrix.platform == 'aarch64' }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: CsharpBindings | |
| path: ./source/MRDotNet2/src | |
| retention-days: 1 | |
| - name: Upload to Test Artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ManyLinux-${{matrix.platform}} | |
| path: ./scripts/wheel/meshlib/wheelhouse/meshlib-*.whl | |
| retention-days: 1 | |
| update-documentation: | |
| # always() need to ignore general fail previous job, because this job depends on one matrix variant (aarch64 && py-version == 3.10), | |
| # and if this variant failed this job also will fail | |
| if: ${{ ( github.event_name == 'release' || inputs.publish ) && always() }} | |
| needs: | |
| - manylinux-pip-build | |
| uses: ./.github/workflows/update-docs.yml | |
| with: | |
| output_folder: MeshLib | |
| secrets: inherit | |
| windows-pip-build: | |
| needs: setup | |
| if: ${{ inputs.disable_windows != true }} | |
| timeout-minutes: 90 | |
| runs-on: [windows-2025] | |
| strategy: | |
| fail-fast: false | |
| permissions: | |
| id-token: write # This is required for requesting the JWT | |
| contents: read # This is required for actions/checkout | |
| env: | |
| VCPKG-VERSION: '2026.06.01' | |
| CUDA-VERSION: '12.0.1' | |
| CUDA-MAJOR: '12' | |
| CUDA-MINOR: '0' | |
| VCPKG_DEFAULT_TRIPLET: x64-windows-meshlib | |
| VCVARS_VER: '14.5' | |
| PLATFORM_TOOLSET: v145 | |
| CUDA_PLATFORM_TOOLSET: v143 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| ref: ${{needs.setup.outputs.version_tag}} | |
| - name: Locate Visual Studio | |
| uses: ./.github/actions/locate-visual-studio | |
| - name: Set up vcpkg | |
| uses: ./.github/actions/setup-vcpkg-windows | |
| with: | |
| vcpkg-version: ${{ env.VCPKG-VERSION }} | |
| vcpkg-triplet: ${{ env.VCPKG_DEFAULT_TRIPLET }} | |
| install-flags: '--write-s3' | |
| internal-build: 'true' | |
| - name: Install all Python versions | |
| run: scripts/mrbind-pybind11/install_all_python_versions_windows.bat | |
| - name: Install CUDA | |
| uses: ./.github/actions/install-cuda | |
| with: | |
| cuda-version: ${{ env.CUDA-VERSION }} | |
| cuda-major: ${{ env.CUDA-MAJOR }} | |
| cuda-minor: ${{ env.CUDA-MINOR }} | |
| - name: Set up CUDA | |
| uses: ./.github/actions/setup-cuda | |
| with: | |
| cuda-major: ${{ env.CUDA-MAJOR }} | |
| cuda-minor: ${{ env.CUDA-MINOR }} | |
| - name: Add msbuild to PATH | |
| uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0 | |
| - name: Build | |
| run: msbuild -m source\MeshLib.sln -p:Configuration=Release -p:VcpkgTriplet=${{ env.VCPKG_DEFAULT_TRIPLET }} -p:PlatformToolset=${{ env.PLATFORM_TOOLSET }} -p:MRCudaPlatformToolset=${{ env.CUDA_PLATFORM_TOOLSET }} -p:MR_PCH_USE_EXTRA_HEADERS=ON | |
| - name: Install MSYS2 for MRBind | |
| uses: ./.github/actions/install-msys2-mrbind | |
| - name: Build MRBind | |
| uses: ./.github/actions/build-mrbind | |
| with: | |
| cache-key-prefix: windows-clang22 | |
| build-script: scripts/mrbind/install_mrbind_windows_msys2.bat | |
| extra-cache-key: ${{ hashFiles('scripts/mrbind/msys2_package_hashes_clang22.txt') }} | |
| - name: Generate and build MRBind bindings | |
| shell: cmd | |
| env: | |
| MSYS2_DIR: C:\msys64 | |
| # `|| exit /b 1` — cmd.exe does not stop on a failed command, so guard each | |
| # one to fail the step on a generation error instead of swallowing it. | |
| run: | | |
| call "${{ env.VC_PATH }}\Common7\Tools\VsDevCmd.bat" -arch=amd64 -vcvars_ver=${{ env.VCVARS_VER }} || exit /b 1 | |
| call ./scripts/mrbind/generate_win.bat -B --trace FOR_WHEEL=1 || exit /b 1 | |
| - name: Run Test | |
| working-directory: source\x64\Release | |
| run: .\MeshViewer.exe -tryHidden -noEventLoop | |
| - name: Verify meshlib.mrmeshpy import | |
| timeout-minutes: 3 | |
| uses: ./.github/actions/verify-meshlib-python-import | |
| with: | |
| build-bin-dir: source\x64\Release | |
| - name: Unit Tests | |
| timeout-minutes: 10 | |
| run: source\x64\Release\MRTest.exe | |
| - name: Python Tests | |
| working-directory: source\x64\Release | |
| run: py -3 -u ..\..\..\scripts\run_python_test_script.py -multi-cmd | |
| - name: Create and fix Wheel | |
| run: | | |
| py -3.11 -m venv venv | |
| venv\Scripts\Activate | |
| python -m pip install --upgrade pip | |
| python .\scripts\wheel\build_wheel.py --plat-name=win-amd64 --version ${{needs.setup.outputs.version_tag || '0'}} | |
| - name: Upload to Test Artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: Windows | |
| path: wheelhouse\meshlib-*.whl | |
| retention-days: 1 | |
| macos-pip-build: | |
| needs: setup | |
| if: ${{ inputs.disable_macos != true }} | |
| timeout-minutes: 120 | |
| runs-on: ${{ matrix.instance }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| platform: ["x86", "arm64"] | |
| include: | |
| - platform: "x86" | |
| plat-name: macosx_12_0_x86_64 | |
| instance: macos-15-intel | |
| brewpath: /usr/local | |
| - platform: "arm64" | |
| plat-name: macosx_12_0_arm64 | |
| instance: macos-14 | |
| brewpath: /opt/homebrew | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| ref: ${{needs.setup.outputs.version_tag}} | |
| - name: Python setup | |
| env: | |
| ENABLE_SUDO: ${{ fromJSON('["1", "0"]')[matrix.platform == 'arm64'] }} | |
| run: | | |
| scripts/mrbind-pybind11/install_all_python_versions_macos.sh | |
| - name: Create virtualenv | |
| run: | | |
| # Remove from PATH anything with the word `anaconda` in it. | |
| # Even if Anaconda's Python works, it's probably a good idea to avoid it for consistency (because without this line only one specific Python version gets taken from Anaconda.) | |
| export PATH="$(echo "$PATH" | perl -pe 's/[^:]*anaconda[^:]*//g;s/::|^:|:$//g')" | |
| python3 -m venv .venv | |
| . .venv/bin/activate | |
| echo PATH=$PATH >> $GITHUB_ENV | |
| - name: Install thirdparty libs | |
| id: thirdparty | |
| uses: ./.github/actions/install-macos-thirdparty | |
| with: | |
| # `cache-instance` and `cache-compiler` must match the values used by | |
| # build-test-macos.yml on the same runner image (`AppleClang` here matches | |
| # build-test-macos.yml's x64-Release and arm64-Debug matrix entries), so | |
| # the thirdparty ./lib + ./include cache is shared across the two workflows. | |
| cache-instance: ${{ matrix.instance }} | |
| cache-compiler: AppleClang | |
| - name: Install MRBind deps | |
| env: | |
| HOMEBREW_NO_INSTALL_UPGRADE: '1' # don't upgrade an already-installed llvm/lld, no z3, no rebuild | |
| HOMEBREW_NO_INSTALL_CLEANUP: '1' # don't prune the known-good keg | |
| run: ./scripts/mrbind/install_deps_macos.sh | |
| - name: Build MRBind | |
| uses: ./.github/actions/build-mrbind | |
| with: | |
| # Keyed on the runner image (matrix.instance) so this cache is shared with | |
| # build-test-macos.yml when its matrix.instance matches. | |
| cache-key-prefix: ${{ matrix.instance }}-clang | |
| build-script: scripts/mrbind/install_mrbind_macos.sh | |
| extra-cache-key: ${{ hashFiles('scripts/mrbind/clang_version_macos.txt') }}-${{ steps.thirdparty.outputs.brew-hash }} | |
| - name: Build | |
| run: ./scripts/build_source.sh | |
| env: | |
| MESHLIB_BUILD_RELEASE: "ON" | |
| MESHLIB_BUILD_DEBUG: "OFF" | |
| CMAKE_CXX_COMPILER: /usr/bin/clang++ | |
| MR_CMAKE_OPTIONS: > | |
| -DMRVIEWER_NO_GTK=ON | |
| -DMR_PCH_USE_EXTRA_HEADERS=ON | |
| # not realy needed | |
| CMAKE_C_COMPILER: /usr/bin/clang | |
| - name: Generate and build MRBind bindings | |
| env: | |
| PATH: ${{matrix.brewpath}}/opt/make/libexec/gnubin:${{matrix.brewpath}}/opt/grep/libexec/gnubin:${{env.PATH}} | |
| # `MACOS_MIN_VER` picked arbitrarily to match what Apple Clang uses when building MeshLib. | |
| # Not setting this or setting a different value cases a warning when linking the bindings, and you can get the correct (?) value from those warnings. | |
| run: | | |
| make --version | |
| make -f scripts/mrbind/generate.mk -B --trace FOR_WHEEL=1 MACOS_MIN_VER=12.7 | |
| - name: Verify meshlib.mrmeshpy import | |
| timeout-minutes: 3 | |
| uses: ./.github/actions/verify-meshlib-python-import | |
| with: | |
| build-bin-dir: ./build/Release/bin | |
| - name: Unit Tests | |
| timeout-minutes: 10 | |
| run: build/Release/bin/MRTest | |
| - name: Python Tests | |
| working-directory: ./build/Release/bin | |
| run: python3 -u ./../../../scripts/run_python_test_script.py -multi-cmd -create-venv | |
| - name: Create and fix Wheel | |
| run: | | |
| python3 ./scripts/wheel/build_wheel.py --plat-name=${{matrix.plat-name}} --version ${{needs.setup.outputs.version_tag || '0'}} | |
| - name: Upload to Test Artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: Macos-${{matrix.platform}} | |
| path: meshlib-*.whl | |
| retention-days: 1 | |
| manylinux-pip-test: | |
| needs: [setup, manylinux-pip-build] | |
| if: ${{ needs.setup.outputs.test-matrix != '[]' }} | |
| timeout-minutes: 20 | |
| runs-on: ${{ matrix.runner }} | |
| container: | |
| image: ${{ matrix.container-prefix }}${{ matrix.os }} | |
| options: ${{ matrix.container-options }} | |
| strategy: | |
| fail-fast: false | |
| # `include` is the cartesian product (surviving platforms x | |
| # py-versions) computed in `setup.matrix`. | |
| matrix: | |
| include: ${{ fromJSON(needs.setup.outputs.test-matrix) }} | |
| env: | |
| PYTHON_CMD: python${{ matrix.py-version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: ${{needs.setup.outputs.version_tag}} | |
| - name: Rocky Linux system setup | |
| if: ${{ matrix.os == 'rockylinux:8' }} | |
| run: dnf -y install python38-pip | |
| - name: Debian/Ubuntu system setup | |
| if: ${{ matrix.os == 'debian:11-slim' || matrix.os == 'ubuntu:22.04' || matrix.os == 'ubuntu:25.10' }} | |
| run: apt -y update && apt -y install curl libssl-dev python3-pip python${{ matrix.py-version }}-venv | |
| - name: Fedora system setup | |
| if: ${{ matrix.os == 'fedora:37' || matrix.os == 'fedora:39' || matrix.os == 'fedora:42' }} | |
| run: dnf -y install python3-pip | |
| - name: Create virtualenv | |
| run: | | |
| ${{ env.PYTHON_CMD }} -m venv .venv | |
| . .venv/bin/activate | |
| echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV | |
| echo $PATH >> $GITHUB_PATH | |
| - name: Pip setup | |
| run: | | |
| ${{ env.PYTHON_CMD }} -m pip install --upgrade pip | |
| ${{ env.PYTHON_CMD }} -m pip uninstall -y meshlib | |
| ${{ env.PYTHON_CMD }} -m pip install --upgrade -r ./requirements/python/requirements.txt | |
| ${{ env.PYTHON_CMD }} -m pip install pytest | |
| - name: Download Meshlib wheel from Artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: ManyLinux-${{matrix.platform}} | |
| merge-multiple: true | |
| - name: Meshlib wheel install | |
| run: ${{ env.PYTHON_CMD }} -m pip install ${{ matrix.pip-options }} ./meshlib-*.whl | |
| - name: Run Python tests | |
| working-directory: test_python | |
| run: ${{ env.PYTHON_CMD }} -m pytest -s -v | |
| windows-pip-test: | |
| needs: [windows-pip-build] | |
| if: ${{ inputs.disable_windows != true }} | |
| timeout-minutes: 90 | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| runner: [windows-2022, windows-2025] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: ${{needs.setup.outputs.version_tag}} | |
| - name: Download Meshlib wheel from Artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: Windows | |
| merge-multiple: true | |
| - name: Python setup | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: | | |
| 3.8 | |
| 3.9 | |
| 3.10 | |
| 3.11 | |
| 3.12 | |
| 3.13 | |
| 3.14 | |
| # One step per Python ABI so the GitHub Actions UI shows per-version | |
| # status / timing / logs. Each step is a thin wrapper around the | |
| # shared `test_wheel_windows.ps1` script. | |
| - name: Test wheel against Python 3.8 | |
| shell: pwsh | |
| run: ./scripts/wheel/test_wheel_windows.ps1 -Version 3.8 | |
| - name: Test wheel against Python 3.9 | |
| shell: pwsh | |
| run: ./scripts/wheel/test_wheel_windows.ps1 -Version 3.9 | |
| - name: Test wheel against Python 3.10 | |
| shell: pwsh | |
| run: ./scripts/wheel/test_wheel_windows.ps1 -Version 3.10 | |
| - name: Test wheel against Python 3.11 | |
| shell: pwsh | |
| run: ./scripts/wheel/test_wheel_windows.ps1 -Version 3.11 | |
| - name: Test wheel against Python 3.12 | |
| shell: pwsh | |
| run: ./scripts/wheel/test_wheel_windows.ps1 -Version 3.12 | |
| - name: Test wheel against Python 3.13 | |
| shell: pwsh | |
| run: ./scripts/wheel/test_wheel_windows.ps1 -Version 3.13 | |
| - name: Test wheel against Python 3.14 | |
| shell: pwsh | |
| run: ./scripts/wheel/test_wheel_windows.ps1 -Version 3.14 | |
| macos-pip-test: | |
| needs: [macos-pip-build] | |
| if: ${{ inputs.disable_macos != true }} | |
| timeout-minutes: 120 | |
| runs-on: ${{ matrix.instance }} | |
| strategy: | |
| fail-fast: false | |
| # `runner-tier` exercises both the GitHub-hosted images that built the | |
| # wheels and our self-hosted fleet (different macOS versions / brew | |
| # prefixes), so we catch wheels that only run on a fresh hosted image. | |
| # Multiple GitHub-hosted images per platform widen macOS-version | |
| # coverage; collapsing the cross-product into `include` keeps each | |
| # (platform, instance) pair explicit instead of relying on exclude. | |
| matrix: | |
| include: | |
| - platform: "arm64" | |
| runner-tier: "self-hosted" | |
| instance: macos-13 | |
| - platform: "arm64" | |
| runner-tier: "github" | |
| instance: macos-14 | |
| - platform: "arm64" | |
| runner-tier: "github" | |
| instance: macos-15 | |
| - platform: "arm64" | |
| runner-tier: "github" | |
| instance: macos-26 | |
| - platform: "x86" | |
| runner-tier: "self-hosted" | |
| instance: macos-12-intel | |
| - platform: "x86" | |
| runner-tier: "github" | |
| instance: macos-15-intel | |
| - platform: "x86" | |
| runner-tier: "github" | |
| instance: macos-26-intel | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: ${{needs.setup.outputs.version_tag}} | |
| - name: Download Meshlib wheel from Artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: Macos-${{matrix.platform}} | |
| merge-multiple: true | |
| # One step per Python ABI so the GitHub Actions UI shows per-version | |
| # status / timing / logs. Each step is a thin wrapper around the | |
| # shared `test_wheel_macos.sh` script. `runner-tier` is forwarded so | |
| # the script can scope the macos-15-intel 3.11 brew-skip to the | |
| # GitHub-hosted runner only (self-hosted x86 does need the install). | |
| # python 3.8 disabled on macOS since 2024-10-14 | |
| - name: Test wheel against Python 3.9 | |
| run: scripts/wheel/test_wheel_macos.sh 3.9 ${{ matrix.platform }} ${{ matrix.runner-tier }} | |
| - name: Test wheel against Python 3.10 | |
| run: scripts/wheel/test_wheel_macos.sh 3.10 ${{ matrix.platform }} ${{ matrix.runner-tier }} | |
| - name: Test wheel against Python 3.11 | |
| run: scripts/wheel/test_wheel_macos.sh 3.11 ${{ matrix.platform }} ${{ matrix.runner-tier }} | |
| - name: Test wheel against Python 3.12 | |
| run: scripts/wheel/test_wheel_macos.sh 3.12 ${{ matrix.platform }} ${{ matrix.runner-tier }} | |
| - name: Test wheel against Python 3.13 | |
| run: scripts/wheel/test_wheel_macos.sh 3.13 ${{ matrix.platform }} ${{ matrix.runner-tier }} | |
| - name: Test wheel against Python 3.14 | |
| run: scripts/wheel/test_wheel_macos.sh 3.14 ${{ matrix.platform }} ${{ matrix.runner-tier }} | |
| upload-to-release: | |
| if: ${{ github.event_name == 'release' || inputs.publish }} | |
| needs: [manylinux-pip-test, windows-pip-test, macos-pip-test] | |
| outputs: | |
| uploaded: ${{ steps.check_upload.outputs.uploaded }} | |
| timeout-minutes: 30 | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download Wheels Artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: ManyLinux-* | |
| merge-multiple: true | |
| - name: Download Wheels Artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: Windows | |
| merge-multiple: true | |
| - name: Download Wheels Artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: Macos-* | |
| merge-multiple: true | |
| - name: Install twine | |
| run: python3 -m pip install --upgrade pip twine packaging | |
| - name: Upload to Production PyPi | |
| run: twine upload ./meshlib-*.whl -u __token__ -p ${{ secrets.PYPI_MESHINSPECTOR_TOKEN }} --skip-existing | |
| - name: Mark Success | |
| id: check_upload | |
| run: echo "uploaded=true" >> $GITHUB_OUTPUT | |
| post-release-test: | |
| if: ${{ github.event_name == 'release' || inputs.publish }} | |
| needs: upload-to-release | |
| uses: MeshInspector/MeshLib/.github/workflows/release-tests.yml@master | |
| delete-artifacts: | |
| timeout-minutes: 5 | |
| runs-on: ubuntu-latest | |
| needs: upload-to-release | |
| if: always() | |
| steps: | |
| - name: Delete all ManyLinux | |
| if: ${{ ( github.event_name == 'release' || inputs.publish ) && needs.upload-to-release.outputs.uploaded == 'true' }} | |
| uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0 | |
| with: | |
| name: ManyLinux-* | |
| failOnError: false | |
| - name: Delete Python Stubs | |
| if: ${{ needs.update-documentation.result == 'success' && ( github.event_name == 'release' || inputs.publish ) }} | |
| uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0 | |
| with: | |
| name: PythonStubs | |
| failOnError: false | |
| - name: Delete C bindings headers | |
| if: ${{ needs.update-documentation.result == 'success' && ( github.event_name == 'release' || inputs.publish ) }} | |
| uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0 | |
| with: | |
| name: CBindings | |
| failOnError: false | |
| - name: Delete Csharp bindings | |
| if: ${{ needs.update-documentation.result == 'success' && ( github.event_name == 'release' || inputs.publish ) }} | |
| uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0 | |
| with: | |
| name: CsharpBindings | |
| failOnError: false | |
| - name: Delete all Windows | |
| if: ${{ ( github.event_name == 'release' || inputs.publish ) && needs.upload-to-release.outputs.uploaded == 'true' }} | |
| uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0 | |
| with: | |
| name: Windows | |
| failOnError: false | |
| - name: Delete all Macos | |
| if: ${{ ( github.event_name == 'release' || inputs.publish ) && needs.upload-to-release.outputs.uploaded == 'true' }} | |
| uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0 | |
| with: | |
| name: Macos-* | |
| failOnError: false |