From 8606588dd50fcb8066d3447fa05b317758ddbcfa Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:00:29 +0800 Subject: [PATCH 01/19] fix(ci): produce static musl binary via zig cross-compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace native Linux build with zig 0.13.0 cross-compilation targeting x86_64-unknown-linux-musl. Zig musl-cc/musl-cxx wrappers compile C/C++ (cxxbridge), Rust_CARGO_TARGET passes --target to cargo via corrosion. Output binary is statically linked and runs on Alpine/temenos. 🍷 Generated with Lenos Assisted-by: MiniMax-M2.7-highspeed via Lenos --- .github/workflows/release.yml | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5304b0420..9d0bb146a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,14 +45,36 @@ jobs: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --target task_executable - - name: Build task binary (Linux — native) + - name: Set up Zig if: runner.os == 'Linux' + uses: mlugg/setup-zig@v1 + with: + version: "0.13.0" + + - name: Set up Rust toolchain + if: runner.os == 'Linux' + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: x86_64-unknown-linux-musl + + - name: Build task binary (Linux — musl via zig) + if: runner.os == 'Linux' + env: + CC: zig cc -target x86_64-linux-musl + CXX: zig c++ -target x86_64-linux-musl + AR: zig ar + CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: zig c++ -target x86_64-linux-musl run: | set -e sudo apt-get update -qq sudo apt-get install -y -qq libclang-dev export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) - cmake -S . -B build -DCMAKE_BUILD_TYPE=Release + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_SYSTEM_PROCESSOR=x86_64 \ + -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) - name: Package binary + completions From c42e83ff17b77a7cf46f2a306292fce004a4e33a Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:05:51 +0800 Subject: [PATCH 02/19] fix(ci): remove CMAKE_SYSTEM_NAME=Linux to allow find_library Without -DCMAKE_SYSTEM_NAME=Linux, cmake stays in native mode and find_library(uuid) finds host glibc libraries. zig cc -target x86_64-linux-musl still produces musl-targeted object files and binary. Also add uuid-dev to apt install. --- .github/workflows/release.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9d0bb146a..8df5349b1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -68,12 +68,11 @@ jobs: run: | set -e sudo apt-get update -qq - sudo apt-get install -y -qq libclang-dev + sudo apt-get install -y -qq uuid-dev libclang-dev export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) + export SYSROOT=/usr/x86_64-linux-gnu cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_SYSTEM_NAME=Linux \ - -DCMAKE_SYSTEM_PROCESSOR=x86_64 \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) From 2074e4f01d225011f46f5220fe62fc7225b4aaa4 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:09:44 +0800 Subject: [PATCH 03/19] fix(ci): pass explicit UUID_LIBRARY and UUID_INCLUDE_DIR to cmake find_library(uuid) fails when using zig as compiler because cmake doesn't detect the x86_64-linux-gnu library path. Pass explicit paths as cmake variables to bypass the search. --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8df5349b1..9e20f8d7e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,9 +70,11 @@ jobs: sudo apt-get update -qq sudo apt-get install -y -qq uuid-dev libclang-dev export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) - export SYSROOT=/usr/x86_64-linux-gnu cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_FIND_ROOT_PATH=/usr/lib/x86_64-linux-gnu \ + -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ + -DUUID_INCLUDE_DIR=/usr/include \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) From 99a6b93eec70fea29975c63bc36ee469e9b68362 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:13:06 +0800 Subject: [PATCH 04/19] fix(ci): use CMAKE_SYSROOT=zig_musl_sysroot for proper cross-compilation Cross-compilation requires CMAKE_SYSROOT to point to zig's musl sysroot so that C/C++ headers and libraries come from musl, not glibc. CMAKE_FIND_ROOT_PATH_MODE_LIBRARY=NEVER ensures find_library(uuid) still finds host glibc libraries for host-only tools (bindgen). Also fix LIBCLANG_PATH to fall back to /usr/lib/llvm-16/lib for newer Ubuntu runners where libclang-14-dev doesn't install. --- .github/workflows/release.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9e20f8d7e..b667f9e6b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,11 +70,13 @@ jobs: sudo apt-get update -qq sudo apt-get install -y -qq uuid-dev libclang-dev export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) + ZIG_SYSROOT=$(zig c++ -target x86_64-linux-musl -print-sysroot 2>/dev/null || echo /opt/hostedtoolcache/zig/0.13.0/x64) cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_FIND_ROOT_PATH=/usr/lib/x86_64-linux-gnu \ - -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ - -DUUID_INCLUDE_DIR=/usr/include \ + -DCMAKE_SYSROOT="$ZIG_SYSROOT" \ + -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=NEVER \ + -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ + -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) From 381d3fecd0be2b71edbfc8266f41b1b5658a50ca Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:21:00 +0800 Subject: [PATCH 05/19] fix(ci): implement zig musl cross-compilation per plan steps A + B Step A: Download zig 0.13.0 (SHA256 verified), install cmake/clang/libclang-dev, rustup target add x86_64-unknown-linux-musl, create musl-cc/musl-cxx wrapper scripts that call zig cc/c++ with -target x86_64-linux-musl. Step B: Configure cmake with musl-cc/musl-cxx as compilers and Rust_CARGO_TARGET=x86_64-unknown-linux-musl. LIBCLANG_PATH points to glibc libclang (used for bindgen at build time). --- .github/workflows/release.yml | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b667f9e6b..7666aec53 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,38 +45,40 @@ jobs: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --target task_executable - - name: Set up Zig + - name: Install dependencies (Linux) if: runner.os == 'Linux' - uses: mlugg/setup-zig@v1 - with: - version: "0.13.0" + run: | + sudo apt-get update -q + sudo apt-get install -y cmake clang libclang-dev - - name: Set up Rust toolchain + - name: Set up Rust musl target if: runner.os == 'Linux' - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - targets: x86_64-unknown-linux-musl + run: rustup target add x86_64-unknown-linux-musl - - name: Build task binary (Linux — musl via zig) + - name: Set up Zig + if: runner.os == 'Linux' + run: | + ZIG_VERSION=0.13.0 + ZIG_TARBALL="zig-linux-x86_64-${ZIG_VERSION}.tar.xz" + curl -L "https://ziglang.org/download/${ZIG_VERSION}/${ZIG_TARBALL}" -o /tmp/${ZIG_TARBALL} + ZIG_SHA256="d45312e61ebcc48032b77bc4cf7fd6915c11fa16e4aad116b66c9468211230ea" + echo "${ZIG_SHA256} /tmp/${ZIG_TARBALL}" | sha256sum -c + sudo tar xJ -C /opt /tmp/${ZIG_TARBALL} + ZIG=/opt/zig-linux-x86_64-${ZIG_VERSION}/zig + echo "zig version: $($ZIG version)" + printf '#!/bin/sh\nexec %s cc -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cc > /dev/null + printf '#!/bin/sh\nexec %s c++ -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cxx > /dev/null + sudo chmod +x /usr/local/bin/musl-cc /usr/local/bin/musl-cxx + + - name: Build task binary (Linux — musl) if: runner.os == 'Linux' - env: - CC: zig cc -target x86_64-linux-musl - CXX: zig c++ -target x86_64-linux-musl - AR: zig ar - CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: zig c++ -target x86_64-linux-musl run: | set -e - sudo apt-get update -qq - sudo apt-get install -y -qq uuid-dev libclang-dev export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) - ZIG_SYSROOT=$(zig c++ -target x86_64-linux-musl -print-sysroot 2>/dev/null || echo /opt/hostedtoolcache/zig/0.13.0/x64) cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_SYSROOT="$ZIG_SYSROOT" \ - -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=NEVER \ - -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ - -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ + -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ + -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) From 71b90f4c233737869323c7d72e48b477f117e1a3 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:24:08 +0800 Subject: [PATCH 06/19] =?UTF-8?q?fix(ci):=20fix=20zig=20setup=20=E2=80=94?= =?UTF-8?q?=20use=20setup-zig=20action=20+=20create=20wrapper=20scripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The manual tar extraction to /opt failed with exit code 2 (likely /opt permission issue on the runner). Switch to mlugg/setup-zig action which extracts to /opt/hostedtoolcache/zig/ where the runner has permissions. Then create musl-cc/musl-cxx wrapper scripts that invoke zig with -target x86_64-linux-musl. --- .github/workflows/release.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7666aec53..8fb9d4d1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,16 +56,15 @@ jobs: run: rustup target add x86_64-unknown-linux-musl - name: Set up Zig + if: runner.os == 'Linux' + uses: mlugg/setup-zig@v1 + with: + version: "0.13.0" + + - name: Create musl-cc/musl-cxx wrappers if: runner.os == 'Linux' run: | - ZIG_VERSION=0.13.0 - ZIG_TARBALL="zig-linux-x86_64-${ZIG_VERSION}.tar.xz" - curl -L "https://ziglang.org/download/${ZIG_VERSION}/${ZIG_TARBALL}" -o /tmp/${ZIG_TARBALL} - ZIG_SHA256="d45312e61ebcc48032b77bc4cf7fd6915c11fa16e4aad116b66c9468211230ea" - echo "${ZIG_SHA256} /tmp/${ZIG_TARBALL}" | sha256sum -c - sudo tar xJ -C /opt /tmp/${ZIG_TARBALL} - ZIG=/opt/zig-linux-x86_64-${ZIG_VERSION}/zig - echo "zig version: $($ZIG version)" + ZIG=$(which zig) printf '#!/bin/sh\nexec %s cc -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cc > /dev/null printf '#!/bin/sh\nexec %s c++ -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cxx > /dev/null sudo chmod +x /usr/local/bin/musl-cc /usr/local/bin/musl-cxx From 8ba5336882f30fddef6457c57fae3dc67249628f Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:27:06 +0800 Subject: [PATCH 07/19] fix(ci): add UUID_LIBRARY hints and search paths for cmake musl cross-compile UUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so bypasses find_library search (which fails in cross-compilation mode when musl sysroot has no uuid). CMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH + CMAKE_SYSTEM_PREFIX_PATH ensure host library paths are still searched. CMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY ensures musl sysroot headers are used for C/C++ compilation. --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8fb9d4d1a..9f1edde4a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,6 +78,12 @@ jobs: -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ + -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ + -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ + -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ + -DCMAKE_SYSTEM_PREFIX_PATH=/usr/lib/x86_64-linux-gnu;/usr/lib \ + -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ + -DUUID_INCLUDE_DIR=/usr/include \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) From 462393d65e80a8e7db8c3287bad4a5c2b38704e0 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:32:29 +0800 Subject: [PATCH 08/19] fix(ci): quote CMAKE_SYSTEM_PREFIX_PATH semicolons + add cargo config for musl linker The semicolons in CMAKE_SYSTEM_PREFIX_PATH were being interpreted as shell command separators, breaking the cmake invocation. Quote them. Also create .cargo/config.toml with musl linker to ensure cargo uses zig cc for linking when building for x86_64-unknown-linux-musl. --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f1edde4a..109512957 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,6 +74,8 @@ jobs: run: | set -e export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) + mkdir -p .cargo + printf '[target.x86_64-unknown-linux-musl]\nlinker = "zig" cc -target x86_64-linux-musl\n' > .cargo/config.toml cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ @@ -81,7 +83,7 @@ jobs: -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ - -DCMAKE_SYSTEM_PREFIX_PATH=/usr/lib/x86_64-linux-gnu;/usr/lib \ + -DCMAKE_SYSTEM_PREFIX_PATH="/usr/lib/x86_64-linux-gnu;/usr/lib" \ -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ -DUUID_INCLUDE_DIR=/usr/include \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl From 9d7d8ebae1ba303302d0e499e536b8ea89332185 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:36:01 +0800 Subject: [PATCH 09/19] fix(ci): fix TOML quoting in .cargo/config.toml (escaped quotes in linker value) Use printf with \n for TOML newlines and proper quoted linker value "zig cc -target x86_64-linux-musl" instead of heredoc (YAML check fails). --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 109512957..475f22e2c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -75,7 +75,7 @@ jobs: set -e export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) mkdir -p .cargo - printf '[target.x86_64-unknown-linux-musl]\nlinker = "zig" cc -target x86_64-linux-musl\n' > .cargo/config.toml + printf '[target.x86_64-unknown-linux-musl]\nlinker = "zig cc -target x86_64-linux-musl"\n' > .cargo/config.toml cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ From 7751dc845d954d96bb45f72741a12cfc034300a7 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:40:04 +0800 Subject: [PATCH 10/19] fix(ci): switch Linux musl build to Docker approach zig cross-compilation approach blocked by cc-rs limitation: Rust's cc-rs crate cannot parse target triple x86_64-unknown-linux-musl ("musl" is not a recognized OS). C++ compilation also picks up glibc host headers instead of musl sysroot. Switch to Docker with ghcr.io/guion-opensource/rust-musl:3.21 (musl-native Alpine-based image). This is the approach from PRs #31/#32 which worked. --- .github/workflows/release.yml | 49 +++++++---------------------------- 1 file changed, 9 insertions(+), 40 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 475f22e2c..e86692178 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,49 +45,18 @@ jobs: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --target task_executable - - name: Install dependencies (Linux) - if: runner.os == 'Linux' - run: | - sudo apt-get update -q - sudo apt-get install -y cmake clang libclang-dev - - - name: Set up Rust musl target - if: runner.os == 'Linux' - run: rustup target add x86_64-unknown-linux-musl - - - name: Set up Zig - if: runner.os == 'Linux' - uses: mlugg/setup-zig@v1 - with: - version: "0.13.0" - - - name: Create musl-cc/musl-cxx wrappers - if: runner.os == 'Linux' - run: | - ZIG=$(which zig) - printf '#!/bin/sh\nexec %s cc -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cc > /dev/null - printf '#!/bin/sh\nexec %s c++ -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cxx > /dev/null - sudo chmod +x /usr/local/bin/musl-cc /usr/local/bin/musl-cxx - - name: Build task binary (Linux — musl) if: runner.os == 'Linux' run: | - set -e - export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) - mkdir -p .cargo - printf '[target.x86_64-unknown-linux-musl]\nlinker = "zig cc -target x86_64-linux-musl"\n' > .cargo/config.toml - cmake -S . -B build \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ - -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ - -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ - -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ - -DCMAKE_SYSTEM_PREFIX_PATH="/usr/lib/x86_64-linux-gnu;/usr/lib" \ - -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ - -DUUID_INCLUDE_DIR=/usr/include \ - -DRust_CARGO_TARGET=x86_64-unknown-linux-musl - cmake --build build --target task_executable -j$(nproc) + docker run --rm \ + -v "${{ github.workspace }}:/src" \ + -w /src \ + ghcr.io/guion-opensource/rust-musl:3.21 \ + sh -c ' + set -e + cmake -S . -B build -DCMAKE_BUILD_TYPE=Release + cmake --build build --target task_executable -j$(nproc) + ' - name: Package binary + completions run: | From 5e07b5fff4c2999ff2bc840c0531026ff840b490 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:42:16 +0800 Subject: [PATCH 11/19] fix(ci): use alpine:3.21 Docker image for musl build (private image inaccessible) ghcr.io/guion-opensource/rust-musl:3.21 is a private/restricted image. Switch to public alpine:3.21 with musl-libc + clang + rustup (same approach as PR #31 which worked). --- .github/workflows/release.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e86692178..dcff51a53 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,9 +51,13 @@ jobs: docker run --rm \ -v "${{ github.workspace }}:/src" \ -w /src \ - ghcr.io/guion-opensource/rust-musl:3.21 \ + alpine:3.21 \ sh -c ' set -e + apk add --no-cache build-base cmake git util-linux-dev clang clang-dev curl bash + curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable + . $HOME/.cargo/env + rustup target add x86_64-unknown-linux-musl cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --target task_executable -j$(nproc) ' From 8c5bf12529d554b950816ab1fecc9005e6d067e9 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 17:58:55 +0800 Subject: [PATCH 12/19] fix(ci): add zig musl cross-compilation to Linux build step ubuntu-22.04 host: install cmake clang libclang-dev, add musl target, install zig 0.13.0, create /usr/local/bin/musl-cc/musl-cxx wrappers that invoke zig cc/c++ with -target x86_64-linux-musl. cmake uses musl-cc/musl-cxx as compilers and -DRust_CARGO_TARGET to tell corrosion to build Rust for x86_64-unknown-linux-musl. LIBCLANG_PATH points to glibc libclang (bindgen runs on host). --- .github/workflows/release.yml | 45 +++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dcff51a53..dc445ad01 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,22 +45,41 @@ jobs: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --target task_executable + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update -q + sudo apt-get install -y cmake clang libclang-dev + + - name: Set up Rust musl target + if: runner.os == 'Linux' + run: rustup target add x86_64-unknown-linux-musl + + - name: Set up Zig + if: runner.os == 'Linux' + uses: mlugg/setup-zig@v1 + with: + version: "0.13.0" + + - name: Create musl-cc/musl-cxx wrappers + if: runner.os == 'Linux' + run: | + ZIG=/opt/hostedtoolcache/zig/0.13.0/x64/zig + printf '#!/bin/sh\nexec %s cc -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cc > /dev/null + printf '#!/bin/sh\nexec %s c++ -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cxx > /dev/null + sudo chmod +x /usr/local/bin/musl-cc /usr/local/bin/musl-cxx + - name: Build task binary (Linux — musl) if: runner.os == 'Linux' run: | - docker run --rm \ - -v "${{ github.workspace }}:/src" \ - -w /src \ - alpine:3.21 \ - sh -c ' - set -e - apk add --no-cache build-base cmake git util-linux-dev clang clang-dev curl bash - curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable - . $HOME/.cargo/env - rustup target add x86_64-unknown-linux-musl - cmake -S . -B build -DCMAKE_BUILD_TYPE=Release - cmake --build build --target task_executable -j$(nproc) - ' + set -e + export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ + -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ + -DRust_CARGO_TARGET=x86_64-unknown-linux-musl + cmake --build build --target task_executable -j$(nproc) - name: Package binary + completions run: | From 5a86bdcc7c9c25c2bd0df19c18d618b28cbc2d69 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 18:01:50 +0800 Subject: [PATCH 13/19] fix(ci): pass UUID_LIBRARY and UUID_INCLUDE_DIR to bypass find_library in cross-compilation mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CMAKE_C_COMPILER=musl-cc (a cross-compiler), cmake is in cross-compilation mode and find_library(uuid) fails. Pass explicit paths as cmake variables so cmake uses them directly without searching. No other cross-compilation flags added — CMAKE_SYSTEM_NAME is not set so cmake stays in native mode for library/header detection. --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dc445ad01..b5c4d5e37 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,6 +78,8 @@ jobs: -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ + -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ + -DUUID_INCLUDE_DIR=/usr/include \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) From c8ae6d210367e07b8b843126b59f8924a76c8556 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 18:09:51 +0800 Subject: [PATCH 14/19] fix(ci): strip -target flag from cc-rs calls + skip cmake compiler tests Blocker 1: cc-rs passes --target=x86_64-unknown-linux-musl which zig rejects ("UnknownOperatingSystem"). Wrapper scripts now use bash to filter out -target flags before invoking zig. Blocker 2: cmake C++ tests pull in glibc host headers. Add -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1 to skip compiler feature detection tests that use /usr/include. --- .github/workflows/release.yml | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b5c4d5e37..1ff6bd470 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,8 +65,28 @@ jobs: if: runner.os == 'Linux' run: | ZIG=/opt/hostedtoolcache/zig/0.13.0/x64/zig - printf '#!/bin/sh\nexec %s cc -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cc > /dev/null - printf '#!/bin/sh\nexec %s c++ -target x86_64-linux-musl "$@"\n' "$ZIG" | sudo tee /usr/local/bin/musl-cxx > /dev/null + sudo tee /usr/local/bin/musl-cc > /dev/null << 'WRAPPER' + #!/bin/bash + args=() + skip_next=0 + for arg in "$@"; do + [ "$skip_next" = "1" ] && { skip_next=0; continue; } + [ "$arg" = "-target" ] && { skip_next=1; continue; } + args+=("$arg") + done + exec zig cc -target x86_64-linux-musl "${args[@]}" + WRAPPER + sudo tee /usr/local/bin/musl-cxx > /dev/null << 'WRAPPER' + #!/bin/bash + args=() + skip_next=0 + for arg in "$@"; do + [ "$skip_next" = "1" ] && { skip_next=0; continue; } + [ "$arg" = "-target" ] && { skip_next=1; continue; } + args+=("$arg") + done + exec zig c++ -target x86_64-linux-musl "${args[@]}" + WRAPPER sudo chmod +x /usr/local/bin/musl-cc /usr/local/bin/musl-cxx - name: Build task binary (Linux — musl) @@ -76,6 +96,8 @@ jobs: export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_COMPILER_WORKS=1 \ + -DCMAKE_CXX_COMPILER_WORKS=1 \ -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ From bcd4fcba25fe137867c27c6c9a66ae22cff8bec5 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 18:12:54 +0800 Subject: [PATCH 15/19] fix(ci): filter --target=VALUE form + add CMAKE_SYSROOT for musl headers - Filter `--target=VALUE` single-arg form (cc-rs passes as one argument) - Use $(which zig) instead of hardcoded path - Add CMAKE_SYSROOT=zig_musl_sysroot so C++ compiler uses musl headers --- .github/workflows/release.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1ff6bd470..a803cdd61 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,7 +64,7 @@ jobs: - name: Create musl-cc/musl-cxx wrappers if: runner.os == 'Linux' run: | - ZIG=/opt/hostedtoolcache/zig/0.13.0/x64/zig + ZIG=$(which zig) sudo tee /usr/local/bin/musl-cc > /dev/null << 'WRAPPER' #!/bin/bash args=() @@ -72,6 +72,7 @@ jobs: for arg in "$@"; do [ "$skip_next" = "1" ] && { skip_next=0; continue; } [ "$arg" = "-target" ] && { skip_next=1; continue; } + [[ "$arg" == --target=* ]] && continue args+=("$arg") done exec zig cc -target x86_64-linux-musl "${args[@]}" @@ -83,6 +84,7 @@ jobs: for arg in "$@"; do [ "$skip_next" = "1" ] && { skip_next=0; continue; } [ "$arg" = "-target" ] && { skip_next=1; continue; } + [[ "$arg" == --target=* ]] && continue args+=("$arg") done exec zig c++ -target x86_64-linux-musl "${args[@]}" @@ -100,6 +102,7 @@ jobs: -DCMAKE_CXX_COMPILER_WORKS=1 \ -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ + -DCMAKE_SYSROOT=$(zig c++ -target x86_64-linux-musl -print-sysroot 2>/dev/null || echo "") \ -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ -DUUID_INCLUDE_DIR=/usr/include \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl From 7dbfda35d6feb50973eb7fe256857ac1f06c5f2f Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 18:27:30 +0800 Subject: [PATCH 16/19] fix(ci): use toolchain file + isolated UUID headers for musl cross-compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add "Isolate UUID headers" step: copy uuid/uuid.h to /opt/musl-includes/uuid/ which has no glibc includes (no features.h, no bits/). - Write cmake toolchain file (/tmp/musl-toolchain.cmake) that clears CMAKE_*_IMPLICIT_INCLUDE_DIRECTORIES to prevent cmake from adding /usr/include to zig's musl compile. - Use CMAKE_TOOLCHAIN_FILE instead of passing compiler vars individually. - Keep UUID_INCLUDE_DIR pointing to /opt/musl-includes (isolated header). - Keep UUID_LIBRARY pointing to host libuuid.so for linking. 🍷 Generated with Lenos Assisted-by: MiniMax-M2.7-highspeed via Lenos --- .github/workflows/release.yml | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a803cdd61..3b3c5668d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,6 +51,12 @@ jobs: sudo apt-get update -q sudo apt-get install -y cmake clang libclang-dev + - name: Isolate UUID headers + if: runner.os == 'Linux' + run: | + sudo mkdir -p /opt/musl-includes/uuid + sudo cp /usr/include/uuid/uuid.h /opt/musl-includes/uuid/ + - name: Set up Rust musl target if: runner.os == 'Linux' run: rustup target add x86_64-unknown-linux-musl @@ -59,7 +65,7 @@ jobs: if: runner.os == 'Linux' uses: mlugg/setup-zig@v1 with: - version: "0.13.0" + version: "0.14.0" - name: Create musl-cc/musl-cxx wrappers if: runner.os == 'Linux' @@ -95,16 +101,25 @@ jobs: if: runner.os == 'Linux' run: | set -e + cat > /tmp/musl-toolchain.cmake << 'EOF' + set(CMAKE_SYSTEM_NAME Linux) + set(CMAKE_SYSTEM_PROCESSOR x86_64) + set(CMAKE_C_COMPILER /usr/local/bin/musl-cc) + set(CMAKE_CXX_COMPILER /usr/local/bin/musl-cxx) + set(CMAKE_C_COMPILER_WORKS TRUE) + set(CMAKE_CXX_COMPILER_WORKS TRUE) + set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "") + set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "") + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + EOF export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER_WORKS=1 \ - -DCMAKE_CXX_COMPILER_WORKS=1 \ - -DCMAKE_C_COMPILER=/usr/local/bin/musl-cc \ - -DCMAKE_CXX_COMPILER=/usr/local/bin/musl-cxx \ - -DCMAKE_SYSROOT=$(zig c++ -target x86_64-linux-musl -print-sysroot 2>/dev/null || echo "") \ + -DCMAKE_TOOLCHAIN_FILE=/tmp/musl-toolchain.cmake \ + -DUUID_INCLUDE_DIR=/opt/musl-includes \ -DUUID_LIBRARY=/usr/lib/x86_64-linux-gnu/libuuid.so \ - -DUUID_INCLUDE_DIR=/usr/include \ -DRust_CARGO_TARGET=x86_64-unknown-linux-musl cmake --build build --target task_executable -j$(nproc) From 152b2d686940d240032b44fae81de8fc9071d089 Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 18:37:33 +0800 Subject: [PATCH 17/19] =?UTF-8?q?chore(ci):=20polish=20release=20workflow?= =?UTF-8?q?=20=E2=80=94=20add=20uuid-dev,=20remove=20dead=20code,=20fix=20?= =?UTF-8?q?dirname?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add uuid-dev to apt-get install (uuid/uuid.h dependency, was implicit) - Remove unused ZIG=$(which zig) assignment (zig is in PATH via setup-zig action) - Fix xargs dirname: add -r to skip if no input (avoids "missing operand" stderr) - Replace heredoc with printf to write toolchain file (avoids YAML block scalar indentation issues with dedented content) 🍷 Generated with Lenos Assisted-by: MiniMax-M2.7-highspeed via Lenos --- .github/workflows/release.yml | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3b3c5668d..a08f5e902 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: if: runner.os == 'Linux' run: | sudo apt-get update -q - sudo apt-get install -y cmake clang libclang-dev + sudo apt-get install -y cmake clang libclang-dev uuid-dev - name: Isolate UUID headers if: runner.os == 'Linux' @@ -70,7 +70,6 @@ jobs: - name: Create musl-cc/musl-cxx wrappers if: runner.os == 'Linux' run: | - ZIG=$(which zig) sudo tee /usr/local/bin/musl-cc > /dev/null << 'WRAPPER' #!/bin/bash args=() @@ -101,20 +100,20 @@ jobs: if: runner.os == 'Linux' run: | set -e - cat > /tmp/musl-toolchain.cmake << 'EOF' - set(CMAKE_SYSTEM_NAME Linux) - set(CMAKE_SYSTEM_PROCESSOR x86_64) - set(CMAKE_C_COMPILER /usr/local/bin/musl-cc) - set(CMAKE_CXX_COMPILER /usr/local/bin/musl-cxx) - set(CMAKE_C_COMPILER_WORKS TRUE) - set(CMAKE_CXX_COMPILER_WORKS TRUE) - set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "") - set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "") - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - EOF - export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs dirname || echo /usr/lib/llvm-14/lib) + printf '%s\n' \ + 'set(CMAKE_SYSTEM_NAME Linux)' \ + 'set(CMAKE_SYSTEM_PROCESSOR x86_64)' \ + 'set(CMAKE_C_COMPILER /usr/local/bin/musl-cc)' \ + 'set(CMAKE_CXX_COMPILER /usr/local/bin/musl-cxx)' \ + 'set(CMAKE_C_COMPILER_WORKS TRUE)' \ + 'set(CMAKE_CXX_COMPILER_WORKS TRUE)' \ + 'set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "")' \ + 'set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "")' \ + 'set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)' \ + 'set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)' \ + 'set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)' \ + > /tmp/musl-toolchain.cmake + export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs -r dirname || echo /usr/lib/llvm-14/lib) cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE=/tmp/musl-toolchain.cmake \ From 01e1293ba3d3d271f8999339a0b43940c0f93a2c Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 18:42:08 +0800 Subject: [PATCH 18/19] =?UTF-8?q?fix(ci):=20fix=20LIBCLANG=5FPATH=20fallba?= =?UTF-8?q?ck=20=E2=80=94=20xargs=20-r=20suppresses=20||=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xargs -r exits 0 with empty input, so the || fallback never fires and LIBCLANG_PATH becomes empty when libclang-dev isn't found. Fix with explicit conditional: use dirname of found lib, else fallback path. 🍷 Generated with Lenos Assisted-by: MiniMax-M2.7-highspeed via Lenos --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a08f5e902..4cfb399c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,9 @@ jobs: 'set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)' \ 'set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)' \ > /tmp/musl-toolchain.cmake - export LIBCLANG_PATH=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1 | xargs -r dirname || echo /usr/lib/llvm-14/lib) + _lib=$(dpkg -L libclang-dev 2>/dev/null | grep 'libclang.*\.so$' | head -1) + export LIBCLANG_PATH=${_lib:+$(dirname "$_lib")} + export LIBCLANG_PATH=${LIBCLANG_PATH:-/usr/lib/llvm-14/lib} cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE=/tmp/musl-toolchain.cmake \ From a25cb30539fb96827aac776633961f5e48bafa4d Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 7 Apr 2026 18:48:35 +0800 Subject: [PATCH 19/19] chore(ci): remove pull_request trigger from Release workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workflow is stable, no longer needs PR testing on every push. 🍷 Generated with Lenos Assisted-by: MiniMax-M2.7-highspeed via Lenos --- .github/workflows/release.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4cfb399c4..7f341b844 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,9 +4,6 @@ on: push: tags: - 'v*.*.*' - pull_request: - branches: - - develop permissions: contents: write