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)
This commit is contained in:
159
scripts/create-appimage.sh
Executable file
159
scripts/create-appimage.sh
Executable file
@@ -0,0 +1,159 @@
|
||||
#!/bin/bash
|
||||
# DragonX ImGui Wallet - AppImage Creation Script
|
||||
# Copyright 2024-2026 The Hush Developers
|
||||
# Released under the GPLv3
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BUILD_DIR="${SCRIPT_DIR}/build/linux"
|
||||
APPDIR="${BUILD_DIR}/AppDir"
|
||||
VERSION="1.0.0"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() { echo -e "${GREEN}[*]${NC} $1"; }
|
||||
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# Check prerequisites
|
||||
if [ ! -f "${BUILD_DIR}/bin/ObsidianDragon" ]; then
|
||||
print_error "Binary not found. Run build.sh --linux-release first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for appimagetool
|
||||
APPIMAGETOOL=""
|
||||
if command -v appimagetool &> /dev/null; then
|
||||
APPIMAGETOOL="appimagetool"
|
||||
elif [ -f "${BUILD_DIR}/appimagetool-x86_64.AppImage" ]; then
|
||||
APPIMAGETOOL="${BUILD_DIR}/appimagetool-x86_64.AppImage"
|
||||
else
|
||||
print_status "Downloading appimagetool..."
|
||||
wget -q -O "${BUILD_DIR}/appimagetool-x86_64.AppImage" \
|
||||
"https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x "${BUILD_DIR}/appimagetool-x86_64.AppImage"
|
||||
APPIMAGETOOL="${BUILD_DIR}/appimagetool-x86_64.AppImage"
|
||||
fi
|
||||
|
||||
print_status "Creating AppDir structure..."
|
||||
rm -rf "${APPDIR}"
|
||||
mkdir -p "${APPDIR}/usr/bin"
|
||||
mkdir -p "${APPDIR}/usr/lib"
|
||||
mkdir -p "${APPDIR}/usr/share/applications"
|
||||
mkdir -p "${APPDIR}/usr/share/icons/hicolor/256x256/apps"
|
||||
mkdir -p "${APPDIR}/usr/share/ObsidianDragon/res"
|
||||
|
||||
# Copy binary
|
||||
print_status "Copying binary..."
|
||||
cp "${BUILD_DIR}/bin/ObsidianDragon" "${APPDIR}/usr/bin/"
|
||||
|
||||
# Copy resources
|
||||
print_status "Copying resources..."
|
||||
cp -r "${BUILD_DIR}/bin/res/"* "${APPDIR}/usr/share/ObsidianDragon/res/" 2>/dev/null || true
|
||||
|
||||
# Create desktop file
|
||||
print_status "Creating desktop file..."
|
||||
cat > "${APPDIR}/usr/share/applications/ObsidianDragon.desktop" << EOF
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=DragonX Wallet
|
||||
Comment=DragonX Cryptocurrency Wallet
|
||||
Exec=ObsidianDragon
|
||||
Icon=ObsidianDragon
|
||||
Categories=Finance;Network;
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
EOF
|
||||
|
||||
# Copy desktop file to root
|
||||
cp "${APPDIR}/usr/share/applications/ObsidianDragon.desktop" "${APPDIR}/"
|
||||
|
||||
# Create icon (simple SVG placeholder if no icon exists)
|
||||
print_status "Creating 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
|
||||
# Create a simple SVG icon as placeholder
|
||||
cat > "${APPDIR}/ObsidianDragon.svg" << 'EOF'
|
||||
<?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>
|
||||
EOF
|
||||
# Convert SVG to PNG if rsvg-convert is available
|
||||
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
|
||||
|
||||
# Copy icon to root
|
||||
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
|
||||
|
||||
# Create AppRun script
|
||||
print_status "Creating AppRun..."
|
||||
cat > "${APPDIR}/AppRun" << 'EOF'
|
||||
#!/bin/bash
|
||||
SELF=$(readlink -f "$0")
|
||||
HERE=${SELF%/*}
|
||||
|
||||
# Set up resource paths
|
||||
export DRAGONX_RES_PATH="${HERE}/usr/share/ObsidianDragon/res"
|
||||
|
||||
# Find libraries
|
||||
export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH}"
|
||||
|
||||
# Change to resource directory for relative paths
|
||||
cd "${HERE}/usr/share/ObsidianDragon"
|
||||
|
||||
exec "${HERE}/usr/bin/ObsidianDragon" "$@"
|
||||
EOF
|
||||
chmod +x "${APPDIR}/AppRun"
|
||||
|
||||
# Bundle required libraries (basic set)
|
||||
print_status "Bundling libraries..."
|
||||
LIBS_TO_BUNDLE=(
|
||||
"libSDL3.so"
|
||||
)
|
||||
|
||||
for lib in "${LIBS_TO_BUNDLE[@]}"; do
|
||||
LIB_PATH=$(ldconfig -p | grep "$lib" | head -1 | awk '{print $NF}')
|
||||
if [ -n "$LIB_PATH" ] && [ -f "$LIB_PATH" ]; then
|
||||
cp "$LIB_PATH" "${APPDIR}/usr/lib/" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Also copy SDL3 from build if exists
|
||||
if [ -f "${BUILD_DIR}/_deps/sdl3-build/libSDL3.so" ]; then
|
||||
cp "${BUILD_DIR}/_deps/sdl3-build/libSDL3.so"* "${APPDIR}/usr/lib/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Create AppImage
|
||||
print_status "Creating AppImage..."
|
||||
cd "${BUILD_DIR}"
|
||||
|
||||
ARCH=$(uname -m)
|
||||
APPIMAGE_NAME="DragonX_Wallet-${VERSION}-${ARCH}.AppImage"
|
||||
|
||||
# Run appimagetool
|
||||
ARCH="${ARCH}" "${APPIMAGETOOL}" "${APPDIR}" "${APPIMAGE_NAME}"
|
||||
|
||||
if [ -f "${APPIMAGE_NAME}" ]; then
|
||||
# Copy to release/linux/ for clean output
|
||||
OUT_DIR="${SCRIPT_DIR}/release/linux"
|
||||
mkdir -p "${OUT_DIR}"
|
||||
cp "${APPIMAGE_NAME}" "${OUT_DIR}/"
|
||||
print_status "AppImage created successfully!"
|
||||
print_status "Output: ${OUT_DIR}/${APPIMAGE_NAME}"
|
||||
ls -lh "${OUT_DIR}/${APPIMAGE_NAME}"
|
||||
else
|
||||
print_error "AppImage creation failed"
|
||||
exit 1
|
||||
fi
|
||||
132
scripts/fetch-libsodium.sh
Executable file
132
scripts/fetch-libsodium.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/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
|
||||
echo "$SODIUM_SHA256 $TARBALL" | sha256sum -c - || {
|
||||
echo "[fetch-libsodium] ERROR: SHA256 mismatch! Removing corrupted download."
|
||||
rm -f "$TARBALL"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ── 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 "$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
|
||||
|
||||
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"
|
||||
178
scripts/json2toml.py
Normal file
178
scripts/json2toml.py
Normal file
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert DragonX ui.json / ui-dark.json / ui-light.json to TOML format.
|
||||
|
||||
Usage:
|
||||
python3 scripts/json2toml.py res/themes/ui.json res/themes/ui.toml
|
||||
python3 scripts/json2toml.py res/themes/ui-dark.json res/themes/ui-dark.toml
|
||||
python3 scripts/json2toml.py res/themes/ui-light.json res/themes/ui-light.toml
|
||||
python3 scripts/json2toml.py --all # converts all three
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
|
||||
# Keys that need quoting in TOML because they contain special chars
|
||||
def needs_quoting(key):
|
||||
# TOML bare keys: [A-Za-z0-9_-]+
|
||||
return not re.match(r'^[A-Za-z0-9_-]+$', key)
|
||||
|
||||
def quote_key(key):
|
||||
if needs_quoting(key):
|
||||
return f'"{key}"'
|
||||
return key
|
||||
|
||||
def format_value(val):
|
||||
"""Format a Python value as a TOML value string."""
|
||||
if isinstance(val, bool):
|
||||
return "true" if val else "false"
|
||||
elif isinstance(val, int):
|
||||
return str(val)
|
||||
elif isinstance(val, float):
|
||||
# Ensure floats always have a decimal point
|
||||
s = repr(val)
|
||||
if '.' not in s and 'e' not in s and 'E' not in s:
|
||||
s += '.0'
|
||||
return s
|
||||
elif isinstance(val, str):
|
||||
# Escape backslashes and quotes
|
||||
escaped = val.replace('\\', '\\\\').replace('"', '\\"')
|
||||
return f'"{escaped}"'
|
||||
elif isinstance(val, list):
|
||||
parts = [format_value(v) for v in val]
|
||||
return f'[{", ".join(parts)}]'
|
||||
else:
|
||||
return repr(val)
|
||||
|
||||
def is_simple_leaf(obj):
|
||||
"""Check if an object is a simple leaf that can be an inline table.
|
||||
Simple leafs: {"size": X}, {"color": "..."}, {"height": X}, or small
|
||||
objects with only primitive values and no nested objects."""
|
||||
if not isinstance(obj, dict):
|
||||
return False
|
||||
for v in obj.values():
|
||||
if isinstance(v, (dict, list)):
|
||||
return False
|
||||
# Keep objects with many keys as sections (threshold: 6 keys)
|
||||
return len(obj) <= 6
|
||||
|
||||
def is_array_of_objects(val):
|
||||
"""Check if val is an array of objects (needs [[array.of.tables]])."""
|
||||
return isinstance(val, list) and all(isinstance(v, dict) for v in val) and len(val) > 0
|
||||
|
||||
def write_inline_table(obj):
|
||||
"""Write a dict as a TOML inline table."""
|
||||
parts = []
|
||||
for k, v in obj.items():
|
||||
parts.append(f'{quote_key(k)} = {format_value(v)}')
|
||||
return '{ ' + ', '.join(parts) + ' }'
|
||||
|
||||
def emit_toml(data, lines, prefix='', depth=0):
|
||||
"""Recursively emit TOML from a parsed JSON dict."""
|
||||
|
||||
# Separate keys into: scalars/arrays, simple-leaf objects, complex objects, array-of-tables
|
||||
scalars = []
|
||||
inline_leaves = []
|
||||
complex_tables = []
|
||||
array_tables = []
|
||||
|
||||
for key, val in data.items():
|
||||
# Skip _comment keys (we'll handle them differently)
|
||||
if key.startswith('_comment'):
|
||||
continue
|
||||
|
||||
if isinstance(val, dict):
|
||||
if is_simple_leaf(val):
|
||||
inline_leaves.append((key, val))
|
||||
else:
|
||||
complex_tables.append((key, val))
|
||||
elif is_array_of_objects(val):
|
||||
array_tables.append((key, val))
|
||||
else:
|
||||
scalars.append((key, val))
|
||||
|
||||
# Emit scalars first
|
||||
for key, val in scalars:
|
||||
lines.append(f'{quote_key(key)} = {format_value(val)}')
|
||||
|
||||
# Emit inline leaf objects (like { size = 42.0 })
|
||||
for key, val in inline_leaves:
|
||||
lines.append(f'{quote_key(key)} = {write_inline_table(val)}')
|
||||
|
||||
# Emit complex sub-tables with [section] headers
|
||||
for key, val in complex_tables:
|
||||
subprefix = f'{prefix}.{key}' if prefix else key
|
||||
lines.append('')
|
||||
lines.append(f'[{subprefix}]')
|
||||
emit_toml(val, lines, subprefix, depth + 1)
|
||||
|
||||
# Emit array-of-tables with [[section]] headers
|
||||
for key, val in array_tables:
|
||||
subprefix = f'{prefix}.{key}' if prefix else key
|
||||
for item in val:
|
||||
lines.append('')
|
||||
lines.append(f'[[{subprefix}]]')
|
||||
if isinstance(item, dict):
|
||||
for ik, iv in item.items():
|
||||
if isinstance(iv, dict):
|
||||
# Nested object inside array item — inline table
|
||||
lines.append(f'{quote_key(ik)} = {write_inline_table(iv)}')
|
||||
else:
|
||||
lines.append(f'{quote_key(ik)} = {format_value(iv)}')
|
||||
|
||||
def convert_file(input_path, output_path):
|
||||
"""Convert a JSON theme file to TOML."""
|
||||
with open(input_path) as f:
|
||||
data = json.load(f, object_pairs_hook=OrderedDict)
|
||||
|
||||
lines = []
|
||||
|
||||
# Add header comments (converted from _comment_* keys)
|
||||
for key, val in data.items():
|
||||
if key.startswith('_comment') and isinstance(val, str):
|
||||
if val:
|
||||
lines.append(f'# {val}')
|
||||
else:
|
||||
lines.append('')
|
||||
|
||||
if lines:
|
||||
lines.append('')
|
||||
|
||||
# Emit all non-comment content
|
||||
emit_toml(data, lines)
|
||||
|
||||
# Clean up extra blank lines
|
||||
output = '\n'.join(lines).strip() + '\n'
|
||||
# Collapse 3+ consecutive newlines to 2
|
||||
while '\n\n\n' in output:
|
||||
output = output.replace('\n\n\n', '\n\n')
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
f.write(output)
|
||||
|
||||
print(f'Converted: {input_path} -> {output_path}')
|
||||
print(f' JSON: {os.path.getsize(input_path):,} bytes')
|
||||
print(f' TOML: {os.path.getsize(output_path):,} bytes')
|
||||
print(f' Reduction: {100 - 100*os.path.getsize(output_path)/os.path.getsize(input_path):.0f}%')
|
||||
|
||||
def main():
|
||||
if len(sys.argv) == 2 and sys.argv[1] == '--all':
|
||||
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
themes = os.path.join(base, 'res', 'themes')
|
||||
for name in ['ui', 'ui-dark', 'ui-light']:
|
||||
inp = os.path.join(themes, f'{name}.json')
|
||||
out = os.path.join(themes, f'{name}.toml')
|
||||
if os.path.exists(inp):
|
||||
convert_file(inp, out)
|
||||
else:
|
||||
print(f'Skipping (not found): {inp}')
|
||||
elif len(sys.argv) == 3:
|
||||
convert_file(sys.argv[1], sys.argv[2])
|
||||
else:
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
224
scripts/legacy/build-release.sh
Executable file
224
scripts/legacy/build-release.sh
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/bin/bash
|
||||
# DragonX ImGui Wallet - Release Build Script
|
||||
# Copyright 2024-2026 The Hush Developers
|
||||
# Released under the GPLv3
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BUILD_DIR="${SCRIPT_DIR}/build/linux"
|
||||
VERSION="1.0.0"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
print_status() {
|
||||
echo -e "${GREEN}[*]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[!]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "DragonX ImGui Wallet Build Script"
|
||||
echo ""
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -d, --debug Build debug version"
|
||||
echo " -r, --release Build release version (default)"
|
||||
echo " -c, --clean Clean build directory first"
|
||||
echo " -j N Use N parallel jobs (default: auto)"
|
||||
echo " -a, --appimage Create AppImage after build"
|
||||
echo " -h, --help Show this help"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 -r # Release build"
|
||||
echo " $0 -c -r # Clean + release build"
|
||||
echo " $0 -r -a # Release build + AppImage"
|
||||
echo " $0 -d -j4 # Debug build with 4 threads"
|
||||
}
|
||||
|
||||
# Default options
|
||||
BUILD_TYPE="Release"
|
||||
CLEAN=false
|
||||
JOBS=$(nproc 2>/dev/null || echo 4)
|
||||
CREATE_APPIMAGE=false
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-d|--debug)
|
||||
BUILD_TYPE="Debug"
|
||||
shift
|
||||
;;
|
||||
-r|--release)
|
||||
BUILD_TYPE="Release"
|
||||
shift
|
||||
;;
|
||||
-c|--clean)
|
||||
CLEAN=true
|
||||
shift
|
||||
;;
|
||||
-j)
|
||||
JOBS="$2"
|
||||
shift 2
|
||||
;;
|
||||
-a|--appimage)
|
||||
CREATE_APPIMAGE=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
print_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
print_status "DragonX ImGui Wallet v${VERSION} - Build Script"
|
||||
print_status "Build type: ${BUILD_TYPE}"
|
||||
print_status "Parallel jobs: ${JOBS}"
|
||||
|
||||
# Clean if requested
|
||||
if [ "$CLEAN" = true ]; then
|
||||
print_status "Cleaning build directory..."
|
||||
rm -rf "${BUILD_DIR}"
|
||||
fi
|
||||
|
||||
# Create build directory
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
cd "${BUILD_DIR}"
|
||||
|
||||
# Configure
|
||||
print_status "Running CMake configuration..."
|
||||
cmake .. \
|
||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||
-DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG" \
|
||||
-DDRAGONX_USE_SYSTEM_SDL3=ON
|
||||
|
||||
# Build
|
||||
print_status "Building with ${JOBS} parallel jobs..."
|
||||
cmake --build . -j "${JOBS}"
|
||||
|
||||
# Check if build succeeded
|
||||
if [ -f "bin/ObsidianDragon" ]; then
|
||||
print_status "Build successful!"
|
||||
|
||||
# Show binary info
|
||||
BINARY_SIZE=$(du -h bin/ObsidianDragon | cut -f1)
|
||||
print_status "Binary size: ${BINARY_SIZE}"
|
||||
|
||||
# Strip in release mode
|
||||
if [ "$BUILD_TYPE" = "Release" ]; then
|
||||
print_status "Stripping debug symbols..."
|
||||
strip bin/ObsidianDragon
|
||||
STRIPPED_SIZE=$(du -h bin/ObsidianDragon | cut -f1)
|
||||
print_status "Stripped size: ${STRIPPED_SIZE}"
|
||||
fi
|
||||
|
||||
# Bundle daemon files if available
|
||||
DAEMON_BUNDLED=0
|
||||
|
||||
# Look for hush-arrakis-chain in common locations (the daemon launcher script)
|
||||
LAUNCHER_PATHS=(
|
||||
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/hush-arrakis-chain"
|
||||
"${SCRIPT_DIR}/../hush-arrakis-chain"
|
||||
"${SCRIPT_DIR}/hush-arrakis-chain"
|
||||
"$HOME/hush3/src/hush-arrakis-chain"
|
||||
)
|
||||
|
||||
for lpath in "${LAUNCHER_PATHS[@]}"; do
|
||||
if [ -f "$lpath" ]; then
|
||||
print_status "Bundling hush-arrakis-chain from $lpath"
|
||||
cp "$lpath" bin/hush-arrakis-chain
|
||||
chmod +x bin/hush-arrakis-chain
|
||||
DAEMON_BUNDLED=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Also look for hushd (the actual daemon binary)
|
||||
HUSHD_PATHS=(
|
||||
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/hushd"
|
||||
"${SCRIPT_DIR}/../hushd"
|
||||
"${SCRIPT_DIR}/hushd"
|
||||
"$HOME/hush3/src/hushd"
|
||||
)
|
||||
|
||||
for hpath in "${HUSHD_PATHS[@]}"; do
|
||||
if [ -f "$hpath" ]; then
|
||||
print_status "Bundling hushd from $hpath"
|
||||
cp "$hpath" bin/hushd
|
||||
chmod +x bin/hushd
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Also copy dragonxd script if available (alternative launcher)
|
||||
DRAGONXD_PATHS=(
|
||||
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/dragonxd"
|
||||
"${SCRIPT_DIR}/../dragonxd"
|
||||
"${SCRIPT_DIR}/dragonxd"
|
||||
"$HOME/hush3/src/dragonxd"
|
||||
)
|
||||
|
||||
for dpath in "${DRAGONXD_PATHS[@]}"; do
|
||||
if [ -f "$dpath" ]; then
|
||||
print_status "Bundling dragonxd script from $dpath"
|
||||
cp "$dpath" bin/dragonxd
|
||||
chmod +x bin/dragonxd
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Look for asmap.dat
|
||||
ASMAP_PATHS=(
|
||||
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/asmap.dat"
|
||||
"${SCRIPT_DIR}/../asmap.dat"
|
||||
"${SCRIPT_DIR}/asmap.dat"
|
||||
"$HOME/hush3/asmap.dat"
|
||||
"$HOME/hush3/contrib/asmap/asmap.dat"
|
||||
)
|
||||
|
||||
for apath in "${ASMAP_PATHS[@]}"; do
|
||||
if [ -f "$apath" ]; then
|
||||
print_status "Bundling asmap.dat from $apath"
|
||||
cp "$apath" bin/
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $DAEMON_BUNDLED -eq 1 ]; then
|
||||
print_status "Daemon bundled - ready for distribution!"
|
||||
else
|
||||
print_warning "dragonxd not found - place prebuilt-binaries/dragonxd-linux/ in project directory for bundling"
|
||||
fi
|
||||
else
|
||||
print_error "Build failed - binary not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create AppImage if requested
|
||||
if [ "$CREATE_APPIMAGE" = true ]; then
|
||||
print_status "Creating AppImage..."
|
||||
"${SCRIPT_DIR}/create-appimage.sh" || print_warning "AppImage creation failed"
|
||||
fi
|
||||
|
||||
print_status ""
|
||||
print_status "Build complete!"
|
||||
print_status "Binary: ${BUILD_DIR}/bin/ObsidianDragon"
|
||||
print_status ""
|
||||
print_status "To run: cd ${BUILD_DIR}/bin && ./ObsidianDragon"
|
||||
60
scripts/legacy/build-windows.bat
Normal file
60
scripts/legacy/build-windows.bat
Normal file
@@ -0,0 +1,60 @@
|
||||
@echo off
|
||||
REM DragonX Wallet - Windows Build Script (Native MSVC/MinGW)
|
||||
REM Run from Visual Studio Developer Command Prompt or MSYS2 MinGW64
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo DragonX Wallet - Windows Build
|
||||
echo ==============================
|
||||
|
||||
REM Check for CMake
|
||||
where cmake >nul 2>nul
|
||||
if %errorlevel% neq 0 (
|
||||
echo Error: CMake not found! Please install CMake and add to PATH.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Create build directory
|
||||
if not exist build-win mkdir build-win
|
||||
cd build-win
|
||||
|
||||
REM Detect compiler
|
||||
where cl >nul 2>nul
|
||||
if %errorlevel% equ 0 (
|
||||
echo Using MSVC compiler
|
||||
set GENERATOR=-G "Visual Studio 17 2022" -A x64
|
||||
) else (
|
||||
where gcc >nul 2>nul
|
||||
if %errorlevel% equ 0 (
|
||||
echo Using MinGW/GCC compiler
|
||||
set GENERATOR=-G "MinGW Makefiles"
|
||||
) else (
|
||||
echo Error: No compiler found! Run from VS Developer Command Prompt or MSYS2.
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Configuring with CMake...
|
||||
cmake .. %GENERATOR% -DCMAKE_BUILD_TYPE=Release -DDRAGONX_USE_SYSTEM_SDL3=OFF
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo CMake configuration failed!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Building...
|
||||
cmake --build . --config Release --parallel
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo Build failed!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Build successful!
|
||||
echo Output: build-win\bin\Release\ObsidianDragon.exe (MSVC)
|
||||
echo or: build-win\bin\ObsidianDragon.exe (MinGW)
|
||||
|
||||
endlocal
|
||||
477
scripts/legacy/build-windows.sh
Executable file
477
scripts/legacy/build-windows.sh
Executable file
@@ -0,0 +1,477 @@
|
||||
#!/bin/bash
|
||||
# DragonX Wallet - Windows Cross-Compile Build Script
|
||||
# Requires: mingw-w64 toolchain with POSIX threads
|
||||
#
|
||||
# On Ubuntu/Debian:
|
||||
# sudo apt install mingw-w64 cmake
|
||||
# sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix
|
||||
# sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
|
||||
#
|
||||
# On Arch Linux:
|
||||
# sudo pacman -S mingw-w64-gcc cmake
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
BUILD_DIR="$SCRIPT_DIR/build/windows"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${GREEN}DragonX Wallet - Windows Cross-Compile Build${NC}"
|
||||
echo "=============================================="
|
||||
|
||||
# Check for mingw toolchain (prefer POSIX variant)
|
||||
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"
|
||||
echo -e "${GREEN}Using POSIX thread model (recommended)${NC}"
|
||||
elif command -v x86_64-w64-mingw32-gcc &> /dev/null; then
|
||||
# Check if it's the posix variant
|
||||
if x86_64-w64-mingw32-gcc -v 2>&1 | grep -q "posix"; then
|
||||
MINGW_GCC="x86_64-w64-mingw32-gcc"
|
||||
MINGW_GXX="x86_64-w64-mingw32-g++"
|
||||
echo -e "${GREEN}Using POSIX thread model${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Warning: Using win32 thread model - may have threading issues${NC}"
|
||||
echo "Run these commands to switch to POSIX threads:"
|
||||
echo " sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix"
|
||||
echo " sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix"
|
||||
MINGW_GCC="x86_64-w64-mingw32-gcc"
|
||||
MINGW_GXX="x86_64-w64-mingw32-g++"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}Error: mingw-w64 not found!${NC}"
|
||||
echo "Install with:"
|
||||
echo " Ubuntu/Debian: sudo apt install mingw-w64"
|
||||
echo " Arch Linux: sudo pacman -S mingw-w64-gcc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "C compiler: $MINGW_GCC"
|
||||
echo "C++ compiler: $MINGW_GXX"
|
||||
|
||||
# Clean and create build directory
|
||||
if [ "$1" == "clean" ]; then
|
||||
echo -e "${YELLOW}Cleaning build directory...${NC}"
|
||||
rm -rf "$BUILD_DIR"
|
||||
fi
|
||||
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Create CMake toolchain file for MinGW
|
||||
cat > mingw-toolchain.cmake << EOF
|
||||
# MinGW-w64 Cross-Compilation Toolchain
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
# Compilers (using POSIX threads)
|
||||
set(CMAKE_C_COMPILER $MINGW_GCC)
|
||||
set(CMAKE_CXX_COMPILER $MINGW_GXX)
|
||||
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
|
||||
|
||||
# Target environment
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
|
||||
|
||||
# Search for programs in the build host directories
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
|
||||
# Search for libraries and headers in the target directories
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
# Static linking - no DLLs needed
|
||||
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")
|
||||
|
||||
# Prefer static libraries
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
EOF
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Generate embedded resources (Sapling params, asmap.dat)
|
||||
# -----------------------------------------------------------------------------
|
||||
echo -e "${GREEN}Generating embedded resources...${NC}"
|
||||
|
||||
GENERATED_DIR="$BUILD_DIR/generated"
|
||||
mkdir -p "$GENERATED_DIR"
|
||||
|
||||
# Find resource files
|
||||
SAPLING_SPEND=""
|
||||
SAPLING_OUTPUT=""
|
||||
ASMAP_DAT=""
|
||||
|
||||
# Look for Sapling params
|
||||
PARAMS_PATHS=(
|
||||
"$HOME/.zcash-params"
|
||||
"$HOME/.hush-params"
|
||||
"$SCRIPT_DIR/../SilentDragonX"
|
||||
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
|
||||
"$SCRIPT_DIR"
|
||||
)
|
||||
|
||||
for ppath in "${PARAMS_PATHS[@]}"; do
|
||||
if [ -f "$ppath/sapling-spend.params" ] && [ -f "$ppath/sapling-output.params" ]; then
|
||||
SAPLING_SPEND="$ppath/sapling-spend.params"
|
||||
SAPLING_OUTPUT="$ppath/sapling-output.params"
|
||||
echo " Found Sapling params in $ppath"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Look for asmap.dat
|
||||
ASMAP_PATHS=(
|
||||
"$HOME/hush3/asmap.dat"
|
||||
"$HOME/hush3/contrib/asmap/asmap.dat"
|
||||
"$SCRIPT_DIR/../asmap.dat"
|
||||
"$SCRIPT_DIR/asmap.dat"
|
||||
"$SCRIPT_DIR/../SilentDragonX/asmap.dat"
|
||||
)
|
||||
|
||||
for apath in "${ASMAP_PATHS[@]}"; do
|
||||
if [ -f "$apath" ]; then
|
||||
ASMAP_DAT="$apath"
|
||||
echo " Found asmap.dat at $apath"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Generate embedded_data.h using INCBIN (assembler .incbin directive).
|
||||
#
|
||||
# Instead of converting binaries to giant hex arrays (530MB+ C source),
|
||||
# we copy the raw files into generated/res/ and generate a small header
|
||||
# that uses INCBIN() macros. The assembler streams the bytes directly
|
||||
# into the object file, using near-zero compile-time RAM.
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ -n "$SAPLING_SPEND" ] && [ -n "$SAPLING_OUTPUT" ]; then
|
||||
echo -e "${GREEN}Embedding resources via INCBIN (assembler .incbin)...${NC}"
|
||||
|
||||
# Stage raw binaries into generated/res/ so .incbin can find them
|
||||
EMBED_RES_DIR="$GENERATED_DIR/res"
|
||||
mkdir -p "$EMBED_RES_DIR"
|
||||
|
||||
cp -f "$SAPLING_SPEND" "$EMBED_RES_DIR/sapling-spend.params"
|
||||
echo " Staged sapling-spend.params ($(du -h "$SAPLING_SPEND" | cut -f1))"
|
||||
cp -f "$SAPLING_OUTPUT" "$EMBED_RES_DIR/sapling-output.params"
|
||||
echo " Staged sapling-output.params ($(du -h "$SAPLING_OUTPUT" | cut -f1))"
|
||||
|
||||
if [ -n "$ASMAP_DAT" ]; then
|
||||
cp -f "$ASMAP_DAT" "$EMBED_RES_DIR/asmap.dat"
|
||||
echo " Staged asmap.dat ($(du -h "$ASMAP_DAT" | cut -f1))"
|
||||
HAS_ASMAP=1
|
||||
else
|
||||
HAS_ASMAP=0
|
||||
fi
|
||||
|
||||
# Start writing the header — use absolute paths for .incbin
|
||||
cat > "$GENERATED_DIR/embedded_data.h" << HEADER_START
|
||||
// Auto-generated embedded resource data — INCBIN edition
|
||||
// DO NOT EDIT — generated by build-windows.sh
|
||||
//
|
||||
// Uses assembler .incbin directive via incbin.h so the compiler never
|
||||
// has to parse hundreds of millions of hex literals. Compile-time RAM
|
||||
// drops from 12 GB+ to well under 1 GB.
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "incbin.h"
|
||||
|
||||
// ---- Sapling params (always present when this header exists) ----
|
||||
INCBIN(sapling_spend_params, "$EMBED_RES_DIR/sapling-spend.params");
|
||||
INCBIN(sapling_output_params, "$EMBED_RES_DIR/sapling-output.params");
|
||||
|
||||
HEADER_START
|
||||
|
||||
# asmap.dat
|
||||
if [ "$HAS_ASMAP" = "1" ]; then
|
||||
echo "INCBIN(asmap_dat, \"$EMBED_RES_DIR/asmap.dat\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
else
|
||||
echo 'extern "C" { static const uint8_t* g_asmap_dat_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo 'static const unsigned int g_asmap_dat_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
|
||||
fi
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
# Daemon binaries
|
||||
DAEMON_DIR="$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
|
||||
if [ -d "$DAEMON_DIR" ] && [ -f "$DAEMON_DIR/hushd.exe" ]; then
|
||||
echo -e "${GREEN}Embedding daemon binaries via INCBIN...${NC}"
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "#define HAS_EMBEDDED_DAEMON 1" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
cp -f "$DAEMON_DIR/hushd.exe" "$EMBED_RES_DIR/hushd.exe"
|
||||
echo " Staged hushd.exe ($(du -h "$DAEMON_DIR/hushd.exe" | cut -f1))"
|
||||
echo "INCBIN(hushd_exe, \"$EMBED_RES_DIR/hushd.exe\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
if [ -f "$DAEMON_DIR/hush-cli.exe" ]; then
|
||||
cp -f "$DAEMON_DIR/hush-cli.exe" "$EMBED_RES_DIR/hush-cli.exe"
|
||||
echo " Staged hush-cli.exe ($(du -h "$DAEMON_DIR/hush-cli.exe" | cut -f1))"
|
||||
echo "INCBIN(hush_cli_exe, \"$EMBED_RES_DIR/hush-cli.exe\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
else
|
||||
echo 'extern "C" { static const uint8_t* g_hush_cli_exe_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo 'static const unsigned int g_hush_cli_exe_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
|
||||
fi
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
if [ -f "$DAEMON_DIR/dragonxd.bat" ]; then
|
||||
cp -f "$DAEMON_DIR/dragonxd.bat" "$EMBED_RES_DIR/dragonxd.bat"
|
||||
echo " Staged dragonxd.bat"
|
||||
echo "INCBIN(dragonxd_bat, \"$EMBED_RES_DIR/dragonxd.bat\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
else
|
||||
echo 'extern "C" { static const uint8_t* g_dragonxd_bat_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo 'static const unsigned int g_dragonxd_bat_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
|
||||
fi
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
if [ -f "$DAEMON_DIR/hush-tx.exe" ]; then
|
||||
cp -f "$DAEMON_DIR/hush-tx.exe" "$EMBED_RES_DIR/hush-tx.exe"
|
||||
echo " Staged hush-tx.exe ($(du -h "$DAEMON_DIR/hush-tx.exe" | cut -f1))"
|
||||
echo "INCBIN(hush_tx_exe, \"$EMBED_RES_DIR/hush-tx.exe\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
else
|
||||
echo 'extern "C" { static const uint8_t* g_hush_tx_exe_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo 'static const unsigned int g_hush_tx_exe_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
|
||||
fi
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
if [ -f "$DAEMON_DIR/dragonx-cli.bat" ]; then
|
||||
cp -f "$DAEMON_DIR/dragonx-cli.bat" "$EMBED_RES_DIR/dragonx-cli.bat"
|
||||
echo " Staged dragonx-cli.bat"
|
||||
echo "INCBIN(dragonx_cli_bat, \"$EMBED_RES_DIR/dragonx-cli.bat\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
else
|
||||
echo 'extern "C" { static const uint8_t* g_dragonx_cli_bat_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo 'static const unsigned int g_dragonx_cli_bat_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
|
||||
fi
|
||||
|
||||
else
|
||||
echo -e "${YELLOW}Note: Daemon binaries not found in prebuilt-binaries/dragonxd-win/ — wallet only${NC}"
|
||||
fi
|
||||
|
||||
# ── xmrig binary (from prebuilt-binaries/xmrig-hac/) ────────────────
|
||||
XMRIG_DIR="$SCRIPT_DIR/prebuilt-binaries/xmrig-hac"
|
||||
if [ -f "$XMRIG_DIR/xmrig.exe" ]; then
|
||||
cp -f "$XMRIG_DIR/xmrig.exe" "$EMBED_RES_DIR/xmrig.exe"
|
||||
echo " Staged xmrig.exe ($(du -h "$XMRIG_DIR/xmrig.exe" | cut -f1))"
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "#define HAS_EMBEDDED_XMRIG 1" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "INCBIN(xmrig_exe, \"$EMBED_RES_DIR/xmrig.exe\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
else
|
||||
echo 'extern "C" { static const uint8_t* g_xmrig_exe_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo 'static const unsigned int g_xmrig_exe_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
|
||||
fi
|
||||
|
||||
# ---- Theme images (backgrounds + logos) ----
|
||||
# Embed ALL images from res/img/backgrounds/ subdirectories and res/img/logos/
|
||||
# so the Windows single-file distribution can display theme backgrounds and logos
|
||||
# without needing res/ on disk.
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "// ---- Embedded theme images ----" >> "$GENERATED_DIR/embedded_data.h"
|
||||
IMAGE_TABLE_ENTRIES=""
|
||||
IMAGE_COUNT=0
|
||||
for IMG_DIR in "$SCRIPT_DIR/res/img/backgrounds/texture" "$SCRIPT_DIR/res/img/backgrounds/gradient" "$SCRIPT_DIR/res/img/logos"; do
|
||||
if [ -d "$IMG_DIR" ]; then
|
||||
for IMG_FILE in "$IMG_DIR"/*.png; do
|
||||
[ -f "$IMG_FILE" ] || continue
|
||||
IMG_BASENAME=$(basename "$IMG_FILE")
|
||||
IMG_SYMBOL=$(echo "$IMG_BASENAME" | sed 's/[^a-zA-Z0-9]/_/g')
|
||||
echo " Staged image: $IMG_BASENAME ($(du -h "$IMG_FILE" | cut -f1))"
|
||||
cp -f "$IMG_FILE" "$EMBED_RES_DIR/$IMG_BASENAME"
|
||||
echo "INCBIN(img_${IMG_SYMBOL}, \"$EMBED_RES_DIR/$IMG_BASENAME\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
IMAGE_TABLE_ENTRIES="${IMAGE_TABLE_ENTRIES} { g_img_${IMG_SYMBOL}_data, g_img_${IMG_SYMBOL}_size, \"${IMG_BASENAME}\" },\n"
|
||||
IMAGE_COUNT=$((IMAGE_COUNT + 1))
|
||||
done
|
||||
fi
|
||||
done
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "#define HAS_EMBEDDED_IMAGES 1" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "#define EMBEDDED_IMAGE_COUNT $IMAGE_COUNT" >> "$GENERATED_DIR/embedded_data.h"
|
||||
# Backward compat defines (referenced by s_resources[] guards)
|
||||
echo "#define HAS_EMBEDDED_GRADIENT 1" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "#define HAS_EMBEDDED_LOGO 1" >> "$GENERATED_DIR/embedded_data.h"
|
||||
# Backward compat aliases for the old symbol names
|
||||
echo "static const uint8_t* g_dark_gradient_png_data = g_img_dark_gradient_png_data;" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "static const unsigned int g_dark_gradient_png_size = g_img_dark_gradient_png_size;" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "static const uint8_t* g_logo_ObsidianDragon_dark_png_data = g_img_logo_ObsidianDragon_dark_png_data;" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "static const unsigned int g_logo_ObsidianDragon_dark_png_size = g_img_logo_ObsidianDragon_dark_png_size;" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "struct EmbeddedImageEntry { const uint8_t* data; unsigned int size; const char* filename; };" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "static const EmbeddedImageEntry s_embedded_images[] = {" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo -e "$IMAGE_TABLE_ENTRIES" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo " { nullptr, 0, nullptr }" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "};" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
# Embed bundled overlay themes (dark.toml, light.toml, obsidian.toml, etc.)
|
||||
# These are extracted to the config dir on first run so the theme selector can find them.
|
||||
THEMES_DIR="$SCRIPT_DIR/res/themes"
|
||||
THEME_COUNT=0
|
||||
THEME_TABLE_ENTRIES=""
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "// ---- Bundled overlay themes ----" >> "$GENERATED_DIR/embedded_data.h"
|
||||
for THEME_FILE in "$THEMES_DIR"/*.toml; do
|
||||
THEME_BASENAME=$(basename "$THEME_FILE")
|
||||
# Skip ui.toml — it's embedded separately via cmake
|
||||
if [ "$THEME_BASENAME" = "ui.toml" ]; then
|
||||
continue
|
||||
fi
|
||||
THEME_SYMBOL=$(echo "$THEME_BASENAME" | sed 's/[^a-zA-Z0-9]/_/g')
|
||||
cp -f "$THEME_FILE" "$EMBED_RES_DIR/$THEME_BASENAME"
|
||||
echo " Staged $THEME_BASENAME"
|
||||
echo "INCBIN(theme_${THEME_SYMBOL}, \"$EMBED_RES_DIR/$THEME_BASENAME\");" >> "$GENERATED_DIR/embedded_data.h"
|
||||
THEME_TABLE_ENTRIES="${THEME_TABLE_ENTRIES} { g_theme_${THEME_SYMBOL}_data, g_theme_${THEME_SYMBOL}_size, \"${THEME_BASENAME}\" },\n"
|
||||
THEME_COUNT=$((THEME_COUNT + 1))
|
||||
done
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "#define EMBEDDED_THEME_COUNT $THEME_COUNT" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
# Generate the theme table struct
|
||||
echo "// Auto-generated theme table" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "struct EmbeddedThemeEntry { const uint8_t* data; unsigned int size; const char* filename; };" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "static const EmbeddedThemeEntry s_embedded_themes[] = {" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo -e "$THEME_TABLE_ENTRIES" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo " { nullptr, 0, nullptr }" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "};" >> "$GENERATED_DIR/embedded_data.h"
|
||||
echo "" >> "$GENERATED_DIR/embedded_data.h"
|
||||
|
||||
echo -e "${GREEN}Embedded resources header generated (INCBIN — near-zero compile RAM)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Warning: Sapling params not found — building without embedded resources${NC}"
|
||||
echo "The wallet will require external param files."
|
||||
fi
|
||||
|
||||
# Ensure libsodium is available for Windows cross-compile
|
||||
if [ ! -f "$SCRIPT_DIR/libs/libsodium-win/lib/libsodium.a" ]; then
|
||||
echo -e "${YELLOW}libsodium for Windows not found, fetching...${NC}"
|
||||
"$SCRIPT_DIR/scripts/fetch-libsodium.sh" --win
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Configuring with CMake...${NC}"
|
||||
cmake .. \
|
||||
-DCMAKE_TOOLCHAIN_FILE=mingw-toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DDRAGONX_USE_SYSTEM_SDL3=OFF
|
||||
|
||||
echo -e "${GREEN}Building...${NC}"
|
||||
cmake --build . -j$(nproc)
|
||||
|
||||
# Check if build succeeded
|
||||
if [ -f "bin/ObsidianDragon.exe" ]; then
|
||||
echo ""
|
||||
echo -e "${GREEN}Build successful!${NC}"
|
||||
echo "Output: $BUILD_DIR/bin/ObsidianDragon.exe"
|
||||
|
||||
# Show file size and check if statically linked
|
||||
ls -lh bin/ObsidianDragon.exe
|
||||
echo ""
|
||||
echo -e "${GREEN}Statically linked - no DLLs required!${NC}"
|
||||
|
||||
# Bundle daemon files if available from dragonxd-win directory
|
||||
DAEMON_DIR="$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
|
||||
DAEMON_BUNDLED=0
|
||||
|
||||
if [ -d "$DAEMON_DIR" ]; then
|
||||
echo -e "${GREEN}Found daemon directory: $DAEMON_DIR${NC}"
|
||||
|
||||
# Copy all daemon files
|
||||
if [ -f "$DAEMON_DIR/dragonxd.bat" ]; then
|
||||
cp "$DAEMON_DIR/dragonxd.bat" bin/
|
||||
echo " - dragonxd.bat"
|
||||
DAEMON_BUNDLED=1
|
||||
fi
|
||||
if [ -f "$DAEMON_DIR/dragonx-cli.bat" ]; then
|
||||
cp "$DAEMON_DIR/dragonx-cli.bat" bin/
|
||||
echo " - dragonx-cli.bat"
|
||||
fi
|
||||
if [ -f "$DAEMON_DIR/hushd.exe" ]; then
|
||||
cp "$DAEMON_DIR/hushd.exe" bin/
|
||||
echo " - hushd.exe ($(du -h "$DAEMON_DIR/hushd.exe" | cut -f1))"
|
||||
fi
|
||||
if [ -f "$DAEMON_DIR/hush-cli.exe" ]; then
|
||||
cp "$DAEMON_DIR/hush-cli.exe" bin/
|
||||
echo " - hush-cli.exe"
|
||||
fi
|
||||
if [ -f "$DAEMON_DIR/hush-tx.exe" ]; then
|
||||
cp "$DAEMON_DIR/hush-tx.exe" bin/
|
||||
echo " - hush-tx.exe"
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}Daemon directory not found: $DAEMON_DIR${NC}"
|
||||
echo " Place prebuilt-binaries/dragonxd-win/ in the project directory to bundle the daemon."
|
||||
fi
|
||||
|
||||
# Create distribution package
|
||||
echo ""
|
||||
echo -e "${GREEN}Creating distribution package...${NC}"
|
||||
cd bin
|
||||
DIST_NAME="DragonX-Wallet-Windows-x64"
|
||||
rm -rf "$DIST_NAME" "$DIST_NAME.zip"
|
||||
mkdir -p "$DIST_NAME"
|
||||
cp ObsidianDragon.exe "$DIST_NAME/"
|
||||
# Copy all daemon files
|
||||
[ -f dragonxd.bat ] && cp dragonxd.bat "$DIST_NAME/"
|
||||
[ -f dragonx-cli.bat ] && cp dragonx-cli.bat "$DIST_NAME/"
|
||||
[ -f hushd.exe ] && cp hushd.exe "$DIST_NAME/"
|
||||
[ -f hush-cli.exe ] && cp hush-cli.exe "$DIST_NAME/"
|
||||
[ -f hush-tx.exe ] && cp hush-tx.exe "$DIST_NAME/"
|
||||
|
||||
# Create README
|
||||
cat > "$DIST_NAME/README.txt" << 'READMEEOF'
|
||||
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\
|
||||
|
||||
The wallet will look for the daemon config at:
|
||||
%APPDATA%\Hush\DRAGONX\DRAGONX.conf
|
||||
|
||||
This will be auto-created on first run if the daemon is present.
|
||||
|
||||
For support: https://git.hush.is/hush/ObsidianDragon
|
||||
READMEEOF
|
||||
|
||||
if command -v zip &> /dev/null; then
|
||||
zip -r "$DIST_NAME.zip" "$DIST_NAME"
|
||||
# Copy zip + single-file exe to release/windows/
|
||||
local OUT_DIR="$SCRIPT_DIR/release/windows"
|
||||
mkdir -p "$OUT_DIR"
|
||||
cp "$DIST_NAME.zip" "$OUT_DIR/"
|
||||
cp ObsidianDragon.exe "$OUT_DIR/"
|
||||
echo -e "${GREEN}Distribution package: $OUT_DIR/$DIST_NAME.zip${NC}"
|
||||
echo -e "${GREEN}Single-file exe: $OUT_DIR/ObsidianDragon.exe${NC}"
|
||||
ls -lh "$OUT_DIR/"
|
||||
else
|
||||
echo "Install 'zip' to create distribution archive"
|
||||
fi
|
||||
|
||||
cd ..
|
||||
echo ""
|
||||
echo -e "${GREEN}============================================${NC}"
|
||||
echo -e "${GREEN}SINGLE-FILE DISTRIBUTION READY!${NC}"
|
||||
echo -e "${GREEN}============================================${NC}"
|
||||
echo ""
|
||||
echo "The executable contains embedded:"
|
||||
echo " - Sapling spend params (~48MB)"
|
||||
echo " - Sapling output params (~3MB)"
|
||||
echo " - asmap.dat (~1MB)"
|
||||
echo ""
|
||||
echo "Just copy ObsidianDragon.exe to Windows and run it!"
|
||||
echo "Resources will be extracted automatically on first launch."
|
||||
else
|
||||
echo -e "${RED}Build failed!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
414
scripts/setup.sh
Executable file
414
scripts/setup.sh
Executable file
@@ -0,0 +1,414 @@
|
||||
#!/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 "═══════════════════════════════════════════"
|
||||
Reference in New Issue
Block a user