#!/usr/bin/env bash # ── scripts/fetch-libsodium.sh ────────────────────────────────────────────── # Download and build libsodium from source for the target platform. # Called automatically by CMake when the pre-built library is not found, # or manually before building: # # ./scripts/fetch-libsodium.sh # native (Linux/macOS) # ./scripts/fetch-libsodium.sh --mac # macOS cross-compile via osxcross # ./scripts/fetch-libsodium.sh --win # Windows cross-compile via MinGW # # Output: libs/libsodium/ (include/ + lib/libsodium.a) # ───────────────────────────────────────────────────────────────────────────── set -euo pipefail SODIUM_VERSION="1.0.18" SODIUM_SHA256="6f504490b342a4f8a4c4a02fc9b866cbef8622d5df4e5452b46be121e46636c1" SODIUM_URL="https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-${SODIUM_VERSION}.tar.gz" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" TARGET="native" while [[ $# -gt 0 ]]; do case $1 in --mac) TARGET="mac"; shift ;; --win) TARGET="win"; shift ;; *) echo "Unknown option: $1"; exit 1 ;; esac done # ── Output directories ────────────────────────────────────────────────────── case "$TARGET" in mac) INSTALL_DIR="$PROJECT_DIR/libs/libsodium-mac" ;; win) INSTALL_DIR="$PROJECT_DIR/libs/libsodium-win" ;; *) INSTALL_DIR="$PROJECT_DIR/libs/libsodium" ;; esac # Skip if already built if [[ -f "$INSTALL_DIR/lib/libsodium.a" ]]; then echo "[fetch-libsodium] Already present: $INSTALL_DIR/lib/libsodium.a" exit 0 fi # ── Download ──────────────────────────────────────────────────────────────── TARBALL="$PROJECT_DIR/libs/libsodium-${SODIUM_VERSION}.tar.gz" SRC_DIR="$PROJECT_DIR/libs/libsodium-${SODIUM_VERSION}" if [[ ! -f "$TARBALL" ]]; then echo "[fetch-libsodium] Downloading libsodium ${SODIUM_VERSION}..." curl -fSL -o "$TARBALL" "$SODIUM_URL" fi # Verify checksum (sha256sum on Linux, shasum on macOS) if command -v sha256sum &>/dev/null; then echo "$SODIUM_SHA256 $TARBALL" | sha256sum -c - || { echo "[fetch-libsodium] ERROR: SHA256 mismatch! Removing corrupted download." rm -f "$TARBALL" exit 1 } elif command -v shasum &>/dev/null; then echo "$SODIUM_SHA256 $TARBALL" | shasum -a 256 -c - || { echo "[fetch-libsodium] ERROR: SHA256 mismatch! Removing corrupted download." rm -f "$TARBALL" exit 1 } fi # ── Extract ───────────────────────────────────────────────────────────────── if [[ ! -d "$SRC_DIR" ]]; then echo "[fetch-libsodium] Extracting..." tar -xzf "$TARBALL" -C "$PROJECT_DIR/libs/" fi # ── Configure & build ─────────────────────────────────────────────────────── cd "$SRC_DIR" CONFIGURE_ARGS=( --prefix="$INSTALL_DIR" --disable-shared --enable-static --with-pic ) case "$TARGET" in mac) # Cross-compile for macOS via osxcross if [[ -z "${OSXCROSS:-}" ]]; then for try in "$PROJECT_DIR/external/osxcross" "$HOME/osxcross" "/opt/osxcross" "$PROJECT_DIR/osxcross"; do [[ -d "$try/target" ]] && OSXCROSS="$try" && break done fi if [[ -z "${OSXCROSS:-}" ]]; then echo "[fetch-libsodium] ERROR: osxcross not found. Set OSXCROSS=/path/to/osxcross" exit 1 fi export PATH="$OSXCROSS/target/bin:$PATH" # Detect osxcross triple TRIPLE=$(ls "$OSXCROSS/target/bin/" | grep -o 'x86_64-apple-darwin[0-9]*' | head -1) [[ -z "$TRIPLE" ]] && TRIPLE="x86_64-apple-darwin22" CONFIGURE_ARGS+=(--host="$TRIPLE") export CC="${TRIPLE}-cc" export CXX="${TRIPLE}-c++" export AR="${TRIPLE}-ar" export RANLIB="${TRIPLE}-ranlib" ;; win) # Cross-compile for Windows via MinGW CONFIGURE_ARGS+=(--host=x86_64-w64-mingw32) # Prefer the posix-thread variant if available if command -v x86_64-w64-mingw32-gcc-posix &>/dev/null; then export CC=x86_64-w64-mingw32-gcc-posix export CXX=x86_64-w64-mingw32-g++-posix else export CC=x86_64-w64-mingw32-gcc export CXX=x86_64-w64-mingw32-g++ fi export AR=x86_64-w64-mingw32-ar export RANLIB=x86_64-w64-mingw32-ranlib # Disable _FORTIFY_SOURCE — MinGW doesn't provide __memcpy_chk etc. export CFLAGS="${CFLAGS:-} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0" ;; esac # ── Native macOS: build universal binary (arm64 + x86_64) ─────────────────── IS_MACOS_NATIVE=false if [[ "$TARGET" == "native" && "$(uname -s)" == "Darwin" ]]; then IS_MACOS_NATIVE=true fi if $IS_MACOS_NATIVE; then echo "[fetch-libsodium] Building universal (arm64 + x86_64) for macOS..." export MACOSX_DEPLOYMENT_TARGET="11.0" INSTALL_ARM64="$PROJECT_DIR/libs/libsodium-arm64" INSTALL_X86_64="$PROJECT_DIR/libs/libsodium-x86_64" for ARCH in arm64 x86_64; do echo "[fetch-libsodium] Building for $ARCH..." cd "$SRC_DIR" make clean 2>/dev/null || true make distclean 2>/dev/null || true if [[ "$ARCH" == "arm64" ]]; then ARCH_INSTALL="$INSTALL_ARM64" HOST_TRIPLE="aarch64-apple-darwin" else ARCH_INSTALL="$INSTALL_X86_64" HOST_TRIPLE="x86_64-apple-darwin" fi ARCH_CFLAGS="-arch $ARCH -mmacosx-version-min=11.0" ./configure \ --prefix="$ARCH_INSTALL" \ --disable-shared \ --enable-static \ --with-pic \ --host="$HOST_TRIPLE" \ CFLAGS="$ARCH_CFLAGS" \ LDFLAGS="-arch $ARCH" \ > /dev/null make -j"$(sysctl -n hw.ncpu 2>/dev/null || echo 4)" > /dev/null 2>&1 make install > /dev/null done # Merge with lipo echo "[fetch-libsodium] Creating universal binary with lipo..." mkdir -p "$INSTALL_DIR/lib" "$INSTALL_DIR/include" lipo -create \ "$INSTALL_ARM64/lib/libsodium.a" \ "$INSTALL_X86_64/lib/libsodium.a" \ -output "$INSTALL_DIR/lib/libsodium.a" cp -R "$INSTALL_ARM64/include/"* "$INSTALL_DIR/include/" # Clean up per-arch builds rm -rf "$INSTALL_ARM64" "$INSTALL_X86_64" cd "$PROJECT_DIR" rm -rf "$SRC_DIR" rm -f "$TARBALL" echo "[fetch-libsodium] Done (universal): $INSTALL_DIR/lib/libsodium.a" lipo -info "$INSTALL_DIR/lib/libsodium.a" exit 0 fi echo "[fetch-libsodium] Configuring for target: $TARGET ..." ./configure "${CONFIGURE_ARGS[@]}" > /dev/null echo "[fetch-libsodium] Building..." make -j"$(nproc)" > /dev/null 2>&1 echo "[fetch-libsodium] Installing to $INSTALL_DIR ..." make install > /dev/null # ── Cleanup ───────────────────────────────────────────────────────────────── cd "$PROJECT_DIR" rm -rf "$SRC_DIR" rm -f "$TARBALL" echo "[fetch-libsodium] Done: $INSTALL_DIR/lib/libsodium.a"