Files
ObsidianDragon/build.sh
dan_s c809666624 ObsidianDragon - DragonX ImGui Wallet
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)
2026-02-27 00:26:01 -06:00

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