#!/bin/bash # Build fully static MUSL binaries for C-Relay # Produces portable binaries with zero runtime dependencies set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BUILD_DIR="$SCRIPT_DIR/build" echo "Building fully static MUSL binaries for C-Relay..." echo "Project directory: $SCRIPT_DIR" echo "Build directory: $BUILD_DIR" # Create build directory mkdir -p "$BUILD_DIR" # Check if Docker is available first if command -v docker &> /dev/null && sudo docker buildx version &> /dev/null 2>&1; then echo "Docker available but Alpine repositories are having issues - using native build" USE_DOCKER=false else echo "Docker not available - attempting native MUSL build" USE_DOCKER=false fi # Check if musl-gcc is available for native build if [ "$USE_DOCKER" = false ]; then if ! command -v musl-gcc &> /dev/null; then echo "Installing musl development tools..." sudo apt update && sudo apt install -y musl-dev musl-tools if ! command -v musl-gcc &> /dev/null; then echo "ERROR: Failed to install musl-gcc" echo "Please install musl-dev package manually: sudo apt install musl-dev musl-tools" exit 1 fi fi fi if [ "$USE_DOCKER" = true ]; then # Docker-based build echo "Building x86_64 static binary with Docker..." sudo docker buildx build \ --platform linux/amd64 \ -f "$SCRIPT_DIR/examples/deployment/static-builder.Dockerfile" \ -t c-relay-static-builder-x86_64 \ --load \ "$SCRIPT_DIR" # Extract x86_64 binary sudo docker run --rm -v "$BUILD_DIR:/output" c-relay-static-builder-x86_64 \ sh -c "cp /c_relay_static_musl_x86_64 /output/c_relay_static_x86_64" echo "x86_64 static binary created: $BUILD_DIR/c_relay_static_x86_64" # Build ARM64 static binary echo "Building ARM64 static binary with Docker..." sudo docker buildx build \ --platform linux/arm64 \ -f "$SCRIPT_DIR/examples/deployment/static-builder.Dockerfile" \ -t c-relay-static-builder-arm64 \ --load \ "$SCRIPT_DIR" # Extract ARM64 binary sudo docker run --rm -v "$BUILD_DIR:/output" c-relay-static-builder-arm64 \ sh -c "cp /c_relay_static_musl_arm64 /output/c_relay_static_arm64" echo "ARM64 static binary created: $BUILD_DIR/c_relay_static_arm64" else # Native static build with regular gcc echo "Building static binary with gcc..." # Check for required static libraries echo "Checking for static libraries..." MISSING_LIBS="" for lib in libsqlite3.a libssl.a libcrypto.a libz.a; do if ! find /usr/lib* /usr/local/lib* -name "$lib" 2>/dev/null | head -1 | grep -q .; then MISSING_LIBS="$MISSING_LIBS $lib" fi done # libsecp256k1 might not be available as static lib, so we'll try without it first # Initialize submodules if needed if [ ! -f "nostr_core_lib/libnostr_core_x64.a" ]; then echo "Building nostr_core_lib..." git submodule update --init --recursive cd nostr_core_lib && ./build.sh && cd .. fi # Install additional static libraries needed for libwebsockets echo "Installing additional static libraries..." sudo apt install -y libcap-dev libuv1-dev libev-dev # Build SQLite with JSON1 extension if not available echo "Building SQLite with JSON1 extension..." SQLITE_BUILD_DIR="/tmp/sqlite-build-$$" mkdir -p "$SQLITE_BUILD_DIR" cd "$SQLITE_BUILD_DIR" wget https://www.sqlite.org/2024/sqlite-autoconf-3460000.tar.gz tar xzf sqlite-autoconf-3460000.tar.gz cd sqlite-autoconf-3460000 ./configure \ --enable-static \ --disable-shared \ --enable-json1 \ --enable-fts5 \ --prefix="$SQLITE_BUILD_DIR/install" \ CFLAGS="-DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_FTS5=1" make && make install # Return to project directory cd "$SCRIPT_DIR" # Try building with regular gcc and static linking echo "Compiling with gcc -static..." # Use the same approach as the regular Makefile but with static linking gcc -static -O2 -Wall -Wextra -std=c99 -g \ -I. -Inostr_core_lib -Inostr_core_lib/nostr_core -Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \ -I"$SQLITE_BUILD_DIR/install/include" \ src/main.c src/config.c src/dm_admin.c src/request_validator.c src/nip009.c src/nip011.c src/nip013.c src/nip040.c src/nip042.c src/websockets.c src/subscriptions.c src/api.c src/embedded_web_content.c \ -o "$BUILD_DIR/c_relay_static_x86_64" \ nostr_core_lib/libnostr_core_x64.a \ "$SQLITE_BUILD_DIR/install/lib/libsqlite3.a" -lwebsockets -lz -ldl -lpthread -lm -L/usr/local/lib -lsecp256k1 -lssl -lcrypto -L/usr/local/lib -lcurl -lcap -luv_a -lev # Clean up SQLite build directory rm -rf "$SQLITE_BUILD_DIR" if [ $? -eq 0 ]; then echo "x86_64 static binary created: $BUILD_DIR/c_relay_static_x86_64" else echo "ERROR: Static build failed" echo "This may be due to missing static libraries or incompatible library versions" echo "Consider using Docker-based build instead" exit 1 fi fi # Verify binaries echo "Verifying static binaries..." for binary in "$BUILD_DIR"/c_relay_static_*; do if [ -f "$binary" ]; then echo "Binary: $(basename "$binary")" file "$binary" ls -lh "$binary" # Test if binary is truly static (no dynamic dependencies) if ldd "$binary" 2>/dev/null | grep -q "not a dynamic executable"; then echo "✓ Binary is fully static" elif ldd "$binary" 2>/dev/null | grep -q "statically linked"; then echo "✓ Binary is statically linked" else echo "⚠ Binary may have dynamic dependencies:" ldd "$binary" 2>/dev/null || echo " (ldd check failed)" fi echo "" fi done echo "Static build complete!" echo "Binaries available in: $BUILD_DIR/" ls -la "$BUILD_DIR"/c_relay_static_* 2>/dev/null || echo "No static binaries found" echo "" echo "These binaries should have minimal runtime dependencies and work across Linux distributions."