Full-node GUI wallet for DragonX cryptocurrency. Built with Dear ImGui, SDL3, and OpenGL3/DX11. Features: - Send/receive shielded and transparent transactions - Autoshield with merged transaction display - Built-in CPU mining (xmrig) - Peer management and network monitoring - Wallet encryption with PIN lock - QR code generation for receive addresses - Transaction history with pagination - Console for direct RPC commands - Cross-platform (Linux, Windows)
1050 lines
46 KiB
Bash
Executable File
1050 lines
46 KiB
Bash
Executable File
#!/bin/bash
|
|
# DragonX ImGui Wallet - Unified Build Script
|
|
# Copyright 2024-2026 The Hush Developers
|
|
# Released under the GPLv3
|
|
#
|
|
# Usage:
|
|
# ./build.sh # Dev build (Linux, debug-friendly)
|
|
# ./build.sh --linux-release # Linux release + AppImage
|
|
# ./build.sh --win-release # Windows cross-compile (mingw-w64)
|
|
# ./build.sh --mac-release # macOS .app bundle + DMG
|
|
# ./build.sh --linux-release --win-release # Multiple targets
|
|
# ./build.sh --clean --win-release # Clean first, then build
|
|
#
|
|
# Prerequisites:
|
|
# Linux: cmake, g++, libsdl3-dev (or fetched), libsodium-dev
|
|
# Windows: mingw-w64 (posix threads), cmake
|
|
# macOS (native): Xcode CLT, cmake, create-dmg (brew install create-dmg)
|
|
# macOS (cross from Linux): osxcross + macOS SDK, genisoimage, icnsutils
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
VERSION="1.0.0"
|
|
|
|
# ── Colours ──────────────────────────────────────────────────────────────────
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
info() { echo -e "${GREEN}[*]${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
|
err() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
header(){ echo -e "\n${CYAN}══════════════════════════════════════════════════════════${NC}"; echo -e "${CYAN} $1${NC}"; echo -e "${CYAN}══════════════════════════════════════════════════════════${NC}"; }
|
|
|
|
JOBS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
|
|
|
# ── Defaults ─────────────────────────────────────────────────────────────────
|
|
DO_DEV=false
|
|
DO_LINUX=false
|
|
DO_WIN=false
|
|
DO_MAC=false
|
|
CLEAN=false
|
|
BUILD_TYPE="Release"
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
DragonX Wallet — Unified Build Script
|
|
|
|
Usage: $0 [options]
|
|
|
|
Targets (at least one required, or none for dev build):
|
|
--linux-release Linux release build + AppImage -> release/linux/
|
|
--win-release Windows cross-compile (mingw-w64) -> release/windows/
|
|
--mac-release macOS .app bundle + DMG -> release/mac/
|
|
|
|
Build trees are stored under build/{linux,windows,mac}/
|
|
|
|
Options:
|
|
-c, --clean Remove build artifacts before building
|
|
-d, --debug Use Debug build type instead of Release
|
|
-j N Parallel jobs (default: $JOBS)
|
|
-h, --help Show this help
|
|
|
|
Cross-compiling from Linux:
|
|
Windows: sudo apt install mingw-w64
|
|
macOS: Requires osxcross (https://github.com/tpoechtrager/osxcross)
|
|
export OSXCROSS=/path/to/osxcross
|
|
sudo apt install genisoimage icnsutils # DMG + icon tools
|
|
|
|
Examples:
|
|
$0 # Quick dev build (Linux)
|
|
$0 --linux-release # Linux release + AppImage
|
|
$0 --win-release # Windows cross-compile
|
|
$0 --mac-release # macOS bundle + DMG (native or osxcross)
|
|
$0 --clean --linux-release --win-release # Clean + both
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
# ── Parse args ───────────────────────────────────────────────────────────────
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--linux-release) DO_LINUX=true; shift ;;
|
|
--win-release) DO_WIN=true; shift ;;
|
|
--mac-release) DO_MAC=true; shift ;;
|
|
-c|--clean) CLEAN=true; shift ;;
|
|
-d|--debug) BUILD_TYPE="Debug"; shift ;;
|
|
-j) JOBS="$2"; shift 2 ;;
|
|
-h|--help) usage ;;
|
|
*) err "Unknown option: $1"; usage ;;
|
|
esac
|
|
done
|
|
|
|
# No release target → dev build (native, no packaging)
|
|
if ! $DO_LINUX && ! $DO_WIN && ! $DO_MAC; then
|
|
DO_DEV=true
|
|
fi
|
|
|
|
# ── Helper: find resource files ──────────────────────────────────────────────
|
|
find_sapling_params() {
|
|
local dirs=(
|
|
"$HOME/.zcash-params"
|
|
"$HOME/.hush-params"
|
|
"$SCRIPT_DIR/../SilentDragonX"
|
|
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
|
|
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-linux"
|
|
"$SCRIPT_DIR"
|
|
)
|
|
for d in "${dirs[@]}"; do
|
|
if [[ -f "$d/sapling-spend.params" && -f "$d/sapling-output.params" ]]; then
|
|
SAPLING_SPEND="$d/sapling-spend.params"
|
|
SAPLING_OUTPUT="$d/sapling-output.params"
|
|
info "Found Sapling params in $d"
|
|
return 0
|
|
fi
|
|
done
|
|
warn "Sapling params not found — embedded resources will be unavailable"
|
|
return 1
|
|
}
|
|
|
|
find_asmap() {
|
|
local paths=(
|
|
"$SCRIPT_DIR/external/hush3/asmap.dat"
|
|
"$SCRIPT_DIR/external/hush3/contrib/asmap/asmap.dat"
|
|
"$HOME/hush3/asmap.dat"
|
|
"$HOME/hush3/contrib/asmap/asmap.dat"
|
|
"$SCRIPT_DIR/../asmap.dat"
|
|
"$SCRIPT_DIR/asmap.dat"
|
|
"$SCRIPT_DIR/../SilentDragonX/asmap.dat"
|
|
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-linux/asmap.dat"
|
|
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-win/asmap.dat"
|
|
)
|
|
for p in "${paths[@]}"; do
|
|
if [[ -f "$p" ]]; then
|
|
ASMAP_DAT="$p"
|
|
info "Found asmap.dat at $p"
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# ── Helper: bundle daemon binaries into a target dir ─────────────────────────
|
|
bundle_linux_daemon() {
|
|
local dest="$1"
|
|
local found=0
|
|
|
|
local launcher_paths=(
|
|
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-linux/hush-arrakis-chain"
|
|
"$SCRIPT_DIR/../hush-arrakis-chain"
|
|
"$SCRIPT_DIR/external/hush3/src/hush-arrakis-chain"
|
|
"$HOME/hush3/src/hush-arrakis-chain"
|
|
)
|
|
for p in "${launcher_paths[@]}"; do
|
|
if [[ -f "$p" ]]; then
|
|
cp "$p" "$dest/hush-arrakis-chain"; chmod +x "$dest/hush-arrakis-chain"
|
|
info " Bundled hush-arrakis-chain"; found=1; break
|
|
fi
|
|
done
|
|
|
|
local hushd_paths=(
|
|
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-linux/hushd"
|
|
"$SCRIPT_DIR/../hushd"
|
|
"$SCRIPT_DIR/external/hush3/src/hushd"
|
|
"$HOME/hush3/src/hushd"
|
|
)
|
|
for p in "${hushd_paths[@]}"; do
|
|
if [[ -f "$p" ]]; then
|
|
cp "$p" "$dest/hushd"; chmod +x "$dest/hushd"
|
|
info " Bundled hushd"; break
|
|
fi
|
|
done
|
|
|
|
local dragonxd_paths=(
|
|
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-linux/dragonxd"
|
|
"$SCRIPT_DIR/../dragonxd"
|
|
"$SCRIPT_DIR/external/hush3/src/dragonxd"
|
|
"$HOME/hush3/src/dragonxd"
|
|
)
|
|
for p in "${dragonxd_paths[@]}"; do
|
|
if [[ -f "$p" ]]; then
|
|
cp "$p" "$dest/dragonxd"; chmod +x "$dest/dragonxd"
|
|
info " Bundled dragonxd"; break
|
|
fi
|
|
done
|
|
|
|
# asmap.dat
|
|
find_asmap && cp "$ASMAP_DAT" "$dest/asmap.dat" && info " Bundled asmap.dat"
|
|
|
|
return $found
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
# DEV BUILD (native, no packaging)
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
build_dev() {
|
|
header "Dev Build ($(uname -s) / $BUILD_TYPE)"
|
|
local bd="$SCRIPT_DIR/build/linux"
|
|
|
|
if $CLEAN; then
|
|
info "Cleaning $bd ..."; rm -rf "$bd"
|
|
fi
|
|
mkdir -p "$bd" && cd "$bd"
|
|
|
|
info "Configuring ..."
|
|
cmake "$SCRIPT_DIR" \
|
|
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
|
-DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG" \
|
|
-DDRAGONX_USE_SYSTEM_SDL3=ON
|
|
|
|
info "Building with $JOBS jobs ..."
|
|
cmake --build . -j "$JOBS"
|
|
|
|
[[ -f "bin/ObsidianDragon" ]] || { err "Build failed"; exit 1; }
|
|
info "Dev binary: $bd/bin/ObsidianDragon ($(du -h bin/ObsidianDragon | cut -f1))"
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
# RELEASE: LINUX — build + strip + bundle daemon + AppImage
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
build_release_linux() {
|
|
header "Release: Linux x86_64"
|
|
local bd="$SCRIPT_DIR/build/linux"
|
|
local out="$SCRIPT_DIR/release/linux"
|
|
|
|
if $CLEAN; then
|
|
info "Cleaning $bd ..."; rm -rf "$bd"
|
|
fi
|
|
mkdir -p "$bd" && cd "$bd"
|
|
|
|
# ── Compile ──────────────────────────────────────────────────────────────
|
|
info "Configuring ..."
|
|
cmake "$SCRIPT_DIR" \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG" \
|
|
-DDRAGONX_USE_SYSTEM_SDL3=ON
|
|
|
|
info "Building with $JOBS jobs ..."
|
|
cmake --build . -j "$JOBS"
|
|
|
|
[[ -f "bin/ObsidianDragon" ]] || { err "Linux build failed"; exit 1; }
|
|
|
|
info "Stripping ..."
|
|
strip bin/ObsidianDragon
|
|
info "Binary: $(du -h bin/ObsidianDragon | cut -f1)"
|
|
|
|
# ── Bundle daemon ────────────────────────────────────────────────────────
|
|
bundle_linux_daemon "bin" || warn "Daemon not bundled — wallet-only build"
|
|
|
|
# ── Package: release/linux/ ──────────────────────────────────────────────
|
|
rm -rf "$out"
|
|
mkdir -p "$out"
|
|
|
|
cp bin/ObsidianDragon "$out/"
|
|
[[ -f bin/hush-arrakis-chain ]] && cp bin/hush-arrakis-chain "$out/"
|
|
[[ -f bin/hushd ]] && cp bin/hushd "$out/"
|
|
[[ -f bin/dragonxd ]] && cp bin/dragonxd "$out/"
|
|
[[ -f bin/asmap.dat ]] && cp bin/asmap.dat "$out/"
|
|
cp -r bin/res "$out/" 2>/dev/null || true
|
|
|
|
# ── AppImage ─────────────────────────────────────────────────────────────
|
|
info "Creating AppImage ..."
|
|
local APPDIR="$bd/AppDir"
|
|
rm -rf "$APPDIR"
|
|
mkdir -p "$APPDIR/usr/bin" "$APPDIR/usr/lib" \
|
|
"$APPDIR/usr/share/applications" \
|
|
"$APPDIR/usr/share/icons/hicolor/256x256/apps" \
|
|
"$APPDIR/usr/share/ObsidianDragon/res"
|
|
|
|
cp bin/ObsidianDragon "$APPDIR/usr/bin/"
|
|
cp -r bin/res/* "$APPDIR/usr/share/ObsidianDragon/res/" 2>/dev/null || true
|
|
|
|
# Daemon inside AppImage
|
|
[[ -f bin/hush-arrakis-chain ]] && cp bin/hush-arrakis-chain "$APPDIR/usr/bin/"
|
|
[[ -f bin/hushd ]] && cp bin/hushd "$APPDIR/usr/bin/"
|
|
[[ -f bin/dragonxd ]] && cp bin/dragonxd "$APPDIR/usr/bin/"
|
|
[[ -f bin/asmap.dat ]] && cp bin/asmap.dat "$APPDIR/usr/share/ObsidianDragon/"
|
|
|
|
# Desktop entry
|
|
cat > "$APPDIR/usr/share/applications/ObsidianDragon.desktop" <<'DESK'
|
|
[Desktop Entry]
|
|
Type=Application
|
|
Name=DragonX Wallet
|
|
Comment=DragonX Cryptocurrency Wallet
|
|
Exec=ObsidianDragon
|
|
Icon=ObsidianDragon
|
|
Categories=Finance;Network;
|
|
Terminal=false
|
|
StartupNotify=true
|
|
DESK
|
|
cp "$APPDIR/usr/share/applications/ObsidianDragon.desktop" "$APPDIR/"
|
|
|
|
# Icon
|
|
if [[ -f "$SCRIPT_DIR/res/icons/dragonx-256.png" ]]; then
|
|
cp "$SCRIPT_DIR/res/icons/dragonx-256.png" \
|
|
"$APPDIR/usr/share/icons/hicolor/256x256/apps/ObsidianDragon.png"
|
|
else
|
|
cat > "$APPDIR/ObsidianDragon.svg" <<'SVG'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<svg width="256" height="256" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
|
<rect width="256" height="256" rx="32" fill="#1a1a1a"/>
|
|
<circle cx="128" cy="128" r="80" fill="none" stroke="#2e7d32" stroke-width="8"/>
|
|
<text x="128" y="145" font-family="Arial,sans-serif" font-size="72" font-weight="bold"
|
|
fill="#4caf50" text-anchor="middle">DX</text>
|
|
</svg>
|
|
SVG
|
|
if command -v rsvg-convert &>/dev/null; then
|
|
rsvg-convert -w 256 -h 256 "$APPDIR/ObsidianDragon.svg" > \
|
|
"$APPDIR/usr/share/icons/hicolor/256x256/apps/ObsidianDragon.png"
|
|
fi
|
|
fi
|
|
cp "$APPDIR/usr/share/icons/hicolor/256x256/apps/ObsidianDragon.png" "$APPDIR/" 2>/dev/null || \
|
|
cp "$APPDIR/ObsidianDragon.svg" "$APPDIR/ObsidianDragon.png" 2>/dev/null || true
|
|
|
|
# AppRun
|
|
cat > "$APPDIR/AppRun" <<'APPRUN'
|
|
#!/bin/bash
|
|
SELF=$(readlink -f "$0")
|
|
HERE=${SELF%/*}
|
|
export DRAGONX_RES_PATH="${HERE}/usr/share/ObsidianDragon/res"
|
|
export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH}"
|
|
cd "${HERE}/usr/share/ObsidianDragon"
|
|
exec "${HERE}/usr/bin/ObsidianDragon" "$@"
|
|
APPRUN
|
|
chmod +x "$APPDIR/AppRun"
|
|
|
|
# Bundle SDL3
|
|
for lib in libSDL3.so; do
|
|
local lp
|
|
lp=$(ldconfig -p 2>/dev/null | grep "$lib" | head -1 | awk '{print $NF}')
|
|
[[ -n "$lp" && -f "$lp" ]] && cp "$lp" "$APPDIR/usr/lib/" 2>/dev/null || true
|
|
done
|
|
[[ -f "$bd/_deps/sdl3-build/libSDL3.so" ]] && cp "$bd/_deps/sdl3-build/libSDL3.so"* "$APPDIR/usr/lib/" 2>/dev/null || true
|
|
|
|
# appimagetool
|
|
local APPIMAGETOOL=""
|
|
if command -v appimagetool &>/dev/null; then
|
|
APPIMAGETOOL="appimagetool"
|
|
elif [[ -f "$bd/appimagetool-x86_64.AppImage" ]]; then
|
|
APPIMAGETOOL="$bd/appimagetool-x86_64.AppImage"
|
|
else
|
|
info "Downloading appimagetool ..."
|
|
wget -q -O "$bd/appimagetool-x86_64.AppImage" \
|
|
"https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
|
|
chmod +x "$bd/appimagetool-x86_64.AppImage"
|
|
APPIMAGETOOL="$bd/appimagetool-x86_64.AppImage"
|
|
fi
|
|
|
|
local ARCH
|
|
ARCH=$(uname -m)
|
|
local IMG_NAME="DragonX_Wallet-${VERSION}-${ARCH}.AppImage"
|
|
cd "$bd"
|
|
ARCH="$ARCH" "$APPIMAGETOOL" "$APPDIR" "$IMG_NAME" 2>/dev/null && {
|
|
cp "$IMG_NAME" "$out/"
|
|
info "AppImage: $out/$IMG_NAME ($(du -h "$IMG_NAME" | cut -f1))"
|
|
} || warn "AppImage creation failed (appimagetool issue) — raw binary still in release/linux/"
|
|
|
|
# Clean up: keep only AppImage + raw binary in release/linux/
|
|
if ls "$out"/*.AppImage 1>/dev/null 2>&1; then
|
|
# AppImage succeeded — remove everything except AppImage and the binary
|
|
find "$out" -maxdepth 1 -type f ! -name '*.AppImage' ! -name 'ObsidianDragon' -delete
|
|
rm -rf "$out/res" 2>/dev/null
|
|
fi
|
|
|
|
info "Linux release artifacts: $out/"
|
|
ls -lh "$out/"
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
# RELEASE: WINDOWS — mingw-w64 cross-compile + INCBIN embedding
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
build_release_win() {
|
|
header "Release: Windows x86_64 (cross-compile)"
|
|
local bd="$SCRIPT_DIR/build/windows"
|
|
local out="$SCRIPT_DIR/release/windows"
|
|
|
|
if $CLEAN; then
|
|
info "Cleaning $bd ..."; rm -rf "$bd"
|
|
fi
|
|
mkdir -p "$bd" && cd "$bd"
|
|
|
|
# ── Find MinGW ───────────────────────────────────────────────────────────
|
|
local MINGW_GCC="" MINGW_GXX=""
|
|
if command -v x86_64-w64-mingw32-gcc-posix &>/dev/null; then
|
|
MINGW_GCC="x86_64-w64-mingw32-gcc-posix"
|
|
MINGW_GXX="x86_64-w64-mingw32-g++-posix"
|
|
info "Using POSIX thread model"
|
|
elif command -v x86_64-w64-mingw32-gcc &>/dev/null; then
|
|
MINGW_GCC="x86_64-w64-mingw32-gcc"
|
|
MINGW_GXX="x86_64-w64-mingw32-g++"
|
|
if x86_64-w64-mingw32-gcc -v 2>&1 | grep -q "posix"; then
|
|
info "Using POSIX thread model"
|
|
else
|
|
warn "Using win32 thread model — may have threading issues"
|
|
warn "Switch: sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix"
|
|
fi
|
|
else
|
|
err "mingw-w64 not found! Install: sudo apt install mingw-w64"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Toolchain file ───────────────────────────────────────────────────────
|
|
cat > "$bd/mingw-toolchain.cmake" <<TOOLCHAIN
|
|
set(CMAKE_SYSTEM_NAME Windows)
|
|
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
|
set(CMAKE_C_COMPILER $MINGW_GCC)
|
|
set(CMAKE_CXX_COMPILER $MINGW_GXX)
|
|
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
|
|
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|
set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive")
|
|
set(CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} -static")
|
|
set(CMAKE_C_FLAGS "\${CMAKE_C_FLAGS} -static")
|
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
|
set(BUILD_SHARED_LIBS OFF)
|
|
TOOLCHAIN
|
|
|
|
# ── INCBIN embedded resources ────────────────────────────────────────────
|
|
info "Generating embedded resources (INCBIN) ..."
|
|
local GEN="$bd/generated"
|
|
local RES="$GEN/res"
|
|
mkdir -p "$RES"
|
|
|
|
SAPLING_SPEND="" SAPLING_OUTPUT="" ASMAP_DAT=""
|
|
find_sapling_params || true
|
|
find_asmap || true
|
|
|
|
if [[ -n "$SAPLING_SPEND" && -n "$SAPLING_OUTPUT" ]]; then
|
|
cp -f "$SAPLING_SPEND" "$RES/sapling-spend.params"
|
|
cp -f "$SAPLING_OUTPUT" "$RES/sapling-output.params"
|
|
|
|
cat > "$GEN/embedded_data.h" <<HDR
|
|
// Auto-generated — DO NOT EDIT (build.sh --win-release)
|
|
#pragma once
|
|
#include <cstdint>
|
|
#include <cstddef>
|
|
#include "incbin.h"
|
|
|
|
INCBIN(sapling_spend_params, "$RES/sapling-spend.params");
|
|
INCBIN(sapling_output_params, "$RES/sapling-output.params");
|
|
HDR
|
|
|
|
if [[ -n "$ASMAP_DAT" ]]; then
|
|
cp -f "$ASMAP_DAT" "$RES/asmap.dat"
|
|
echo "INCBIN(asmap_dat, \"$RES/asmap.dat\");" >> "$GEN/embedded_data.h"
|
|
else
|
|
echo 'extern "C" { static const uint8_t* g_asmap_dat_data = nullptr; }' >> "$GEN/embedded_data.h"
|
|
echo 'static const unsigned int g_asmap_dat_size = 0;' >> "$GEN/embedded_data.h"
|
|
fi
|
|
|
|
# ── Daemon binaries ──────────────────────────────────────────────
|
|
local DD="$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
|
|
if [[ -d "$DD" && -f "$DD/hushd.exe" ]]; then
|
|
info "Embedding daemon binaries ..."
|
|
echo -e "\n#define HAS_EMBEDDED_DAEMON 1\n" >> "$GEN/embedded_data.h"
|
|
for f in hushd.exe hush-cli.exe hush-tx.exe dragonxd.bat dragonx-cli.bat; do
|
|
local sym=$(echo "$f" | sed 's/[^a-zA-Z0-9]/_/g')
|
|
if [[ -f "$DD/$f" ]]; then
|
|
cp -f "$DD/$f" "$RES/$f"
|
|
info " Staged $f ($(du -h "$DD/$f" | cut -f1))"
|
|
echo "INCBIN(${sym}, \"$RES/$f\");" >> "$GEN/embedded_data.h"
|
|
else
|
|
echo "extern \"C\" { static const uint8_t* g_${sym}_data = nullptr; }" >> "$GEN/embedded_data.h"
|
|
echo "static const unsigned int g_${sym}_size = 0;" >> "$GEN/embedded_data.h"
|
|
fi
|
|
done
|
|
else
|
|
warn "prebuilt-binaries/dragonxd-win/ not found — wallet-only build"
|
|
fi
|
|
|
|
# ── xmrig binary (from prebuilt-binaries/xmrig-hac/) ────────────────
|
|
local XMRIG_DIR="$SCRIPT_DIR/prebuilt-binaries/xmrig-hac"
|
|
if [[ -f "$XMRIG_DIR/xmrig.exe" ]]; then
|
|
cp -f "$XMRIG_DIR/xmrig.exe" "$RES/xmrig.exe"
|
|
info " Staged xmrig.exe ($(du -h "$XMRIG_DIR/xmrig.exe" | cut -f1))"
|
|
echo -e "\n#define HAS_EMBEDDED_XMRIG 1" >> "$GEN/embedded_data.h"
|
|
echo "INCBIN(xmrig_exe, \"$RES/xmrig.exe\");" >> "$GEN/embedded_data.h"
|
|
else
|
|
echo 'extern "C" { static const uint8_t* g_xmrig_exe_data = nullptr; }' >> "$GEN/embedded_data.h"
|
|
echo 'static const unsigned int g_xmrig_exe_size = 0;' >> "$GEN/embedded_data.h"
|
|
fi
|
|
|
|
# ── Theme images ─────────────────────────────────────────────────
|
|
echo -e "\n// ---- Embedded theme images ----" >> "$GEN/embedded_data.h"
|
|
local IMAGE_TABLE="" IMAGE_COUNT=0
|
|
for dir in "$SCRIPT_DIR/res/img/backgrounds/texture" "$SCRIPT_DIR/res/img/backgrounds/gradient" "$SCRIPT_DIR/res/img/logos"; do
|
|
[[ -d "$dir" ]] || continue
|
|
for img in "$dir"/*.png; do
|
|
[[ -f "$img" ]] || continue
|
|
local bn=$(basename "$img")
|
|
local sym=$(echo "$bn" | sed 's/[^a-zA-Z0-9]/_/g')
|
|
cp -f "$img" "$RES/$bn"
|
|
echo "INCBIN(img_${sym}, \"$RES/$bn\");" >> "$GEN/embedded_data.h"
|
|
IMAGE_TABLE+=" { g_img_${sym}_data, g_img_${sym}_size, \"${bn}\" },\n"
|
|
IMAGE_COUNT=$((IMAGE_COUNT + 1))
|
|
done
|
|
done
|
|
echo "" >> "$GEN/embedded_data.h"
|
|
echo "#define HAS_EMBEDDED_IMAGES 1" >> "$GEN/embedded_data.h"
|
|
echo "#define EMBEDDED_IMAGE_COUNT $IMAGE_COUNT" >> "$GEN/embedded_data.h"
|
|
echo "#define HAS_EMBEDDED_GRADIENT 1" >> "$GEN/embedded_data.h"
|
|
echo "#define HAS_EMBEDDED_LOGO 1" >> "$GEN/embedded_data.h"
|
|
# Backward compat aliases
|
|
echo "static const uint8_t* g_dark_gradient_png_data = g_img_dark_gradient_png_data;" >> "$GEN/embedded_data.h"
|
|
echo "static const unsigned int g_dark_gradient_png_size = g_img_dark_gradient_png_size;" >> "$GEN/embedded_data.h"
|
|
echo "static const uint8_t* g_logo_ObsidianDragon_dark_png_data = g_img_logo_ObsidianDragon_dark_png_data;" >> "$GEN/embedded_data.h"
|
|
echo "static const unsigned int g_logo_ObsidianDragon_dark_png_size = g_img_logo_ObsidianDragon_dark_png_size;" >> "$GEN/embedded_data.h"
|
|
echo "" >> "$GEN/embedded_data.h"
|
|
echo "struct EmbeddedImageEntry { const uint8_t* data; unsigned int size; const char* filename; };" >> "$GEN/embedded_data.h"
|
|
echo "static const EmbeddedImageEntry s_embedded_images[] = {" >> "$GEN/embedded_data.h"
|
|
echo -e "$IMAGE_TABLE" >> "$GEN/embedded_data.h"
|
|
echo " { nullptr, 0, nullptr }" >> "$GEN/embedded_data.h"
|
|
echo "};" >> "$GEN/embedded_data.h"
|
|
|
|
# ── Overlay themes ───────────────────────────────────────────────
|
|
echo -e "\n// ---- Bundled overlay themes ----" >> "$GEN/embedded_data.h"
|
|
local THEME_TABLE="" THEME_COUNT=0
|
|
for tf in "$SCRIPT_DIR/res/themes"/*.toml; do
|
|
local tbn=$(basename "$tf")
|
|
[[ "$tbn" == "ui.toml" ]] && continue
|
|
local tsym=$(echo "$tbn" | sed 's/[^a-zA-Z0-9]/_/g')
|
|
cp -f "$tf" "$RES/$tbn"
|
|
echo "INCBIN(theme_${tsym}, \"$RES/$tbn\");" >> "$GEN/embedded_data.h"
|
|
THEME_TABLE+=" { g_theme_${tsym}_data, g_theme_${tsym}_size, \"${tbn}\" },\n"
|
|
THEME_COUNT=$((THEME_COUNT + 1))
|
|
done
|
|
echo "" >> "$GEN/embedded_data.h"
|
|
echo "#define EMBEDDED_THEME_COUNT $THEME_COUNT" >> "$GEN/embedded_data.h"
|
|
echo "struct EmbeddedThemeEntry { const uint8_t* data; unsigned int size; const char* filename; };" >> "$GEN/embedded_data.h"
|
|
echo "static const EmbeddedThemeEntry s_embedded_themes[] = {" >> "$GEN/embedded_data.h"
|
|
echo -e "$THEME_TABLE" >> "$GEN/embedded_data.h"
|
|
echo " { nullptr, 0, nullptr }" >> "$GEN/embedded_data.h"
|
|
echo "};" >> "$GEN/embedded_data.h"
|
|
|
|
info "Embedded resources header generated"
|
|
else
|
|
warn "Building WITHOUT embedded resources (Sapling params not found)"
|
|
fi
|
|
|
|
# ── Fetch libsodium for Windows if needed ──────────────────────────────
|
|
if [[ ! -f "$SCRIPT_DIR/libs/libsodium-win/lib/libsodium.a" ]]; then
|
|
info "Fetching libsodium for Windows ..."
|
|
"$SCRIPT_DIR/scripts/fetch-libsodium.sh" --win
|
|
fi
|
|
|
|
# ── CMake + build ────────────────────────────────────────────────────────
|
|
info "Configuring (cross-compile) ..."
|
|
cmake "$SCRIPT_DIR" \
|
|
-DCMAKE_TOOLCHAIN_FILE="$bd/mingw-toolchain.cmake" \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DDRAGONX_USE_SYSTEM_SDL3=OFF
|
|
|
|
info "Building with $JOBS jobs ..."
|
|
cmake --build . -j "$JOBS"
|
|
|
|
[[ -f "bin/ObsidianDragon.exe" ]] || { err "Windows build failed"; exit 1; }
|
|
info "Binary: $(du -h bin/ObsidianDragon.exe | cut -f1)"
|
|
|
|
# ── Package: release/windows/ ────────────────────────────────────────────
|
|
rm -rf "$out"
|
|
mkdir -p "$out"
|
|
|
|
local DIST="DragonX-Wallet-Windows-x64"
|
|
local dist_dir="$out/$DIST"
|
|
mkdir -p "$dist_dir"
|
|
cp bin/ObsidianDragon.exe "$dist_dir/"
|
|
|
|
local DD="$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
|
|
for f in dragonxd.bat dragonx-cli.bat hushd.exe hush-cli.exe hush-tx.exe; do
|
|
[[ -f "$DD/$f" ]] && cp "$DD/$f" "$dist_dir/"
|
|
done
|
|
|
|
cat > "$dist_dir/README.txt" <<'README'
|
|
DragonX Wallet - Windows Edition
|
|
================================
|
|
|
|
SINGLE-FILE DISTRIBUTION
|
|
========================
|
|
This wallet is a true single-file executable with all resources embedded.
|
|
Just run ObsidianDragon.exe — no additional files needed!
|
|
|
|
On first run, the wallet will automatically extract:
|
|
- Sapling parameters to %APPDATA%\ZcashParams\
|
|
- asmap.dat to %APPDATA%\Hush\DRAGONX\
|
|
|
|
For support: https://git.hush.is/hush/ObsidianDragon
|
|
README
|
|
|
|
# Copy single-file exe to release dir
|
|
cp bin/ObsidianDragon.exe "$out/"
|
|
|
|
if command -v zip &>/dev/null; then
|
|
(cd "$out" && zip -r "$DIST.zip" "$DIST")
|
|
info "Zip: $out/$DIST.zip ($(du -h "$out/$DIST.zip" | cut -f1))"
|
|
# Clean up: keep .zip + single-file exe, remove loose directory
|
|
rm -rf "$dist_dir"
|
|
fi
|
|
|
|
info "Windows release artifacts: $out/"
|
|
ls -lh "$out/"
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
# RELEASE: macOS — .app bundle + DMG
|
|
#
|
|
# Cross-compile from Linux:
|
|
# 1. Install osxcross: https://github.com/tpoechtrager/osxcross
|
|
# export OSXCROSS="$HOME/osxcross" (or wherever you installed it)
|
|
# 2. For DMG: sudo apt install genisoimage
|
|
# 3. For .icns icons: sudo apt install icnsutils
|
|
# 4. Place macOS daemon binaries in prebuilt-binaries/dragonxd-mac/ (optional)
|
|
#
|
|
# Native on macOS:
|
|
# Works out of the box. brew install create-dmg for prettier DMGs.
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
build_release_mac() {
|
|
local IS_CROSS=false
|
|
local MAC_ARCH="x86_64"
|
|
|
|
# Detect cross-compilation from Linux
|
|
if [[ "$(uname -s)" == "Linux" ]]; then
|
|
IS_CROSS=true
|
|
info "Cross-compiling for macOS from Linux"
|
|
|
|
# Find osxcross
|
|
if [[ -z "${OSXCROSS:-}" ]]; then
|
|
# Try common locations
|
|
for try_path in "$SCRIPT_DIR/external/osxcross" "$HOME/osxcross" "/opt/osxcross" "/usr/local/osxcross"; do
|
|
if [[ -d "$try_path/target" ]]; then
|
|
OSXCROSS="$try_path"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [[ -z "${OSXCROSS:-}" || ! -d "${OSXCROSS}/target" ]]; then
|
|
err "osxcross not found! Set OSXCROSS=/path/to/osxcross or install it:"
|
|
echo ""
|
|
echo " git clone https://github.com/tpoechtrager/osxcross"
|
|
echo " cd osxcross"
|
|
echo " # Place MacOSX SDK (e.g. MacOSX13.0.sdk.tar.xz) in tarballs/"
|
|
echo " UNATTENDED=1 ./build.sh"
|
|
echo " export OSXCROSS=\$PWD"
|
|
echo ""
|
|
exit 1
|
|
fi
|
|
info "Using osxcross at: $OSXCROSS"
|
|
export PATH="$OSXCROSS/target/bin:$PATH"
|
|
|
|
# Find the right compiler triple
|
|
local OSXCROSS_CC="" OSXCROSS_CXX="" OSXCROSS_TRIPLE=""
|
|
|
|
# Look for full-triple compilers first (e.g. x86_64-apple-darwin22.4-clang++)
|
|
local found_triple
|
|
found_triple=$(ls "$OSXCROSS/target/bin/"x86_64-apple-darwin*-clang++ 2>/dev/null | head -1)
|
|
if [[ -n "$found_triple" ]]; then
|
|
OSXCROSS_TRIPLE=$(basename "$found_triple" | sed 's/-clang++$//')
|
|
OSXCROSS_CC="$OSXCROSS/target/bin/${OSXCROSS_TRIPLE}-clang"
|
|
OSXCROSS_CXX="$OSXCROSS/target/bin/${OSXCROSS_TRIPLE}-clang++"
|
|
MAC_ARCH="x86_64"
|
|
fi
|
|
# Prefer arm64 if available (Apple Silicon)
|
|
found_triple=$(ls "$OSXCROSS/target/bin/"aarch64-apple-darwin*-clang++ 2>/dev/null | head -1)
|
|
if [[ -n "$found_triple" ]]; then
|
|
OSXCROSS_TRIPLE=$(basename "$found_triple" | sed 's/-clang++$//')
|
|
OSXCROSS_CC="$OSXCROSS/target/bin/${OSXCROSS_TRIPLE}-clang"
|
|
OSXCROSS_CXX="$OSXCROSS/target/bin/${OSXCROSS_TRIPLE}-clang++"
|
|
MAC_ARCH="arm64"
|
|
fi
|
|
# Also try o64/oa64 wrapper — but resolve the underlying triple
|
|
if [[ -z "$OSXCROSS_CXX" ]]; then
|
|
if command -v o64-clang++ &>/dev/null; then
|
|
# Resolve the x86_64 triple from binutils
|
|
OSXCROSS_TRIPLE=$(ls "$OSXCROSS/target/bin/"x86_64-apple-darwin*-ar 2>/dev/null | head -1 | xargs basename | sed 's/-ar$//')
|
|
OSXCROSS_CC="o64-clang"
|
|
OSXCROSS_CXX="o64-clang++"
|
|
MAC_ARCH="x86_64"
|
|
elif command -v oa64-clang++ &>/dev/null; then
|
|
OSXCROSS_TRIPLE=$(ls "$OSXCROSS/target/bin/"aarch64-apple-darwin*-ar 2>/dev/null | head -1 | xargs basename | sed 's/-ar$//')
|
|
OSXCROSS_CC="oa64-clang"
|
|
OSXCROSS_CXX="oa64-clang++"
|
|
MAC_ARCH="arm64"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$OSXCROSS_CXX" ]]; then
|
|
err "Could not find osxcross compilers in PATH"
|
|
echo " Ensure \$OSXCROSS/target/bin contains *-apple-darwin*-clang++"
|
|
exit 1
|
|
fi
|
|
info "macOS cross-compiler: $OSXCROSS_CXX (arch: $MAC_ARCH)"
|
|
else
|
|
MAC_ARCH=$(uname -m)
|
|
fi
|
|
|
|
header "Release: macOS ($MAC_ARCH$(${IS_CROSS} && echo ' — cross-compile'))"
|
|
local bd="$SCRIPT_DIR/build/mac"
|
|
local out="$SCRIPT_DIR/release/mac"
|
|
|
|
if $CLEAN; then
|
|
info "Cleaning $bd ..."; rm -rf "$bd"
|
|
fi
|
|
mkdir -p "$bd" && cd "$bd"
|
|
|
|
# ── Compile ──────────────────────────────────────────────────────────────
|
|
if $IS_CROSS; then
|
|
# OSXCROSS_TRIPLE already resolved during compiler detection above
|
|
local OSXCROSS_SDK_PATH
|
|
OSXCROSS_SDK_PATH=$(ls -d "$OSXCROSS"/target/SDK/MacOSX*.sdk 2>/dev/null | head -1)
|
|
|
|
# Generate osxcross toolchain file
|
|
cat > "$bd/osxcross-toolchain.cmake" <<TOOLCHAIN
|
|
set(CMAKE_SYSTEM_NAME Darwin)
|
|
set(CMAKE_SYSTEM_PROCESSOR ${MAC_ARCH})
|
|
|
|
# Compilers
|
|
set(CMAKE_C_COMPILER ${OSXCROSS_CC})
|
|
set(CMAKE_CXX_COMPILER ${OSXCROSS_CXX})
|
|
set(CMAKE_OBJC_COMPILER ${OSXCROSS_CC})
|
|
set(CMAKE_OBJCXX_COMPILER ${OSXCROSS_CXX})
|
|
|
|
# SDK sysroot
|
|
set(CMAKE_OSX_SYSROOT "${OSXCROSS_SDK_PATH}")
|
|
|
|
# Cross-compilation binutils
|
|
set(CMAKE_AR "${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-ar" CACHE FILEPATH "ar")
|
|
set(CMAKE_RANLIB "${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-ranlib" CACHE FILEPATH "ranlib")
|
|
set(CMAKE_STRIP "${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-strip" CACHE FILEPATH "strip")
|
|
set(CMAKE_INSTALL_NAME_TOOL "${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-install_name_tool" CACHE FILEPATH "install_name_tool")
|
|
set(CMAKE_OTOOL "${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-otool" CACHE FILEPATH "otool")
|
|
set(CMAKE_LIBTOOL "${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-libtool" CACHE FILEPATH "libtool")
|
|
|
|
# Search paths
|
|
set(CMAKE_FIND_ROOT_PATH
|
|
"${OSXCROSS_SDK_PATH}"
|
|
"${OSXCROSS}/target/macports/pkgs"
|
|
"${OSXCROSS}/target/macports/pkgs/opt/local"
|
|
)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
|
|
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0)
|
|
TOOLCHAIN
|
|
|
|
# Find compiler-rt builtins for macOS
|
|
local COMPILER_RT=""
|
|
local CLANG_RESOURCE_DIR
|
|
CLANG_RESOURCE_DIR=$("$OSXCROSS_CC" -print-resource-dir 2>/dev/null || echo "")
|
|
if [[ -n "$CLANG_RESOURCE_DIR" && -f "$CLANG_RESOURCE_DIR/lib/darwin/libclang_rt.osx.a" ]]; then
|
|
COMPILER_RT="$CLANG_RESOURCE_DIR/lib/darwin/libclang_rt.osx.a"
|
|
elif [[ -f "$OSXCROSS/build/compiler-rt/compiler-rt/build/lib/darwin/libclang_rt.osx.a" ]]; then
|
|
COMPILER_RT="$OSXCROSS/build/compiler-rt/compiler-rt/build/lib/darwin/libclang_rt.osx.a"
|
|
fi
|
|
|
|
# Fetch libsodium for macOS if needed
|
|
if [[ ! -f "$SCRIPT_DIR/libs/libsodium-mac/lib/libsodium.a" ]]; then
|
|
info "Fetching libsodium for macOS ..."
|
|
"$SCRIPT_DIR/scripts/fetch-libsodium.sh" --mac
|
|
fi
|
|
|
|
info "Configuring (cross-compile via osxcross) ..."
|
|
cmake "$SCRIPT_DIR" \
|
|
-DCMAKE_TOOLCHAIN_FILE="$bd/osxcross-toolchain.cmake" \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG" \
|
|
-DDRAGONX_USE_SYSTEM_SDL3=OFF \
|
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \
|
|
${COMPILER_RT:+-DOSXCROSS_COMPILER_RT="$COMPILER_RT"}
|
|
else
|
|
info "Configuring (native) ..."
|
|
cmake "$SCRIPT_DIR" \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG" \
|
|
-DDRAGONX_USE_SYSTEM_SDL3=OFF \
|
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0
|
|
fi
|
|
|
|
info "Building with $JOBS jobs ..."
|
|
cmake --build . -j "$JOBS"
|
|
|
|
[[ -f "bin/ObsidianDragon" ]] || { err "macOS build failed"; exit 1; }
|
|
|
|
# Strip — use osxcross strip for cross-builds
|
|
if $IS_CROSS; then
|
|
local STRIP_CMD="${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-strip"
|
|
if [[ -x "$STRIP_CMD" ]]; then
|
|
info "Stripping (osxcross) ..."
|
|
"$STRIP_CMD" bin/ObsidianDragon
|
|
else
|
|
warn "osxcross strip not found at $STRIP_CMD — skipping"
|
|
fi
|
|
else
|
|
info "Stripping ..."
|
|
strip bin/ObsidianDragon
|
|
fi
|
|
info "Binary: $(du -h bin/ObsidianDragon | cut -f1)"
|
|
|
|
# ── Create .app bundle ───────────────────────────────────────────────────
|
|
rm -rf "$out"
|
|
mkdir -p "$out"
|
|
|
|
local APP="$out/ObsidianDragon.app"
|
|
local CONTENTS="$APP/Contents"
|
|
local MACOS="$CONTENTS/MacOS"
|
|
local RESOURCES="$CONTENTS/Resources"
|
|
local FRAMEWORKS="$CONTENTS/Frameworks"
|
|
|
|
mkdir -p "$MACOS" "$RESOURCES/res" "$FRAMEWORKS"
|
|
|
|
# Main binary
|
|
cp bin/ObsidianDragon "$MACOS/"
|
|
chmod +x "$MACOS/ObsidianDragon"
|
|
|
|
# Resources
|
|
cp -r bin/res/* "$RESOURCES/res/" 2>/dev/null || true
|
|
|
|
# Daemon binaries (macOS native, from dragonxd-mac/)
|
|
local daemon_dir="$SCRIPT_DIR/prebuilt-binaries/dragonxd-mac"
|
|
if [[ -d "$daemon_dir" ]]; then
|
|
for f in hush-arrakis-chain hushd hush-cli hush-tx dragonxd; do
|
|
[[ -f "$daemon_dir/$f" ]] && { cp "$daemon_dir/$f" "$MACOS/"; chmod +x "$MACOS/$f"; info " Bundled $f"; }
|
|
done
|
|
elif ! $IS_CROSS; then
|
|
# Native macOS: try standard paths
|
|
local launcher_paths=(
|
|
"$SCRIPT_DIR/../hush-arrakis-chain"
|
|
"$HOME/hush3/src/hush-arrakis-chain"
|
|
)
|
|
for p in "${launcher_paths[@]}"; do
|
|
[[ -f "$p" ]] && { cp "$p" "$MACOS/hush-arrakis-chain"; chmod +x "$MACOS/hush-arrakis-chain"; info " Bundled hush-arrakis-chain"; break; }
|
|
done
|
|
local hushd_paths=(
|
|
"$SCRIPT_DIR/../hushd"
|
|
"$HOME/hush3/src/hushd"
|
|
)
|
|
for p in "${hushd_paths[@]}"; do
|
|
[[ -f "$p" ]] && { cp "$p" "$MACOS/hushd"; chmod +x "$MACOS/hushd"; info " Bundled hushd"; break; }
|
|
done
|
|
else
|
|
warn "prebuilt-binaries/dragonxd-mac/ not found — place macOS daemon binaries there for bundling"
|
|
fi
|
|
|
|
# asmap.dat
|
|
find_asmap 2>/dev/null && cp "$ASMAP_DAT" "$RESOURCES/asmap.dat" && info " Bundled asmap.dat"
|
|
|
|
# Bundle SDL3 dylib
|
|
local sdl_dylib=""
|
|
for candidate in \
|
|
"$bd/_deps/sdl3-build/libSDL3.dylib" \
|
|
"$bd/_deps/sdl3-build/libSDL3.0.dylib" \
|
|
"/usr/local/lib/libSDL3.dylib" \
|
|
"/opt/homebrew/lib/libSDL3.dylib"; do
|
|
if [[ -f "$candidate" ]]; then
|
|
sdl_dylib="$candidate"
|
|
break
|
|
fi
|
|
done
|
|
if [[ -n "$sdl_dylib" ]]; then
|
|
cp "$sdl_dylib" "$FRAMEWORKS/"
|
|
local sdl_name=$(basename "$sdl_dylib")
|
|
# Fix the rpath so the binary finds SDL3 in Frameworks/
|
|
if $IS_CROSS; then
|
|
local INSTALL_NAME_TOOL="${OSXCROSS}/target/bin/${OSXCROSS_TRIPLE}-install_name_tool"
|
|
[[ -x "$INSTALL_NAME_TOOL" ]] && "$INSTALL_NAME_TOOL" -change "@rpath/$sdl_name" "@executable_path/../Frameworks/$sdl_name" "$MACOS/ObsidianDragon" 2>/dev/null || true
|
|
else
|
|
install_name_tool -change "@rpath/$sdl_name" "@executable_path/../Frameworks/$sdl_name" "$MACOS/ObsidianDragon" 2>/dev/null || true
|
|
fi
|
|
info " Bundled $sdl_name"
|
|
fi
|
|
|
|
# Launcher script (ensures working dir + dylib path)
|
|
mv "$MACOS/ObsidianDragon" "$MACOS/ObsidianDragon.bin"
|
|
cat > "$MACOS/ObsidianDragon" <<'LAUNCH'
|
|
#!/bin/bash
|
|
DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
export DYLD_LIBRARY_PATH="$DIR/../Frameworks:$DYLD_LIBRARY_PATH"
|
|
export DRAGONX_RES_PATH="$DIR/../Resources/res"
|
|
cd "$DIR/../Resources"
|
|
exec "$DIR/ObsidianDragon.bin" "$@"
|
|
LAUNCH
|
|
chmod +x "$MACOS/ObsidianDragon"
|
|
|
|
# Info.plist
|
|
cat > "$CONTENTS/Info.plist" <<PLIST
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>CFBundleName</key>
|
|
<string>DragonX Wallet</string>
|
|
<key>CFBundleDisplayName</key>
|
|
<string>DragonX Wallet</string>
|
|
<key>CFBundleIdentifier</key>
|
|
<string>is.hush.dragonx</string>
|
|
<key>CFBundleVersion</key>
|
|
<string>${VERSION}</string>
|
|
<key>CFBundleShortVersionString</key>
|
|
<string>${VERSION}</string>
|
|
<key>CFBundleExecutable</key>
|
|
<string>ObsidianDragon</string>
|
|
<key>CFBundleIconFile</key>
|
|
<string>ObsidianDragon</string>
|
|
<key>CFBundlePackageType</key>
|
|
<string>APPL</string>
|
|
<key>CFBundleSignature</key>
|
|
<string>DRGX</string>
|
|
<key>LSMinimumSystemVersion</key>
|
|
<string>11.0</string>
|
|
<key>NSHighResolutionCapable</key>
|
|
<true/>
|
|
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
|
<true/>
|
|
<key>LSApplicationCategoryType</key>
|
|
<string>public.app-category.finance</string>
|
|
</dict>
|
|
</plist>
|
|
PLIST
|
|
|
|
# ── Icon (.icns) ─────────────────────────────────────────────────────────
|
|
if [[ -f "$SCRIPT_DIR/res/img/ObsidianDragon.icns" ]]; then
|
|
cp "$SCRIPT_DIR/res/img/ObsidianDragon.icns" "$RESOURCES/ObsidianDragon.icns"
|
|
elif [[ -f "$SCRIPT_DIR/res/icons/dragonx-256.png" ]]; then
|
|
if command -v iconutil &>/dev/null && command -v sips &>/dev/null; then
|
|
# Native macOS: sips + iconutil
|
|
local iconset="$bd/ObsidianDragon.iconset"
|
|
mkdir -p "$iconset"
|
|
local src="$SCRIPT_DIR/res/icons/dragonx-256.png"
|
|
for sz in 16 32 64 128 256; do
|
|
sips -z $sz $sz "$src" --out "$iconset/icon_${sz}x${sz}.png" &>/dev/null || true
|
|
done
|
|
for sz in 16 32 128; do
|
|
local r=$((sz * 2))
|
|
sips -z $r $r "$src" --out "$iconset/icon_${sz}x${sz}@2x.png" &>/dev/null || true
|
|
done
|
|
iconutil -c icns "$iconset" -o "$RESOURCES/ObsidianDragon.icns" 2>/dev/null || true
|
|
rm -rf "$iconset"
|
|
elif command -v png2icns &>/dev/null; then
|
|
# Linux: png2icns from icnsutils (sudo apt install icnsutils)
|
|
info "Creating .icns with png2icns ..."
|
|
local src="$SCRIPT_DIR/res/icons/dragonx-256.png"
|
|
# png2icns needs specific sizes; resize with ImageMagick if available
|
|
if command -v convert &>/dev/null; then
|
|
local icondir="$bd/icon-sizes"
|
|
mkdir -p "$icondir"
|
|
for sz in 16 32 48 128 256; do
|
|
convert "$src" -resize ${sz}x${sz} "$icondir/icon_${sz}.png" 2>/dev/null || true
|
|
done
|
|
png2icns "$RESOURCES/ObsidianDragon.icns" "$icondir"/icon_*.png 2>/dev/null || true
|
|
rm -rf "$icondir"
|
|
else
|
|
# Just use the 256px as-is
|
|
png2icns "$RESOURCES/ObsidianDragon.icns" "$src" 2>/dev/null || true
|
|
fi
|
|
else
|
|
warn "No .icns tool found (install: sudo apt install icnsutils)"
|
|
fi
|
|
fi
|
|
|
|
info ".app bundle created: $APP"
|
|
|
|
# ── Create DMG ───────────────────────────────────────────────────────────
|
|
local DMG_NAME="DragonX_Wallet-${VERSION}-macOS-${MAC_ARCH}.dmg"
|
|
|
|
if command -v create-dmg &>/dev/null; then
|
|
# create-dmg (works on macOS; also available on Linux via npm)
|
|
info "Creating DMG with create-dmg ..."
|
|
create-dmg \
|
|
--volname "DragonX Wallet" \
|
|
--volicon "$RESOURCES/ObsidianDragon.icns" \
|
|
--window-pos 200 120 \
|
|
--window-size 600 400 \
|
|
--icon-size 100 \
|
|
--icon "ObsidianDragon.app" 150 190 \
|
|
--app-drop-link 450 190 \
|
|
--no-internet-enable \
|
|
"$out/$DMG_NAME" \
|
|
"$APP" 2>/dev/null && {
|
|
info "DMG: $out/$DMG_NAME ($(du -h "$out/$DMG_NAME" | cut -f1))"
|
|
} || warn "create-dmg failed — .app bundle still available"
|
|
elif command -v hdiutil &>/dev/null; then
|
|
# Native macOS
|
|
info "Creating DMG with hdiutil ..."
|
|
local staging="$bd/dmg-staging"
|
|
rm -rf "$staging"
|
|
mkdir -p "$staging"
|
|
cp -a "$APP" "$staging/"
|
|
ln -s /Applications "$staging/Applications"
|
|
hdiutil create -volname "DragonX Wallet" \
|
|
-srcfolder "$staging" \
|
|
-ov -format UDZO \
|
|
"$out/$DMG_NAME" 2>/dev/null && {
|
|
info "DMG: $out/$DMG_NAME ($(du -h "$out/$DMG_NAME" | cut -f1))"
|
|
} || warn "hdiutil failed — .app bundle still available"
|
|
rm -rf "$staging"
|
|
elif command -v genisoimage &>/dev/null; then
|
|
# Linux fallback: genisoimage produces a hybrid ISO/DMG that macOS can open
|
|
info "Creating DMG with genisoimage (Linux) ..."
|
|
local staging="$bd/dmg-staging"
|
|
rm -rf "$staging"
|
|
mkdir -p "$staging"
|
|
cp -a "$APP" "$staging/"
|
|
# Can't create a real symlink to /Applications in an ISO, but the .app
|
|
# is the important part — users drag it to Applications manually.
|
|
genisoimage -V "DragonX Wallet" \
|
|
-D -R -apple -no-pad \
|
|
-o "$out/$DMG_NAME" \
|
|
"$staging" 2>/dev/null && {
|
|
info "DMG: $out/$DMG_NAME ($(du -h "$out/$DMG_NAME" | cut -f1))"
|
|
info " (ISO/HFS hybrid — mountable on macOS)"
|
|
} || warn "genisoimage failed — .app bundle still available"
|
|
rm -rf "$staging"
|
|
else
|
|
warn "No DMG tool found — .app bundle still available"
|
|
echo ""
|
|
echo " To create DMGs on Linux, install one of:"
|
|
echo " sudo apt install genisoimage # Basic DMG (recommended)"
|
|
echo " sudo apt install icnsutils # For .icns icon creation"
|
|
echo ""
|
|
fi
|
|
|
|
info "macOS release artifacts: $out/"
|
|
ls -lhR "$out/" 2>/dev/null | head -30
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
# MAIN
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
echo -e "${GREEN}DragonX Wallet v${VERSION} — Unified Build${NC}"
|
|
echo "─────────────────────────────────────────"
|
|
|
|
$DO_DEV && build_dev
|
|
$DO_LINUX && build_release_linux
|
|
$DO_WIN && build_release_win
|
|
$DO_MAC && build_release_mac
|
|
|
|
header "Done"
|
|
if $DO_LINUX || $DO_WIN || $DO_MAC; then
|
|
echo -e " Release artifacts in: ${GREEN}$SCRIPT_DIR/release/${NC}"
|
|
[[ -d "$SCRIPT_DIR/release/linux" ]] && echo -e " ${CYAN}linux/${NC} — AppImage + binary"
|
|
[[ -d "$SCRIPT_DIR/release/windows" ]] && echo -e " ${CYAN}windows/${NC} — .exe + .zip"
|
|
[[ -d "$SCRIPT_DIR/release/mac" ]] && echo -e " ${CYAN}mac/${NC} — .app + .dmg"
|
|
fi
|