Skip to content

Commit cb5c602

Browse files
authored
build: use static glibc linking for Linux releases (#76)
1 parent 2983136 commit cb5c602

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

.github/workflows/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ jobs:
5757
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
5858
echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV
5959
60+
- name: Build static Linux binary
61+
if: contains(matrix.target, 'linux')
62+
run: ./scripts/build-static.sh --ci ${{ matrix.target }}
63+
6064
- name: Build binary
65+
if: "!contains(matrix.target, 'linux')"
6166
run: cargo build --release --target ${{ matrix.target }}
6267

6368
- name: Create tarball

build.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,18 @@ fn main() {
2525
"cargo:rustc-env=VERSION_WITH_GIT_HASH={} ({})",
2626
version, git_hash
2727
);
28+
29+
// Configure static linking for Linux gnu targets
30+
// Note: We use gnu (glibc) instead of musl because V8 doesn't provide prebuilt musl binaries
31+
// and building V8 from source for musl fails. Static glibc linking provides good portability
32+
// while still allowing us to use V8 prebuilt binaries.
33+
let target = env::var("TARGET").unwrap_or_default();
34+
if target.contains("linux") && target.contains("gnu") {
35+
// Enable static linking of the C runtime and standard library
36+
// This links glibc statically, adding ~2-5MB to binary size but improving portability
37+
println!("cargo:rustc-link-arg=-static-libgcc");
38+
39+
// Note: Full static linking (-static) would break NSS/DNS, so we use crt-static instead
40+
// which is applied via RUSTFLAGS in the build process
41+
}
2842
}

scripts/build-static.sh

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/bin/bash
2+
# Build and verify static glibc binaries for Linux
3+
# This uses the gnu target with crt-static for better portability while avoiding musl/V8 issues
4+
#
5+
# Usage: ./build-static.sh [--ci|--non-interactive] [TARGET]
6+
# TARGET: Optional rust target (e.g., x86_64-unknown-linux-gnu)
7+
# If not provided, detects from uname -m
8+
9+
set -e
10+
11+
# Parse arguments
12+
NON_INTERACTIVE=false
13+
TARGET=""
14+
15+
for arg in "$@"; do
16+
if [[ "$arg" == "--non-interactive" ]] || [[ "$arg" == "--ci" ]]; then
17+
NON_INTERACTIVE=true
18+
elif [[ "$arg" == *"unknown-linux-gnu"* ]]; then
19+
TARGET="$arg"
20+
fi
21+
done
22+
23+
echo "=== httpjail static build verification ==="
24+
echo ""
25+
26+
# Determine target if not provided
27+
if [ -z "$TARGET" ]; then
28+
ARCH=$(uname -m)
29+
case "$ARCH" in
30+
x86_64)
31+
TARGET="x86_64-unknown-linux-gnu"
32+
;;
33+
aarch64|arm64)
34+
TARGET="aarch64-unknown-linux-gnu"
35+
;;
36+
*)
37+
echo "Unsupported architecture: $ARCH"
38+
exit 1
39+
;;
40+
esac
41+
echo "Auto-detected target from architecture: $ARCH -> $TARGET"
42+
else
43+
echo "Using specified target: $TARGET"
44+
fi
45+
46+
echo "Note: Using gnu target with crt-static for static glibc linking"
47+
echo ""
48+
49+
# Check if rust target is installed
50+
echo "1. Checking Rust target..."
51+
if ! rustup target list --installed | grep -q "$TARGET"; then
52+
echo "Target $TARGET not installed. Installing..."
53+
rustup target add "$TARGET"
54+
else
55+
echo "✓ Target $TARGET already installed"
56+
fi
57+
echo ""
58+
59+
# Build with static linking
60+
echo "2. Building for $TARGET with static glibc..."
61+
RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target "$TARGET"
62+
echo ""
63+
64+
# Verify binary (check both local and shared cargo target)
65+
BINARY="target/$TARGET/release/httpjail"
66+
if [ ! -f "$BINARY" ] && [ -n "${CARGO_HOME}" ]; then
67+
# Check shared cargo target when CARGO_HOME is set
68+
BINARY="${CARGO_HOME}/shared-target/$TARGET/release/httpjail"
69+
fi
70+
71+
if [ ! -f "$BINARY" ]; then
72+
echo "✗ Binary not found at $BINARY"
73+
exit 1
74+
fi
75+
76+
echo "3. Verifying linking..."
77+
echo ""
78+
79+
# Check file type
80+
echo "File type:"
81+
file "$BINARY"
82+
echo ""
83+
84+
# Check dynamic dependencies
85+
echo "Dynamic dependencies:"
86+
if ldd "$BINARY" 2>&1; then
87+
echo ""
88+
echo "Note: Binary uses dynamic linking for some system libraries (expected with glibc)"
89+
echo "The C runtime is statically linked, improving portability to older systems"
90+
else
91+
echo "✓ Binary is fully statically linked"
92+
fi
93+
echo ""
94+
95+
# Check binary size
96+
SIZE=$(du -h "$BINARY" | cut -f1)
97+
echo "Binary size: $SIZE"
98+
echo ""
99+
100+
# Test basic functionality
101+
echo "4. Testing binary..."
102+
if "$BINARY" --version; then
103+
echo "✓ Binary runs successfully"
104+
else
105+
echo "✗ Binary failed to run"
106+
exit 1
107+
fi
108+
echo ""
109+
110+
echo "=== Build verification complete ==="
111+
echo ""
112+
echo "Binary location: $BINARY"
113+
echo "To test on an older system, copy this binary and run:"
114+
echo " ./httpjail --version"
115+
echo ""
116+
echo "The binary uses static glibc linking for improved portability while"
117+
echo "still working with V8 prebuilt binaries (musl not supported by V8)."

0 commit comments

Comments
 (0)