Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/actions/install-musl-toolchain/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Install musl toolchain
description: Install x86_64 musl-tools (apt) and the cached aarch64 musl cross compiler from cross-tools/musl-cross.

runs:
using: composite
steps:
- name: Cache aarch64 musl cross compiler
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/musl-cross
key: aarch64-unknown-linux-musl-cross-tools-20260430
- name: Install musl toolchains
shell: bash
run: |
for i in 1 2 3; do
sudo apt-get update && sudo apt-get install -y musl-tools && break
[ "$i" = 3 ] && exit 1
sleep 5
done
if [ ! -x "$HOME/musl-cross/aarch64-unknown-linux-musl/bin/aarch64-unknown-linux-musl-gcc" ]; then
mkdir -p "$HOME/musl-cross"
curl -fL "https://github.com/cross-tools/musl-cross/releases/download/20260430/aarch64-unknown-linux-musl.tar.xz" \
| tar -xJ -C "$HOME/musl-cross"
fi
{
echo "$HOME/musl-cross/aarch64-unknown-linux-musl/bin"
} >> "$GITHUB_PATH"
{
echo "CC_x86_64_unknown_linux_musl=musl-gcc"
echo "CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=musl-gcc"
echo "CC_aarch64_unknown_linux_musl=aarch64-unknown-linux-musl-gcc"
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-unknown-linux-musl-gcc"
} >> "$GITHUB_ENV"
59 changes: 26 additions & 33 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,53 +61,46 @@ jobs:
name: Cross Compile (Linux)
runs-on: ubuntu-latest
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
RUSTFLAGS: "-C target-feature=+crt-static"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rust
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: cargo-ubuntu-cross-linux-${{ hashFiles('**/Cargo.lock') }}
key: cargo-ubuntu-cross-linux-musl-${{ hashFiles('**/Cargo.lock') }}
restore-keys: cargo-ubuntu-
- name: Install Rust
- uses: ./.github/actions/install-musl-toolchain
- name: Build x86_64 musl
run: cargo build --release --target x86_64-unknown-linux-musl --features vendored-openssl
- name: Verify x86_64 static linkage
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup target add aarch64-unknown-linux-gnu
- name: Install aarch64 cross toolchain
file target/x86_64-unknown-linux-musl/release/pup
if readelf -d target/x86_64-unknown-linux-musl/release/pup | grep -q "(NEEDED)"; then
echo "ERROR: binary has dynamic NEEDED entries"
exit 1
fi
- name: Build aarch64 musl
run: cargo build --release --target aarch64-unknown-linux-musl --features vendored-openssl
- name: Verify aarch64 static linkage
run: |
for i in 1 2 3; do
sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu && exit 0
sleep 5
done
exit 1
- name: Build all targets
run: |
PIDS=()
for target in x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
(set -o pipefail
echo "==> Starting ${target}"
cargo build --release --target "${target}" --features vendored-openssl 2>&1 \
| tee "/tmp/${target}.log"
) &
PIDS+=($!)
done
status=0
for pid in "${PIDS[@]}"; do
wait "$pid" || status=1
done
exit $status
file target/aarch64-unknown-linux-musl/release/pup
if readelf -d target/aarch64-unknown-linux-musl/release/pup | grep -q "(NEEDED)"; then
echo "ERROR: binary has dynamic NEEDED entries"
exit 1
fi
- name: Report sizes
run: |
for target in x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
echo "${target}:"
ls -lh "target/${target}/release/pup"
done
ls -lh target/x86_64-unknown-linux-musl/release/pup
ls -lh target/aarch64-unknown-linux-musl/release/pup

cross-compile-macos:
name: Cross Compile (macOS)
Expand Down
13 changes: 3 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ jobs:
name: Build Linux
runs-on: ubuntu-latest
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
RUSTFLAGS: "-C target-feature=+crt-static"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
Expand All @@ -30,7 +29,7 @@ jobs:
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup target add aarch64-unknown-linux-gnu
rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
- name: Cache Rust dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
Expand All @@ -42,13 +41,7 @@ jobs:
key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-release-
- name: Install aarch64 cross toolchain
run: |
for i in 1 2 3; do
sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu && exit 0
sleep 5
done
exit 1
- uses: ./.github/actions/install-musl-toolchain
- name: Install syft
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
- uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7.2.1
Expand Down
4 changes: 2 additions & 2 deletions .goreleaser-linux.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ builds:
binary: pup
command: build
targets:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-musl
flags:
- --release
- --features=vendored-openssl
Expand Down
11 changes: 11 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ Technical architecture and design rationale for Pup CLI.
4. **Concurrency** - Async/await with tokio runtime
5. **Strong type system** - Catch errors at compile time with rich enums

### Static Linking for Linux

Linux release binaries are statically linked using musl libc:
- **No glibc dependency** - Works across all Linux distributions, including older systems like Ubuntu 22.04 (Jammy) with glibc 2.35
- **Fully self-contained** - No library compatibility issues
- **Portable** - Same binary works on Debian, Ubuntu, Alpine, CentOS, etc.

Build targets:
- `x86_64-unknown-linux-musl` - Intel/AMD 64-bit processors
- `aarch64-unknown-linux-musl` - ARM 64-bit processors

**Tradeoffs:**
- Steeper learning curve than Go
- Longer compile times
Expand Down
26 changes: 26 additions & 0 deletions docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

Common issues and solutions for Pup CLI.

## Compatibility Issues

### GLIBC version error on Linux

**Symptoms:**
```
pup: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by pup)
pup: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.39' not found (required by pup)
```

**Solution:**
Upgrade to **pup 0.58.4 or later**. Starting with version 0.58.4, Linux binaries are statically linked with musl libc and have **no glibc dependency**.

```bash
# Update to the latest version
brew upgrade pup

# Or download the latest release manually
curl -L https://github.com/DataDog/pup/releases/latest/download/pup_Linux_x86_64.tar.gz | tar xz
```

**Technical details:**
- Versions before 0.58.4 were dynamically linked and required glibc ≥ 2.38
- Versions 0.58.4+ are static musl binaries that work on any Linux distribution
- No action required after upgrading — the new binary "just works"

## Authentication Issues

### OAuth2 Login Fails
Expand Down
Loading