diff --git a/.github/workflows/package-preview.yml b/.github/workflows/package-preview.yml index 28ed40f..9834a2d 100644 --- a/.github/workflows/package-preview.yml +++ b/.github/workflows/package-preview.yml @@ -57,7 +57,7 @@ jobs: run: brew install cmake libb2 lz4 xz zstd - name: Install Linux dependencies - if: runner.os == 'Linux' + if: runner.os == 'Linux' && matrix.target != 'aarch64-unknown-linux-musl' run: | sudo apt-get update sudo apt-get install -y \ @@ -72,6 +72,7 @@ jobs: echo /opt/zig >> "$GITHUB_PATH" - name: Install Rust toolchain + if: matrix.target != 'aarch64-unknown-linux-musl' run: | rustup toolchain install stable --profile minimal rustup default stable @@ -83,9 +84,13 @@ jobs: python-version: "3.x" - name: Package Unix - if: runner.os != 'Windows' + if: runner.os != 'Windows' && matrix.target != 'aarch64-unknown-linux-musl' run: scripts/package-release.sh "${{ matrix.target }}" dist + - name: Package Linux ARM64 musl in Alpine + if: matrix.target == 'aarch64-unknown-linux-musl' + run: scripts/package-release-alpine.sh "${{ matrix.target }}" dist + - name: Package Windows if: runner.os == 'Windows' shell: pwsh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ed355b..d9338ac 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,7 +53,7 @@ jobs: run: brew install cmake libb2 lz4 xz zstd - name: Install Linux dependencies - if: runner.os == 'Linux' + if: runner.os == 'Linux' && matrix.target != 'aarch64-unknown-linux-musl' run: | sudo apt-get update sudo apt-get install -y \ @@ -68,6 +68,7 @@ jobs: echo /opt/zig >> "$GITHUB_PATH" - name: Install Rust toolchain + if: matrix.target != 'aarch64-unknown-linux-musl' run: | rustup toolchain install stable --profile minimal rustup default stable @@ -79,9 +80,13 @@ jobs: python-version: "3.x" - name: Package Unix - if: runner.os != 'Windows' + if: runner.os != 'Windows' && matrix.target != 'aarch64-unknown-linux-musl' run: scripts/package-release.sh "${{ matrix.target }}" dist + - name: Package Linux ARM64 musl in Alpine + if: matrix.target == 'aarch64-unknown-linux-musl' + run: scripts/package-release-alpine.sh "${{ matrix.target }}" dist + - name: Package Windows if: runner.os == 'Windows' shell: pwsh diff --git a/docs/INSTALL.md b/docs/INSTALL.md index bcf915a..755f478 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -115,9 +115,9 @@ zm completions powershell > zm.ps1 ## Linux Direct Install -Linux release archives are statically linked musl builds. The install script is -the recommended path; use the manual flow when you want to inspect or stage the -tarball yourself. +Linux release archives are statically linked musl builds that run +without installing extra runtime packages. The install script is the recommended +path; use the manual flow when you want to inspect or stage the tarball yourself. ```sh curl -LO https://github.com/tzap-org/zmanager/releases/download/v1.0.4/SHA256SUMS diff --git a/scripts/package-release-alpine.sh b/scripts/package-release-alpine.sh new file mode 100755 index 0000000..d9c8c5e --- /dev/null +++ b/scripts/package-release-alpine.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 1 || $# -gt 2 ]]; then + echo "usage: scripts/package-release-alpine.sh [out-dir]" >&2 + exit 2 +fi + +TARGET=$1 +OUT_DIR=${2:-dist} +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +IMAGE=${ZM_ALPINE_RUST_IMAGE:-rust:1-alpine3.22} + +if [[ "$TARGET" != "aarch64-unknown-linux-musl" ]]; then + echo "Alpine packaging is currently supported only for aarch64-unknown-linux-musl" >&2 + exit 2 +fi + +if ! command -v docker >/dev/null 2>&1; then + echo "docker is required for Alpine musl packaging" >&2 + exit 1 +fi + +cd "$ROOT" +mkdir -p "$OUT_DIR" + +docker run --rm \ + --platform linux/arm64 \ + -v "$ROOT:/workspace" \ + -w /workspace \ + -e TARGET="$TARGET" \ + -e OUT_DIR="$OUT_DIR" \ + -e CARGO_HOME=/workspace/target/alpine-cargo \ + -e CARGO_TARGET_DIR=/workspace/target \ + -e HOST_UID="$(id -u)" \ + -e HOST_GID="$(id -g)" \ + -e ZM_USE_SYSTEM_MUSL_TOOLCHAIN=1 \ + "$IMAGE" \ + /bin/sh -c ' + set -eu + apk add --no-cache \ + bash \ + binutils \ + build-base \ + cmake \ + file \ + linux-headers \ + perl \ + pkgconf \ + python3 + + export CC_aarch64_unknown_linux_musl=cc + export CXX_aarch64_unknown_linux_musl=c++ + export AR_aarch64_unknown_linux_musl=ar + export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=cc + + scripts/package-release.sh "$TARGET" "$OUT_DIR" + + chown -R "$HOST_UID:$HOST_GID" "$OUT_DIR" "target/$TARGET" 2>/dev/null || true + ' diff --git a/scripts/package-release.sh b/scripts/package-release.sh index 07615c3..6da0f49 100755 --- a/scripts/package-release.sh +++ b/scripts/package-release.sh @@ -37,13 +37,29 @@ configure_static_linux_target() { ;; esac + local target_env=${TARGET//-/_} + local target_env_upper=${target_env^^} + + if [[ "${ZM_USE_SYSTEM_MUSL_TOOLCHAIN:-}" == "1" ]]; then + local cc_env="CC_${target_env}" + local cxx_env="CXX_${target_env}" + local ar_env="AR_${target_env}" + local cxxstdlib_env="CXXSTDLIB_${target_env}" + local linker_env="CARGO_TARGET_${target_env_upper}_LINKER" + + export "$cc_env=${!cc_env:-${CC:-cc}}" + export "$cxx_env=${!cxx_env:-${CXX:-c++}}" + export "$ar_env=${!ar_env:-${AR:-ar}}" + export "$cxxstdlib_env=${!cxxstdlib_env:-stdc++}" + export "$linker_env=${!linker_env:-${!cc_env}}" + return + fi + if ! command -v zig >/dev/null 2>&1; then echo "zig is required to build static Linux release artifacts for $TARGET" >&2 exit 1 fi - local target_env=${TARGET//-/_} - local target_env_upper=${target_env^^} local tool_dir="$ROOT/target/zmanager-tools/$TARGET" local zig_cc="$tool_dir/zig-cc" local zig_cxx="$tool_dir/zig-cxx"