From eee3f30494a95bf677e326bcbce4df2f994c3695 Mon Sep 17 00:00:00 2001 From: glowinthedark <48893368+glowinthedark@users.noreply.github.com> Date: Sun, 31 May 2026 18:01:36 +0200 Subject: [PATCH 1/6] Add GitHub Actions workflow for macOS wheel builds using brew lzo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GitHub Actions workflow for macOS WHL generationg using brew lzo - this is an alternative to the existing macOS that builds using the source from the `lzo-2.10` brew version is installed with `brew install lzo` ```sh $ brew info lzo ==> lzo ✔: stable 2.10 (bottled) Real-time data compression library https://www.oberhumer.com/opensource/lzo/ Installed /opt/homebrew/Cellar/lzo/2.10 (32 files, 581.6KB) * Poured from bottle using the formulae.brew.sh API on 2026-05-31 at 16:40:48 From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/l/lzo.rb License: GPL-2.0-or-later ``` Please let me know if you would rather prefer to not use the brew provided `lzo` and use instead the included source as in the original workflow. I suppose that it should be doable, the key addition in this workflow apart from the cosmetic stuff is setting the env vars which python expects when building the wheels, so I suppose they would just have to point to the right paths under `./lzo-2.10` ```sh CFLAGS="-I${LZO_PREFIX}/include" \ LDFLAGS="-L${LZO_PREFIX}/lib -Wl,-rpath,${LZO_PREFIX}/lib" \ python -m build --wheel ``` --- .github/workflows/build-macos-brew.yml | 194 +++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 .github/workflows/build-macos-brew.yml diff --git a/.github/workflows/build-macos-brew.yml b/.github/workflows/build-macos-brew.yml new file mode 100644 index 0000000..448a0af --- /dev/null +++ b/.github/workflows/build-macos-brew.yml @@ -0,0 +1,194 @@ +name: "Build [+release] wheels for macOS (brew LZO)" + +on: + workflow_dispatch: + inputs: + tag: + description: > + Release tag — optional (e.g. v1.16). + Leave blank to build wheels only (no release will be created). + Existing tag → wheels are replaced on the existing release. + New tag → git tag is created from HEAD and a new release is published. + Format: vMAJOR.MINOR[.PATCH][-prerelease] + required: false + type: string + default: "" + +permissions: + contents: write # required to create tags, releases, and upload assets + +jobs: + # ─────────────────────────────────────────────────────────────────────────── + # 1. VALIDATE INPUT — runs once, cheaply, before the matrix fans out. + # Skipped entirely when no tag is provided (build-only mode). + # ─────────────────────────────────────────────────────────────────────────── + validate-tag: + runs-on: ubuntu-latest + # Skip this job when the tag input is blank — no release + if: inputs.tag != '' + steps: + - name: Check tag format + run: | + TAG="${{ inputs.tag }}" + if [[ ! "${TAG}" =~ ^v[0-9]+\.[0-9]+(\.[0-9]+)?(-[a-zA-Z0-9._-]+)?$ ]]; then + echo "::error::Tag '${TAG}' is not valid. Must match vMAJOR.MINOR[.PATCH][-prerelease]" + exit 1 + fi + echo "Tag '${TAG}' is valid." + + # ─────────────────────────────────────────────────────────────────────────── + # 2. BUILD — matrix across Python versions + # ─────────────────────────────────────────────────────────────────────────── + build: + # When no tag is provided, validate-tag is skipped (result = 'skipped'), + needs: validate-tag + if: always() && (needs.validate-tag.result == 'success' || needs.validate-tag.result == 'skipped') + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + python-version: +# - "3.8" +# - "3.9" +# - "3.10" +# - "3.11" +# - "3.12" + - "3.13" + - "3.14" + name: "Python ${{ matrix.python-version }}" + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + persist-credentials: false + + # === NOTE: using homebrew lzo instead === + # - name: Run cmake + # working-directory: ./lzo-2.10 + # run: | + # mkdir build + # cd build + # cmake -DCMAKE_INSTALL_PREFIX=.. .. + # - name: Build lzo static lib + # working-directory: ./lzo-2.10/build + # run: | + # make + # make install + + - name: Install lzo C library via Homebrew + run: | + brew install lzo + LZO_PREFIX=$(brew --prefix lzo) + echo "LZO_PREFIX=${LZO_PREFIX}" >> "$GITHUB_ENV" + echo "--- lzo install ---" + # ls "${LZO_PREFIX}/include/lzo/" + # ls "${LZO_PREFIX}/lib/" + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install build frontend + run: python -m pip install --upgrade pip build + + - name: Build wheel + # CFLAGS — clang needs to find lzo/lzo1x.h (not in /usr/include on arm64 macOS) + # LDFLAGS — linker needs to find liblzo2.dylib + # -rpath — embeds the runtime library path into the .so so Python + # finds liblzo2.dylib at import time without DYLD_LIBRARY_PATH + run: | + CFLAGS="-I${LZO_PREFIX}/include" \ + LDFLAGS="-L${LZO_PREFIX}/lib -Wl,-rpath,${LZO_PREFIX}/lib" \ + python -m build --wheel + echo "--- dist/ ---" + ls -lh dist/ + + - name: Smoke-test the wheel + run: | + pip install dist/*.whl + python -c " + import lzo + print('lzo version:', lzo.__version__) + data = b'hello world' * 100 + compressed = lzo.compress(data) + assert lzo.decompress(compressed) == data + print('compress/decompress round-trip OK') + " + + - name: Upload wheel artifact + uses: actions/upload-artifact@v4 + with: + # Each matrix leg must use a unique name — upload-artifact v4 + # does not allow parallel jobs to write to the same artifact. + name: wheel-py${{ matrix.python-version }} + path: dist/*.whl + if-no-files-found: error + + # ─────────────────────────────────────────────────────────────────────────── + # 3. PUBLISH — collect all wheels, tag if needed, upsert the release. + # Skipped entirely when no tag was provided. + # ─────────────────────────────────────────────────────────────────────────── + publish: + name: Publish GitHub release + needs: build + # Skip when tag is blank — build-only run, no release wanted. + if: always() && inputs.tag != '' && needs.build.result == 'success' + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + # Full history so we can push a new tag if it does not yet exist. + # (A shallow clone cannot push tags to a ref that isn't fetched.) + fetch-depth: 0 + persist-credentials: true # gh CLI uses the GITHUB_TOKEN credential + + - name: Download all wheel artifacts + uses: actions/download-artifact@v4 + with: + pattern: wheel-py* + merge-multiple: true + path: dist/ + + - name: List wheels to publish + run: ls -lh dist/ + + - name: Create git tag if it does not exist + run: | + if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q "${TAG}"; then + echo "Tag ${TAG} already exists — skipping tag creation." + else + echo "Tag ${TAG} does not exist — creating it from HEAD." + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "${TAG}" -m "Release ${TAG}" + git push origin "${TAG}" + echo "Tag ${TAG} pushed." + fi + + - name: Create or update GitHub release + # gh release create → used when no release exists yet for this tag. + # • Automatically uses the tag we just pushed (or the existing one). + # • --generate-notes asks GitHub to auto-fill the release notes from + # commits since the previous release. + # + # gh release upload --clobber → used when a release already exists. + # • --clobber deletes any asset with the same filename before + # re-uploading, giving us idempotent replace semantics. + # • WARNING: gh documents that if the upload fails after --clobber, + # the original asset is gone. Acceptable here because we always + # have the artifact zip as a fallback. + run: | + if gh release view "${TAG}" > /dev/null 2>&1; then + echo "Release for ${TAG} already exists — replacing assets." + gh release upload "${TAG}" dist/*.whl --clobber + else + echo "No release for ${TAG} yet — creating release and uploading assets." + gh release create "${TAG}" dist/*.whl \ + --title "${TAG}" \ + --generate-notes + fi From 62605b2ead47b79033f67c181108039053af93ac Mon Sep 17 00:00:00 2001 From: glowinthedark <48893368+glowinthedark@users.noreply.github.com> Date: Mon, 1 Jun 2026 11:57:49 +0200 Subject: [PATCH 2/6] fix cmake build failure - fix cmake build failure because of deprecated version --- .github/workflows/build-macos.yml | 137 +++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index a454e37..95c130d 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -1,52 +1,163 @@ -name: Build wheels for macOS +name: "Build wheels for macOS (+optional release)" on: workflow_dispatch: + inputs: + tag: + description: > + Release tag — optional (e.g. v1.16). + Leave blank to build wheels only (no release will be created). + Existing tag → wheels are replaced on the existing release. + New tag → git tag is created from HEAD and a new release is published. + Format: vMAJOR.MINOR[.PATCH][-prerelease] + required: false + type: string + default: "" + +permissions: + contents: write # required to create tags, releases, and upload assets jobs: build-macos: - runs-on: macos-latest + runs-on: ${{ matrix.os }} strategy: matrix: python-version: - - "3.8" + # - "3.8" # - "3.9" -# - "3.10" -# - "3.11" -# - "3.12" + - "3.10" + - "3.11" + - "3.12" - "3.13" + - "3.14" + os: + - macos-14 + - macos-15 ## currently same as macos-latest (2026) name: ${{ matrix.python-version }} steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false + + - name: Patch lzo CMakeLists.txt + working-directory: ./lzo-2.10 + run: | + sed -i '' 's/cmake_minimum_required(VERSION [0-9.]* *FATAL_ERROR)/cmake_minimum_required(VERSION 3.5)/' CMakeLists.txt + grep cmake_minimum_required CMakeLists.txt + - name: Run cmake working-directory: ./lzo-2.10 run: | mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=.. .. + - name: Build lzo static lib working-directory: ./lzo-2.10/build run: | make make install - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + - name: Build wheel env: LZO_DIR: ./lzo-2.10 run: | - python -m pip install -U pip wheel build - python -m build + CFLAGS="-I./lzo-2.10/include" \ + LDFLAGS="-L./lzo-2.10/lib -Wl,-rpath,./lzo-2.10/lib" \ + python -m pip install --upgrade pip build + python -m build --wheel + echo "--- dist/ ---" ls -l dist + + - name: Smoke-test the wheel + run: | + pip install dist/*.whl + python -c " + import lzo + print('lzo version:', lzo.__version__) + data = b'hello world' * 100 + compressed = lzo.compress(data) + assert lzo.decompress(compressed) == data + print('compress/decompress round-trip OK') + " + - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: wheels - path: dist + name: wheel-py-${{ matrix.os }}-${{ matrix.python-version }} + path: dist/*.whl overwrite: true if-no-files-found: error + + # ─────────────────────────────────────────────────────────────────────────── + # 3. PUBLISH — collect all wheels, tag if needed, upsert the release. + # Skipped entirely when no tag was provided. + # ─────────────────────────────────────────────────────────────────────────── + publish: + name: Publish GitHub release + needs: build-macos + # Skip when tag is blank — build-only run, no release wanted. + if: inputs.tag != '' + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout repo + uses: actions/checkout@v6 + with: + # Full history so we can push a new tag if it does not yet exist. + # (A shallow clone cannot push tags to a ref that isn't fetched.) + fetch-depth: 0 + persist-credentials: true # gh CLI uses the GITHUB_TOKEN credential + + - name: Download all wheel artifacts + uses: actions/download-artifact@v8 + with: + pattern: wheel-py* + merge-multiple: true + path: dist/ + + - name: List wheels to publish + run: ls -lh dist/ + + - name: Create git tag if it does not exist + run: | + if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q "${TAG}"; then + echo "Tag ${TAG} already exists — skipping tag creation." + else + echo "Tag ${TAG} does not exist — creating it from HEAD." + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "${TAG}" -m "Release ${TAG}" + git push origin "${TAG}" + echo "Tag ${TAG} pushed." + fi + + - name: Create or update GitHub release + # gh release create → used when no release exists yet for this tag. + # • Automatically uses the tag we just pushed (or the existing one). + # • --generate-notes asks GitHub to auto-fill the release notes from + # commits since the previous release. + # + # gh release upload --clobber → used when a release already exists. + # • --clobber deletes any asset with the same filename before + # re-uploading, giving us idempotent replace semantics. + # • WARNING: gh documents that if the upload fails after --clobber, + # the original asset is gone. Acceptable here because we always + # have the artifact zip as a fallback. + run: | + if gh release view "${TAG}" > /dev/null 2>&1; then + echo "Release for ${TAG} already exists — replacing assets." + gh release upload "${TAG}" dist/*.whl --clobber + else + echo "No release for ${TAG} yet — creating release and uploading assets." + gh release create "${TAG}" dist/*.whl \ + --title "${TAG}" \ + --generate-notes + fi From 1dcc7e620006e5f6bd380a709349a6db23818207 Mon Sep 17 00:00:00 2001 From: glowinthedark <48893368+glowinthedark@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:29:19 +0200 Subject: [PATCH 3/6] Enhance macOS build workflow with tag validation Refactor GitHub Actions workflow for macOS builds to include input validation for tags, improve build steps, and ensure proper artifact handling. --- .github/workflows/build-macos.yml | 120 ++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 41 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 95c130d..92d9286 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -13,17 +13,41 @@ on: required: false type: string default: "" - + permissions: - contents: write # required to create tags, releases, and upload assets + contents: write # required to create tags, releases jobs: - build-macos: + # ─────────────────────────────────────────────────────────────────────────── + # VALIDATE INPUT + # ─────────────────────────────────────────────────────────────────────────── + validate-tag: + runs-on: ubuntu-latest + # Skip this job when the tag input is blank — no release + if: inputs.tag != '' + steps: + - name: Check tag format + run: | + TAG="${{ inputs.tag }}" + if [[ ! "${TAG}" =~ ^v[0-9]+\.[0-9]+(\.[0-9]+)?(-[a-zA-Z0-9._-]+)?$ ]]; then + echo "::error::Tag '${TAG}' is not valid. Must match vMAJOR.MINOR[.PATCH][-prerelease]" + exit 1 + fi + echo "Tag '${TAG}' is valid." + + # ─────────────────────────────────────────────────────────────────────────── + # BUILD + # ─────────────────────────────────────────────────────────────────────────── + build: + # When no tag is provided, validate-tag is skipped (result = 'skipped'), + needs: validate-tag + if: always() && (needs.validate-tag.result == 'success' || needs.validate-tag.result == 'skipped') runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: python-version: - # - "3.8" +# - "3.8" # - "3.9" - "3.10" - "3.11" @@ -32,47 +56,63 @@ jobs: - "3.14" os: - macos-14 - - macos-15 ## currently same as macos-latest (2026) - name: ${{ matrix.python-version }} + - macos-15 # currently (2026) same as macos-latest + name: "Python ${{ matrix.python-version }}" steps: - name: Checkout repo uses: actions/checkout@v6 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 with: - persist-credentials: false + python-version: ${{ matrix.python-version }} - - name: Patch lzo CMakeLists.txt - working-directory: ./lzo-2.10 + - name: Install build frontend + run: python -m pip install --upgrade pip build + + # try brew LZO build first + - name: Build wheel (brew LZO) + id: build_brew + # CFLAGS — clang needs to find lzo/lzo1x.h (not in /usr/include on arm64 macOS) + # LDFLAGS — linker needs to find liblzo2.dylib + # -rpath — embeds the runtime library path into the .so so Python + # finds liblzo2.dylib at import time without DYLD_LIBRARY_PATH run: | - sed -i '' 's/cmake_minimum_required(VERSION [0-9.]* *FATAL_ERROR)/cmake_minimum_required(VERSION 3.5)/' CMakeLists.txt - grep cmake_minimum_required CMakeLists.txt + LZO_PREFIX=$(brew --prefix lzo) + CFLAGS="-I${LZO_PREFIX}/include" \ + LDFLAGS="-L${LZO_PREFIX}/lib -Wl,-rpath,${LZO_PREFIX}/lib" \ + python -m build --wheel + continue-on-error: true - - name: Run cmake + # Fallback: build with local LZO sources + - name: Build LZO with cmake + id: build_lzo + if: steps.build_brew.outcome == 'failure' working-directory: ./lzo-2.10 run: | mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=.. .. - - - name: Build lzo static lib - working-directory: ./lzo-2.10/build - run: | make make install - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} + continue-on-error: true - - name: Build wheel - env: - LZO_DIR: ./lzo-2.10 + - name: Build wheel with local LZO + id: build_local + if: steps.build_brew.outcome == 'failure' && steps.build_lzo.outcome == 'success' run: | CFLAGS="-I./lzo-2.10/include" \ LDFLAGS="-L./lzo-2.10/lib -Wl,-rpath,./lzo-2.10/lib" \ - python -m pip install --upgrade pip build python -m build --wheel - echo "--- dist/ ---" - ls -l dist + + # Fail the job if nothing worked + - name: Abort on fail + if: | + steps.build_brew.outcome == 'failure' && + (steps.build_lzo.outcome == 'failure' || steps.build_local.outcome == 'failure' || steps.build_local.outcome == 'skipped') + run: | + echo "Both brew and local LZO builds failed." + exit 1 - name: Smoke-test the wheel run: | @@ -80,29 +120,28 @@ jobs: python -c " import lzo print('lzo version:', lzo.__version__) - data = b'hello world' * 100 + data = b'hello world' * 42 compressed = lzo.compress(data) assert lzo.decompress(compressed) == data print('compress/decompress round-trip OK') " - - - name: Upload artifact - uses: actions/upload-artifact@v7 + + - name: Upload wheel artifact + uses: actions/upload-artifact@v6 with: name: wheel-py-${{ matrix.os }}-${{ matrix.python-version }} path: dist/*.whl - overwrite: true if-no-files-found: error - + # ─────────────────────────────────────────────────────────────────────────── - # 3. PUBLISH — collect all wheels, tag if needed, upsert the release. - # Skipped entirely when no tag was provided. + # PUBLISH — collect wheels, tag if needed, make the release. + # Skip if no tag # ─────────────────────────────────────────────────────────────────────────── publish: name: Publish GitHub release - needs: build-macos + needs: build # Skip when tag is blank — build-only run, no release wanted. - if: inputs.tag != '' + if: always() && inputs.tag != '' && needs.build.result == 'success' runs-on: ubuntu-latest env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -111,13 +150,12 @@ jobs: - name: Checkout repo uses: actions/checkout@v6 with: - # Full history so we can push a new tag if it does not yet exist. - # (A shallow clone cannot push tags to a ref that isn't fetched.) + # must fetch full history so a new tag can be created if it does not exist fetch-depth: 0 - persist-credentials: true # gh CLI uses the GITHUB_TOKEN credential + persist-credentials: true - name: Download all wheel artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v7 with: pattern: wheel-py* merge-multiple: true @@ -141,7 +179,7 @@ jobs: - name: Create or update GitHub release # gh release create → used when no release exists yet for this tag. - # • Automatically uses the tag we just pushed (or the existing one). + # • Automatically uses the tag that was pushed (or the existing one). # • --generate-notes asks GitHub to auto-fill the release notes from # commits since the previous release. # From bfd1eef942f5b9256ba1f2608839ebe6befa0010 Mon Sep 17 00:00:00 2001 From: glowinthedark <48893368+glowinthedark@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:31:03 +0200 Subject: [PATCH 4/6] Update build-macos.yml --- .github/workflows/build-macos.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 92d9286..720e341 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -1,4 +1,5 @@ name: "Build wheels for macOS (+optional release)" +# Hybrid approach: try to build with brew lzo, fall back to included sources on: workflow_dispatch: From 467da6b14c43e55f3a125fd429be6e3468e9e7ce Mon Sep 17 00:00:00 2001 From: glowinthedark <48893368+glowinthedark@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:34:02 +0200 Subject: [PATCH 5/6] Delete .github/workflows/build-macos-brew.yml remove file as logic was moved to `build-macos.yml` --- .github/workflows/build-macos-brew.yml | 194 ------------------------- 1 file changed, 194 deletions(-) delete mode 100644 .github/workflows/build-macos-brew.yml diff --git a/.github/workflows/build-macos-brew.yml b/.github/workflows/build-macos-brew.yml deleted file mode 100644 index 448a0af..0000000 --- a/.github/workflows/build-macos-brew.yml +++ /dev/null @@ -1,194 +0,0 @@ -name: "Build [+release] wheels for macOS (brew LZO)" - -on: - workflow_dispatch: - inputs: - tag: - description: > - Release tag — optional (e.g. v1.16). - Leave blank to build wheels only (no release will be created). - Existing tag → wheels are replaced on the existing release. - New tag → git tag is created from HEAD and a new release is published. - Format: vMAJOR.MINOR[.PATCH][-prerelease] - required: false - type: string - default: "" - -permissions: - contents: write # required to create tags, releases, and upload assets - -jobs: - # ─────────────────────────────────────────────────────────────────────────── - # 1. VALIDATE INPUT — runs once, cheaply, before the matrix fans out. - # Skipped entirely when no tag is provided (build-only mode). - # ─────────────────────────────────────────────────────────────────────────── - validate-tag: - runs-on: ubuntu-latest - # Skip this job when the tag input is blank — no release - if: inputs.tag != '' - steps: - - name: Check tag format - run: | - TAG="${{ inputs.tag }}" - if [[ ! "${TAG}" =~ ^v[0-9]+\.[0-9]+(\.[0-9]+)?(-[a-zA-Z0-9._-]+)?$ ]]; then - echo "::error::Tag '${TAG}' is not valid. Must match vMAJOR.MINOR[.PATCH][-prerelease]" - exit 1 - fi - echo "Tag '${TAG}' is valid." - - # ─────────────────────────────────────────────────────────────────────────── - # 2. BUILD — matrix across Python versions - # ─────────────────────────────────────────────────────────────────────────── - build: - # When no tag is provided, validate-tag is skipped (result = 'skipped'), - needs: validate-tag - if: always() && (needs.validate-tag.result == 'success' || needs.validate-tag.result == 'skipped') - runs-on: macos-latest - strategy: - fail-fast: false - matrix: - python-version: -# - "3.8" -# - "3.9" -# - "3.10" -# - "3.11" -# - "3.12" - - "3.13" - - "3.14" - name: "Python ${{ matrix.python-version }}" - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - persist-credentials: false - - # === NOTE: using homebrew lzo instead === - # - name: Run cmake - # working-directory: ./lzo-2.10 - # run: | - # mkdir build - # cd build - # cmake -DCMAKE_INSTALL_PREFIX=.. .. - # - name: Build lzo static lib - # working-directory: ./lzo-2.10/build - # run: | - # make - # make install - - - name: Install lzo C library via Homebrew - run: | - brew install lzo - LZO_PREFIX=$(brew --prefix lzo) - echo "LZO_PREFIX=${LZO_PREFIX}" >> "$GITHUB_ENV" - echo "--- lzo install ---" - # ls "${LZO_PREFIX}/include/lzo/" - # ls "${LZO_PREFIX}/lib/" - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Install build frontend - run: python -m pip install --upgrade pip build - - - name: Build wheel - # CFLAGS — clang needs to find lzo/lzo1x.h (not in /usr/include on arm64 macOS) - # LDFLAGS — linker needs to find liblzo2.dylib - # -rpath — embeds the runtime library path into the .so so Python - # finds liblzo2.dylib at import time without DYLD_LIBRARY_PATH - run: | - CFLAGS="-I${LZO_PREFIX}/include" \ - LDFLAGS="-L${LZO_PREFIX}/lib -Wl,-rpath,${LZO_PREFIX}/lib" \ - python -m build --wheel - echo "--- dist/ ---" - ls -lh dist/ - - - name: Smoke-test the wheel - run: | - pip install dist/*.whl - python -c " - import lzo - print('lzo version:', lzo.__version__) - data = b'hello world' * 100 - compressed = lzo.compress(data) - assert lzo.decompress(compressed) == data - print('compress/decompress round-trip OK') - " - - - name: Upload wheel artifact - uses: actions/upload-artifact@v4 - with: - # Each matrix leg must use a unique name — upload-artifact v4 - # does not allow parallel jobs to write to the same artifact. - name: wheel-py${{ matrix.python-version }} - path: dist/*.whl - if-no-files-found: error - - # ─────────────────────────────────────────────────────────────────────────── - # 3. PUBLISH — collect all wheels, tag if needed, upsert the release. - # Skipped entirely when no tag was provided. - # ─────────────────────────────────────────────────────────────────────────── - publish: - name: Publish GitHub release - needs: build - # Skip when tag is blank — build-only run, no release wanted. - if: always() && inputs.tag != '' && needs.build.result == 'success' - runs-on: ubuntu-latest - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ inputs.tag }} - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - # Full history so we can push a new tag if it does not yet exist. - # (A shallow clone cannot push tags to a ref that isn't fetched.) - fetch-depth: 0 - persist-credentials: true # gh CLI uses the GITHUB_TOKEN credential - - - name: Download all wheel artifacts - uses: actions/download-artifact@v4 - with: - pattern: wheel-py* - merge-multiple: true - path: dist/ - - - name: List wheels to publish - run: ls -lh dist/ - - - name: Create git tag if it does not exist - run: | - if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q "${TAG}"; then - echo "Tag ${TAG} already exists — skipping tag creation." - else - echo "Tag ${TAG} does not exist — creating it from HEAD." - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git tag -a "${TAG}" -m "Release ${TAG}" - git push origin "${TAG}" - echo "Tag ${TAG} pushed." - fi - - - name: Create or update GitHub release - # gh release create → used when no release exists yet for this tag. - # • Automatically uses the tag we just pushed (or the existing one). - # • --generate-notes asks GitHub to auto-fill the release notes from - # commits since the previous release. - # - # gh release upload --clobber → used when a release already exists. - # • --clobber deletes any asset with the same filename before - # re-uploading, giving us idempotent replace semantics. - # • WARNING: gh documents that if the upload fails after --clobber, - # the original asset is gone. Acceptable here because we always - # have the artifact zip as a fallback. - run: | - if gh release view "${TAG}" > /dev/null 2>&1; then - echo "Release for ${TAG} already exists — replacing assets." - gh release upload "${TAG}" dist/*.whl --clobber - else - echo "No release for ${TAG} yet — creating release and uploading assets." - gh release create "${TAG}" dist/*.whl \ - --title "${TAG}" \ - --generate-notes - fi From af03330c267bc904368d5a4f25b5ff62caeb009a Mon Sep 17 00:00:00 2001 From: glowinthedark <48893368+glowinthedark@users.noreply.github.com> Date: Mon, 1 Jun 2026 23:05:19 +0200 Subject: [PATCH 6/6] Update build-macos.yml --- .github/workflows/build-macos.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 720e341..f1373ef 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -91,6 +91,8 @@ jobs: if: steps.build_brew.outcome == 'failure' working-directory: ./lzo-2.10 run: | + sed -i '' 's/cmake_minimum_required(VERSION [0-9.]* *FATAL_ERROR)/cmake_minimum_required(VERSION 3.5)/' CMakeLists.txt + grep cmake_minimum_required CMakeLists.txt mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=.. ..