#!/usr/bin/env bash # ── scripts/setup.sh ──────────────────────────────────────────────────────── # DragonX Wallet — Development Environment Setup # Copyright 2024-2026 The Hush Developers # Released under the GPLv3 # # Detects your OS/distro, installs build prerequisites, fetches libraries, # and validates the environment so you can build immediately with: # # ./build.sh # dev build # ./build.sh --win-release # Windows cross-compile # ./build.sh --linux-release # Linux release + AppImage # # Usage: # ./scripts/setup.sh # Interactive — install everything needed # ./scripts/setup.sh --check # Just report what's missing, don't install # ./scripts/setup.sh --all # Install dev + all cross-compile targets # ./scripts/setup.sh --win # Also install Windows cross-compile deps # ./scripts/setup.sh --mac # Also install macOS cross-compile deps # ./scripts/setup.sh --sapling # Also download Sapling params (~51 MB) # ───────────────────────────────────────────────────────────────────────────── set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" # ── Colours ────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' ok() { echo -e " ${GREEN}✓${NC} $1"; } miss() { echo -e " ${RED}✗${NC} $1"; } skip() { echo -e " ${YELLOW}—${NC} $1"; } info() { echo -e "${GREEN}[*]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1"; } err() { echo -e "${RED}[ERROR]${NC} $1"; } header(){ echo -e "\n${CYAN}── $1 ──${NC}"; } # ── Parse args ─────────────────────────────────────────────────────────────── CHECK_ONLY=false SETUP_WIN=false SETUP_MAC=false SETUP_SAPLING=false while [[ $# -gt 0 ]]; do case $1 in --check) CHECK_ONLY=true; shift ;; --win) SETUP_WIN=true; shift ;; --mac) SETUP_MAC=true; shift ;; --sapling) SETUP_SAPLING=true; shift ;; --all) SETUP_WIN=true; SETUP_MAC=true; SETUP_SAPLING=true; shift ;; -h|--help) sed -n '2,/^# ─\{10\}/{ /^# ─\{10\}/d; s/^# \?//p; }' "$0" exit 0 ;; *) err "Unknown option: $1"; exit 1 ;; esac done # ── Detect OS / distro ────────────────────────────────────────────────────── detect_os() { OS="$(uname -s)" DISTRO="unknown" PKG="" case "$OS" in Linux) if [[ -f /etc/os-release ]]; then . /etc/os-release case "${ID:-}" in ubuntu|debian|linuxmint|pop|elementary|zorin|neon) DISTRO="debian"; PKG="apt" ;; fedora|rhel|centos|rocky|alma) DISTRO="fedora"; PKG="dnf" ;; arch|manjaro|endeavouros|garuda) DISTRO="arch"; PKG="pacman" ;; opensuse*|suse*) DISTRO="suse"; PKG="zypper" ;; void) DISTRO="void"; PKG="xbps" ;; gentoo) DISTRO="gentoo"; PKG="emerge" ;; *) # Fallback: check for package managers command -v apt &>/dev/null && { DISTRO="debian"; PKG="apt"; } || command -v dnf &>/dev/null && { DISTRO="fedora"; PKG="dnf"; } || command -v pacman &>/dev/null && { DISTRO="arch"; PKG="pacman"; } ;; esac fi ;; Darwin) DISTRO="macos" command -v brew &>/dev/null && PKG="brew" ;; *) err "Unsupported OS: $OS" exit 1 ;; esac } # ── Package lists per distro ──────────────────────────────────────────────── # Core: minimum to do a dev build (Linux native) pkgs_core_debian="build-essential cmake git pkg-config libgl1-mesa-dev libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libxkbcommon-dev libwayland-dev libsodium-dev libcurl4-openssl-dev" pkgs_core_fedora="gcc gcc-c++ cmake git pkg-config mesa-libGL-devel libX11-devel libXcursor-devel libXrandr-devel libXinerama-devel libXi-devel libxkbcommon-devel wayland-devel libsodium-devel libcurl-devel" pkgs_core_arch="base-devel cmake git pkg-config mesa libx11 libxcursor libxrandr libxinerama libxi libxkbcommon wayland libsodium curl" pkgs_core_macos="cmake" # Windows cross-compile (from Linux) pkgs_win_debian="mingw-w64 zip" pkgs_win_fedora="mingw64-gcc mingw64-gcc-c++ zip" pkgs_win_arch="mingw-w64-gcc zip" # macOS cross-compile helpers (osxcross is separate) pkgs_mac_debian="genisoimage icnsutils" pkgs_mac_fedora="genisoimage" pkgs_mac_arch="cdrtools" # ── Helpers ────────────────────────────────────────────────────────────────── has_cmd() { command -v "$1" &>/dev/null; } # Install packages for the detected distro install_pkgs() { local pkgs="$1" local desc="$2" if $CHECK_ONLY; then warn "Would install ($desc): $pkgs" return fi info "Installing $desc packages..." case "$PKG" in apt) sudo apt-get update -qq && sudo apt-get install -y $pkgs ;; dnf) sudo dnf install -y $pkgs ;; pacman) sudo pacman -S --needed --noconfirm $pkgs ;; zypper) sudo zypper install -y $pkgs ;; brew) brew install $pkgs ;; *) err "No supported package manager found for $DISTRO" echo "Please install manually: $pkgs" return 1 ;; esac } # Select the right package list variable get_pkgs() { local category="$1" # core, win, mac local var="pkgs_${category}_${DISTRO}" echo "${!var:-}" } # ── Check individual tools ────────────────────────────────────────────────── MISSING=0 check_tool() { local cmd="$1" local label="${2:-$1}" if has_cmd "$cmd"; then ok "$label" else miss "$label (not found: $cmd)" MISSING=$((MISSING + 1)) fi } check_file() { local path="$1" local label="$2" if [[ -f "$path" ]]; then ok "$label" else miss "$label ($path)" MISSING=$((MISSING + 1)) fi } check_dir() { local path="$1" local label="$2" if [[ -d "$path" ]]; then ok "$label" else miss "$label ($path)" MISSING=$((MISSING + 1)) fi } # ═════════════════════════════════════════════════════════════════════════════ # MAIN # ═════════════════════════════════════════════════════════════════════════════ echo -e "${BOLD}DragonX Wallet — Development Setup${NC}" echo "═══════════════════════════════════" detect_os info "Detected: $OS / $DISTRO (package manager: ${PKG:-none})" # ── 1. Core build dependencies ────────────────────────────────────────────── header "Core Build Dependencies" core_pkgs="$(get_pkgs core)" if [[ -z "$core_pkgs" ]]; then warn "No package list for $DISTRO — check README for manual instructions" else # Check if key tools are already present NEED_CORE=false has_cmd cmake && has_cmd g++ && has_cmd pkg-config || NEED_CORE=true if $NEED_CORE; then install_pkgs "$core_pkgs" "core build" else ok "Core tools already installed (cmake, g++, pkg-config)" fi fi check_tool cmake "cmake" check_tool g++ "g++ (C++ compiler)" check_tool git "git" check_tool make "make" # ── 2. libsodium ──────────────────────────────────────────────────────────── header "libsodium" SODIUM_OK=false # Check system libsodium if pkg-config --exists libsodium 2>/dev/null; then ok "libsodium (system, $(pkg-config --modversion libsodium))" SODIUM_OK=true elif [[ -f "$PROJECT_DIR/libs/libsodium/lib/libsodium.a" ]]; then ok "libsodium (local build)" SODIUM_OK=true else miss "libsodium not found" if ! $CHECK_ONLY; then info "Building libsodium from source..." "$SCRIPT_DIR/fetch-libsodium.sh" && SODIUM_OK=true fi fi # ── 3. Windows cross-compile (optional) ───────────────────────────────────── header "Windows Cross-Compile" if $SETUP_WIN; then win_pkgs="$(get_pkgs win)" if [[ -n "$win_pkgs" ]]; then install_pkgs "$win_pkgs" "Windows cross-compile" fi # Set posix thread model if available if has_cmd update-alternatives && [[ "$PKG" == "apt" ]]; then if ! $CHECK_ONLY; then sudo update-alternatives --set x86_64-w64-mingw32-gcc \ /usr/bin/x86_64-w64-mingw32-gcc-posix 2>/dev/null || true sudo update-alternatives --set x86_64-w64-mingw32-g++ \ /usr/bin/x86_64-w64-mingw32-g++-posix 2>/dev/null || true fi fi # Fetch libsodium for Windows if [[ ! -f "$PROJECT_DIR/libs/libsodium-win/lib/libsodium.a" ]]; then if ! $CHECK_ONLY; then info "Building libsodium for Windows target..." "$SCRIPT_DIR/fetch-libsodium.sh" --win else miss "libsodium-win (not built yet)" fi else ok "libsodium-win" fi fi if has_cmd x86_64-w64-mingw32-g++-posix || has_cmd x86_64-w64-mingw32-g++; then ok "mingw-w64 ($(x86_64-w64-mingw32-g++-posix --version 2>/dev/null | head -1 || x86_64-w64-mingw32-g++ --version 2>/dev/null | head -1))" else if $SETUP_WIN; then miss "mingw-w64" else skip "mingw-w64 (use --win to install)" fi fi # ── 4. macOS cross-compile (optional) ─────────────────────────────────────── header "macOS Cross-Compile" if $SETUP_MAC; then mac_pkgs="$(get_pkgs mac)" if [[ -n "$mac_pkgs" ]]; then install_pkgs "$mac_pkgs" "macOS cross-compile helpers" fi # Fetch libsodium for macOS if [[ ! -f "$PROJECT_DIR/libs/libsodium-mac/lib/libsodium.a" ]]; then if ! $CHECK_ONLY; then info "Building libsodium for macOS target..." "$SCRIPT_DIR/fetch-libsodium.sh" --mac else miss "libsodium-mac (not built yet)" fi else ok "libsodium-mac" fi fi if [[ -d "$PROJECT_DIR/external/osxcross/target" ]] || [[ -d "${OSXCROSS:-}/target" ]]; then ok "osxcross" else if $SETUP_MAC; then miss "osxcross (must be set up manually — see README)" else skip "osxcross (use --mac to set up macOS deps)" fi fi # ── 5. Sapling parameters ─────────────────────────────────────────────────── header "Sapling Parameters" SAPLING_DIR="" for d in "$HOME/.zcash-params" "$HOME/.hush-params"; do if [[ -f "$d/sapling-spend.params" && -f "$d/sapling-output.params" ]]; then SAPLING_DIR="$d" break fi done # Also check project-local locations if [[ -z "$SAPLING_DIR" ]]; then for d in "$PROJECT_DIR/prebuilt-binaries/dragonxd-linux" "$PROJECT_DIR/prebuilt-binaries/dragonxd-win"; do if [[ -f "$d/sapling-spend.params" && -f "$d/sapling-output.params" ]]; then SAPLING_DIR="$d" break fi done fi if [[ -n "$SAPLING_DIR" ]]; then ok "sapling-spend.params ($(du -h "$SAPLING_DIR/sapling-spend.params" | cut -f1))" ok "sapling-output.params ($(du -h "$SAPLING_DIR/sapling-output.params" | cut -f1))" elif $SETUP_SAPLING; then if ! $CHECK_ONLY; then info "Downloading Sapling parameters (~51 MB)..." PARAMS_DIR="$HOME/.zcash-params" mkdir -p "$PARAMS_DIR" SPEND_URL="https://z.cash/downloads/sapling-spend.params" OUTPUT_URL="https://z.cash/downloads/sapling-output.params" curl -fSL -o "$PARAMS_DIR/sapling-spend.params" "$SPEND_URL" && \ ok "Downloaded sapling-spend.params" curl -fSL -o "$PARAMS_DIR/sapling-output.params" "$OUTPUT_URL" && \ ok "Downloaded sapling-output.params" fi else skip "Sapling params not found (use --sapling to download, or they'll be extracted at runtime from embedded builds)" fi # ── 6. Binary directories ─────────────────────────────────────────────────── header "Binary Directories" for platform in dragonxd-linux dragonxd-win dragonxd-mac xmrig; do dir="$PROJECT_DIR/prebuilt-binaries/$platform" if [[ -d "$dir" ]]; then # Count actual files (not .gitkeep) count=$(find "$dir" -maxdepth 1 -type f ! -name '.gitkeep' | wc -l) if [[ $count -gt 0 ]]; then ok "prebuilt-binaries/$platform/ ($count files)" else skip "prebuilt-binaries/$platform/ (empty — place binaries here)" fi else if ! $CHECK_ONLY; then mkdir -p "$dir" touch "$dir/.gitkeep" ok "Created prebuilt-binaries/$platform/" else miss "prebuilt-binaries/$platform/" fi fi done # ── Summary ────────────────────────────────────────────────────────────────── echo "" echo "═══════════════════════════════════════════" if [[ $MISSING -eq 0 ]]; then echo -e "${GREEN}${BOLD} Setup complete — ready to build!${NC}" echo "" echo " Quick start:" echo " ./build.sh # Dev build" echo " ./build.sh --linux-release # Linux release + AppImage" echo " ./build.sh --win-release # Windows cross-compile" else echo -e "${YELLOW}${BOLD} $MISSING item(s) still need attention${NC}" if $CHECK_ONLY; then echo "" echo " Run without --check to install automatically:" echo " ./scripts/setup.sh" echo " ./scripts/setup.sh --all # Include cross-compile + Sapling" fi fi echo "═══════════════════════════════════════════"