diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 200fb9d3..cd14a157 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -25,26 +25,37 @@ jobs: build_wheels: runs-on: ${{ matrix.os }} + # windows-11-arm is newly added; its native toolchain may not build every + # dependency yet (embree / predicates use x86 SIMD), so don't let that leg + # block a release if it fails. + continue-on-error: ${{ matrix.os == 'windows-11-arm' }} strategy: fail-fast: false + # One runner per *native* target architecture; cibuildwheel builds the + # runner's native arch by default. Do NOT reintroduce a cross `arch` + # dimension: previously `arch: arm64` on the x86 ubuntu-24.04 / windows-latest + # runners silently built x86_64 / amd64 wheels (only CIBW_ARCHS_MACOS was + # wired up), producing duplicate wheels that collided during the release + # artifact download and left win_arm64 uncovered. matrix: - os: [ubuntu-24.04, ubuntu-24.04-arm, macos-latest, macos-15-intel, windows-latest] # Use specific versions for clarity - arch: [x86_64, arm64] - pybuilds: [cp38, cp39, cp310, cp311, cp312] # Define pybuilds at the top level + os: [ubuntu-24.04, ubuntu-24.04-arm, macos-latest, macos-15-intel, windows-latest, windows-11-arm] + pybuilds: [cp38, cp39, cp310, cp311, cp312] exclude: - - os: ubuntu-24.04-arm # No need to specify arch, it's already implicit - arch: x86_64 # Exclude x86_64 on ARM + # No macOS CPython 3.8 wheels are shipped. - os: macos-latest - arch: x86_64 # Exclude x86_64 explicitly - - os: macos-latest # Exclude cp38 pybuilds: cp38 - os: macos-15-intel - arch: arm64 # Exclude arm64 on macOS 13 - - os: macos-15-intel pybuilds: cp38 + # Windows on ARM64 has official CPython only for 3.11+. + - os: windows-11-arm + pybuilds: cp38 + - os: windows-11-arm + pybuilds: cp39 + - os: windows-11-arm + pybuilds: cp310 name: > - ${{ matrix.pybuilds }} ${{ matrix.os }} ${{ matrix.arch }} + ${{ matrix.pybuilds }} ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -59,15 +70,21 @@ jobs: CIBW_ENVIRONMENT_LINUX: "CC=clang CXX=clang++" CIBW_MANYLINUX_X86_64_IMAGE: "manylinux_2_28" CIBW_MANYLINUX_AARCH64_IMAGE: "manylinux_2_28" - CIBW_BUILD: "${{ matrix.pybuilds }}-*" # Use matrix.pybuilds and matrix.arch - CIBW_ARCHS_MACOS: ${{ matrix.arch }} + CIBW_BUILD: "${{ matrix.pybuilds }}-*" + # No CIBW_ARCHS_* override: each runner builds its native architecture. CIBW_SKIP: "cp*-manylinux_i686 cp*-musllinux* cp*-win32" + # embree only enables its NEON (sse2neon) path when its build detects an + # ARM target; on Windows/MSVC-ARM64 that detection falls back to SSE2 and + # fails to compile (x86 immintrin.h). Drop embree on win_arm64 (the + # igl.embree submodule is simply absent from that wheel). + CIBW_ENVIRONMENT_WINDOWS: ${{ matrix.os == 'windows-11-arm' && 'CMAKE_ARGS=-DLIBIGL_EMBREE=OFF' || '' }} - name: Upload Artifact uses: actions/upload-artifact@v4 continue-on-error: true # Important: Continue if upload fails with: - # Include pybuilds in the artifact name - name: wheels-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.pybuilds }} + # Unique per (os, python); one native arch per runner so wheel + # filenames never collide when the release job merges artifacts. + name: wheels-${{ matrix.os }}-${{ matrix.pybuilds }} path: ./wheelhouse/*.whl if-no-files-found: error # Fail if no wheels are found compression-level: 6 diff --git a/pyproject.toml b/pyproject.toml index b0cc59c2..efbeeeba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ build-backend = "scikit_build_core.build" [project] name = "libigl" -version = "2.6.3" +version = "2.6.4.dev0" description = "libigl: A simple C++ geometry processing library" readme = "README.md" requires-python = ">=3.8" diff --git a/tests/test_all.py b/tests/test_all.py index ed893aa5..868622de 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -10,11 +10,18 @@ import igl.copyleft import igl.copyleft.tetgen import igl.copyleft.cgal -import igl.embree import igl.spectra import igl.predicates import igl.cycodebase +# embree is not built on every platform (e.g. Windows/ARM64, where upstream +# embree has no MSVC build), so treat it as optional. +try: + import igl.embree + HAS_EMBREE = True +except ImportError: + HAS_EMBREE = False + @pytest.fixture def icosahedron(): V,F = igl.icosahedron() @@ -569,6 +576,7 @@ def test_cgal(): R = igl.copyleft.cgal.oriented_bounding_box(VC) +@pytest.mark.skipif(not HAS_EMBREE, reason="igl.embree not built (e.g. Windows/ARM64)") def test_embree(): # octahedron V = np.array([[1,0,0],[0,1,0],[0,0,1],[-1,0,0],[0,-1,0],[0,0,-1]],dtype=np.float64) @@ -1392,6 +1400,7 @@ def test_new_tetgen_algorithms(): assert FF_sk.shape[1] == 3 +@pytest.mark.skipif(not HAS_EMBREE, reason="igl.embree not built (e.g. Windows/ARM64)") def test_new_embree_algorithms(): V_oct = np.array([[1,0,0],[0,1,0],[0,0,1],[-1,0,0],[0,-1,0],[0,0,-1]], dtype=np.float64) F_oct = np.array([[0,1,2],[0,2,4],[0,4,5],[0,5,1],[1,3,2],[1,5,3],[2,3,4],[3,5,4]], dtype=np.int64)