Files
nostr_terminal/build.sh

209 lines
5.3 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
# nt static-only builder (Docker + musl + ccache)
# Output: ./nt
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_status() { echo -e "${BLUE}[INFO]${NC} $1" >&2; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" >&2; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" >&2; }
print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOCKERFILE="$SCRIPT_DIR/Dockerfile.alpine-musl"
IMAGE_TAG="nt-static-builder:latest"
CCACHE_DIR_HOST="$SCRIPT_DIR/.ccache"
BUILD_WORK_DIR="$SCRIPT_DIR/.build-static"
TARGET_ARCH=""
show_usage() {
echo "nt static-only builder"
echo ""
echo "USAGE:"
echo " $0 [--arch <x86_64|arm64>] [--clean]"
echo ""
echo "OPTIONS:"
echo " --arch <arch> Target architecture: x86_64 or arm64"
echo " --clean Remove .build-static before build"
echo " -h, --help Show this help"
}
CLEAN=0
while [[ $# -gt 0 ]]; do
case "$1" in
--arch)
if [[ -z "${2:-}" ]]; then
print_error "--arch requires a value: x86_64 or arm64"
exit 1
fi
case "$2" in
x86_64|arm64)
TARGET_ARCH="$2"
;;
*)
print_error "Unsupported architecture '$2'"
print_error "Supported values: x86_64, arm64"
exit 1
;;
esac
shift 2
;;
--clean)
CLEAN=1
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
print_error "Unknown argument '$1'"
show_usage
exit 1
;;
esac
done
if ! command -v docker >/dev/null 2>&1; then
print_error "docker is required"
exit 1
fi
if ! docker info >/dev/null 2>&1; then
print_error "docker daemon is not running"
exit 1
fi
HOST_UNAME="$(uname -m)"
case "$HOST_UNAME" in
x86_64)
HOST_ARCH="x86_64"
;;
aarch64|arm64)
HOST_ARCH="arm64"
;;
*)
HOST_ARCH="unknown"
;;
esac
if [[ -z "$TARGET_ARCH" ]]; then
if [[ "$HOST_ARCH" == "unknown" ]]; then
TARGET_ARCH="x86_64"
print_warning "Unknown host architecture '$HOST_UNAME'; defaulting target arch to x86_64"
else
TARGET_ARCH="$HOST_ARCH"
fi
fi
case "$TARGET_ARCH" in
x86_64)
PLATFORM="linux/amd64"
;;
arm64)
PLATFORM="linux/arm64"
;;
*)
print_error "Unsupported target architecture '$TARGET_ARCH'"
exit 1
;;
esac
if [[ "$CLEAN" -eq 1 ]]; then
print_status "Cleaning $BUILD_WORK_DIR"
rm -rf "$BUILD_WORK_DIR" 2>/dev/null || true
docker run --rm \
--platform "$PLATFORM" \
-v "$SCRIPT_DIR:/work" \
alpine:3.19 \
/bin/sh -lc 'rm -rf /work/.build-static'
fi
mkdir -p "$CCACHE_DIR_HOST" "$BUILD_WORK_DIR"
docker run --rm \
--platform "$PLATFORM" \
-v "$CCACHE_DIR_HOST:/ccache" \
alpine:3.19 \
/bin/sh -lc "chown -R $(id -u):$(id -g) /ccache 2>/dev/null || true; chmod -R u+rwX /ccache 2>/dev/null || true; mkdir -p /ccache/tmp"
print_status "Building/updating builder image: $IMAGE_TAG"
docker build --platform "$PLATFORM" -f "$DOCKERFILE" -t "$IMAGE_TAG" "$SCRIPT_DIR" >/dev/null
print_status "Compiling static nt inside container ($PLATFORM) with ccache"
docker run --rm \
--platform "$PLATFORM" \
--user "$(id -u):$(id -g)" \
-v "$SCRIPT_DIR:/work" \
-v "$CCACHE_DIR_HOST:/ccache" \
-w /work \
-e CCACHE_DIR=/ccache \
"$IMAGE_TAG" \
/bin/bash -lc '
set -euo pipefail
mkdir -p .build-static/obj
CFLAGS_BASE="-std=c99 -O2 -Wall -Wextra -D_GNU_SOURCE -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0"
INCLUDES="-Iinclude -Iresources/nostr_core_lib -Iresources/nostr_core_lib/nostr_core -Iresources/nostr_core_lib/nostr_websocket -Iresources/nostr_core_lib/cjson -Iresources/tui_ncurses"
CFLAGS="$CFLAGS_BASE $INCLUDES"
mapfile -t SOURCES < <(
{
find src -name "*.c" -print
echo resources/tui_ncurses/tui_ncurses.c
find resources/nostr_core_lib/nostr_core -name "*.c" -print
find resources/nostr_core_lib/nostr_core/crypto -name "*.c" -print
echo resources/nostr_core_lib/nostr_websocket/nostr_websocket_openssl.c
echo resources/nostr_core_lib/platform/linux.c
echo resources/nostr_core_lib/cjson/cJSON.c
} | sort -u
)
for src in "${SOURCES[@]}"; do
obj=".build-static/obj/${src}.o"
mkdir -p "$(dirname "$obj")"
ccache gcc $CFLAGS -c "$src" -o "$obj"
done
CURL_LDFLAGS="$(pkg-config --libs --static libcurl)"
OBJS=$(find .build-static/obj -name "*.o" -print | sort)
gcc -static -o nt $OBJS \
$CURL_LDFLAGS \
-lsqlite3 -lncursesw -lsecp256k1 -lssl -lcrypto -lpthread -lm -lz -ldl
strip nt || true
'
print_status "Verifying ./nt static linkage"
if [[ ! -x "$SCRIPT_DIR/nt" ]]; then
print_error "Build failed: ./nt missing"
exit 1
fi
FILE_OUTPUT="$(file "$SCRIPT_DIR/nt" 2>&1 || true)"
LDD_OUTPUT="$(ldd "$SCRIPT_DIR/nt" 2>&1 || true)"
echo "$FILE_OUTPUT" >&2
echo "$LDD_OUTPUT" >&2
if echo "$LDD_OUTPUT" | grep -Eq "not a dynamic executable|statically linked" || echo "$FILE_OUTPUT" | grep -q "statically linked"; then
print_success "Static binary ready: $SCRIPT_DIR/nt"
else
print_error "./nt does not appear fully static"
exit 1
fi
print_status "ccache stats"
docker run --rm \
--platform "$PLATFORM" \
-v "$CCACHE_DIR_HOST:/ccache" \
-e CCACHE_DIR=/ccache \
"$IMAGE_TAG" /bin/bash -lc 'ccache -s' >&2 || true