diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5eed4b78..9a33a407 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,7 +57,12 @@ jobs: echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV + - name: Build static Linux binary + if: contains(matrix.target, 'linux') + run: ./scripts/build-static.sh --ci ${{ matrix.target }} + - name: Build binary + if: "!contains(matrix.target, 'linux')" run: cargo build --release --target ${{ matrix.target }} - name: Create tarball diff --git a/build.rs b/build.rs index dcd7eb46..51d880a1 100644 --- a/build.rs +++ b/build.rs @@ -25,4 +25,18 @@ fn main() { "cargo:rustc-env=VERSION_WITH_GIT_HASH={} ({})", version, git_hash ); + + // Configure static linking for Linux gnu targets + // Note: We use gnu (glibc) instead of musl because V8 doesn't provide prebuilt musl binaries + // and building V8 from source for musl fails. Static glibc linking provides good portability + // while still allowing us to use V8 prebuilt binaries. + let target = env::var("TARGET").unwrap_or_default(); + if target.contains("linux") && target.contains("gnu") { + // Enable static linking of the C runtime and standard library + // This links glibc statically, adding ~2-5MB to binary size but improving portability + println!("cargo:rustc-link-arg=-static-libgcc"); + + // Note: Full static linking (-static) would break NSS/DNS, so we use crt-static instead + // which is applied via RUSTFLAGS in the build process + } } diff --git a/scripts/build-static.sh b/scripts/build-static.sh new file mode 100755 index 00000000..b51575fd --- /dev/null +++ b/scripts/build-static.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# Build and verify static glibc binaries for Linux +# This uses the gnu target with crt-static for better portability while avoiding musl/V8 issues +# +# Usage: ./build-static.sh [--ci|--non-interactive] [TARGET] +# TARGET: Optional rust target (e.g., x86_64-unknown-linux-gnu) +# If not provided, detects from uname -m + +set -e + +# Parse arguments +NON_INTERACTIVE=false +TARGET="" + +for arg in "$@"; do + if [[ "$arg" == "--non-interactive" ]] || [[ "$arg" == "--ci" ]]; then + NON_INTERACTIVE=true + elif [[ "$arg" == *"unknown-linux-gnu"* ]]; then + TARGET="$arg" + fi +done + +echo "=== httpjail static build verification ===" +echo "" + +# Determine target if not provided +if [ -z "$TARGET" ]; then + ARCH=$(uname -m) + case "$ARCH" in + x86_64) + TARGET="x86_64-unknown-linux-gnu" + ;; + aarch64|arm64) + TARGET="aarch64-unknown-linux-gnu" + ;; + *) + echo "Unsupported architecture: $ARCH" + exit 1 + ;; + esac + echo "Auto-detected target from architecture: $ARCH -> $TARGET" +else + echo "Using specified target: $TARGET" +fi + +echo "Note: Using gnu target with crt-static for static glibc linking" +echo "" + +# Check if rust target is installed +echo "1. Checking Rust target..." +if ! rustup target list --installed | grep -q "$TARGET"; then + echo "Target $TARGET not installed. Installing..." + rustup target add "$TARGET" +else + echo "✓ Target $TARGET already installed" +fi +echo "" + +# Build with static linking +echo "2. Building for $TARGET with static glibc..." +RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target "$TARGET" +echo "" + +# Verify binary (check both local and shared cargo target) +BINARY="target/$TARGET/release/httpjail" +if [ ! -f "$BINARY" ] && [ -n "${CARGO_HOME}" ]; then + # Check shared cargo target when CARGO_HOME is set + BINARY="${CARGO_HOME}/shared-target/$TARGET/release/httpjail" +fi + +if [ ! -f "$BINARY" ]; then + echo "✗ Binary not found at $BINARY" + exit 1 +fi + +echo "3. Verifying linking..." +echo "" + +# Check file type +echo "File type:" +file "$BINARY" +echo "" + +# Check dynamic dependencies +echo "Dynamic dependencies:" +if ldd "$BINARY" 2>&1; then + echo "" + echo "Note: Binary uses dynamic linking for some system libraries (expected with glibc)" + echo "The C runtime is statically linked, improving portability to older systems" +else + echo "✓ Binary is fully statically linked" +fi +echo "" + +# Check binary size +SIZE=$(du -h "$BINARY" | cut -f1) +echo "Binary size: $SIZE" +echo "" + +# Test basic functionality +echo "4. Testing binary..." +if "$BINARY" --version; then + echo "✓ Binary runs successfully" +else + echo "✗ Binary failed to run" + exit 1 +fi +echo "" + +echo "=== Build verification complete ===" +echo "" +echo "Binary location: $BINARY" +echo "To test on an older system, copy this binary and run:" +echo " ./httpjail --version" +echo "" +echo "The binary uses static glibc linking for improved portability while" +echo "still working with V8 prebuilt binaries (musl not supported by V8)."