Preserve the previously-uncommitted lite wallet implementation and related dev WIP under version control: - src/wallet/ lite services: client bridge, bridge runtime, connection, lifecycle, sync, gateway, result parsers, state mapper, artifact contract/resolver, refresh services, UI adapters, wallet_backend/capabilities. (Includes two small M1 fixes: lifecycle walletReady now parses the response; default chain name -> "main".) - src/chat/ chat protocol; tests/fixtures/ (lite + hushchat); tools/hushchat_fixture_check.cpp; scripts/build-lite-backend-artifact.sh. - Pre-existing modified app_network/security/wizard, network_refresh_service, sidebar, mining_tab, bootstrap dialog, and version headers captured as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
769 lines
29 KiB
Bash
Executable File
769 lines
29 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
|
ABI_VERSION="sdxl-c-v1"
|
|
LINK_MODE="imported"
|
|
BACKEND_DIR="$PROJECT_ROOT/external/SilentDragonXLite/lib"
|
|
BACKEND_SOURCE_DIR=""
|
|
BUILD_BACKEND_DIR=""
|
|
BACKEND_DEPENDENCY_DIR=""
|
|
BACKEND_DEPENDENCY_OVERRIDE_REQUESTED=false
|
|
OUT_DIR="$PROJECT_ROOT/build/lite-backend"
|
|
PLATFORM=""
|
|
RUST_TARGET=""
|
|
CARGO_TARGET_DIR_VALUE="${CARGO_TARGET_DIR:-}"
|
|
ARTIFACT_PATH=""
|
|
BUILD_ARTIFACT=true
|
|
BUILDER="${DRAGONX_LITE_BACKEND_BUILDER:-local}"
|
|
JOBS="${JOBS:-}"
|
|
SOURCE_DATE_EPOCH_VALUE="${SOURCE_DATE_EPOCH:-}"
|
|
REPRODUCIBLE=false
|
|
SIGNATURE_REQUIRED=false
|
|
SIGNATURE_FILE=""
|
|
SIGNATURE_FORMAT=""
|
|
SIGNATURE_VERIFICATION_TOOL=""
|
|
SIGNATURE_VERIFICATION_COMMAND=""
|
|
SIGNATURE_KEY_FINGERPRINT=""
|
|
SIGNATURE_CERTIFICATE_IDENTITY=""
|
|
SIGNATURE_CERTIFICATE_ISSUER=""
|
|
SIGNATURE_TRANSPARENCY_LOG_URL=""
|
|
SIGNATURE_VERIFIED_SHA256=""
|
|
SIGNATURE_POLICY_NAME="dragonx-lite-backend-signature-policy-v1"
|
|
SIGNATURE_POLICY_DEFINED_MANIFEST_VALUE=true
|
|
SIGNATURE_REQUIRED_MANIFEST_VALUE=false
|
|
SIGNATURE_METADATA_PROVIDED=false
|
|
SIGNATURE_VERIFICATION_PERFORMED=false
|
|
SIGNATURE_VERIFICATION_STATUS="not-provided"
|
|
SIGNATURE_FILE_SHA256=""
|
|
|
|
REQUIRED_SYMBOLS=(
|
|
litelib_wallet_exists
|
|
litelib_initialize_new
|
|
litelib_initialize_new_from_phrase
|
|
litelib_initialize_existing
|
|
litelib_execute
|
|
litelib_rust_free_string
|
|
litelib_check_server_online
|
|
litelib_shutdown
|
|
)
|
|
|
|
EXTRA_CARGO_ARGS=()
|
|
EXTRA_REMAP_PATH_PREFIXES=()
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Build or inventory the SDXL-compatible lite backend artifact.
|
|
|
|
Usage: $0 [options]
|
|
|
|
Options:
|
|
--platform linux|windows|macos Artifact platform. Defaults to host platform.
|
|
--rust-target TRIPLE Cargo target triple for cross builds.
|
|
--cargo-target-dir PATH Isolated Cargo target directory for clean builds.
|
|
--backend-dir PATH SilentDragonXLite/lib source directory.
|
|
--silentdragonxlitelib-dir PATH Override the wrapper's silentdragonxlitelib dependency path.
|
|
--out-dir PATH Output directory for copied artifact and metadata.
|
|
--artifact PATH Inventory an existing artifact instead of building.
|
|
--no-build Do not run cargo; requires --artifact.
|
|
--reproducible Add deterministic Rust path remaps for clean builds.
|
|
--remap-path-prefix FROM=TO Extra rustc path remap used with --reproducible.
|
|
--builder NAME Redacted builder/provenance label. Default: local.
|
|
--signature-required Fail if verified signature metadata is not supplied.
|
|
--signature-file PATH Existing sidecar signature file to record.
|
|
--signature-format FORMAT Signature format: minisign, gpg, sigstore, external, or other.
|
|
--signature-verification-tool T Verification tool and version used by the release builder.
|
|
--signature-verification-command C
|
|
Verification command already run by the release builder.
|
|
--signature-key-fingerprint F Reviewed public-key fingerprint, when applicable.
|
|
--signature-certificate-identity ID
|
|
Reviewed certificate identity, when applicable.
|
|
--signature-certificate-issuer I
|
|
Reviewed certificate issuer, when applicable.
|
|
--signature-transparency-log-url URL
|
|
Transparency log entry, when applicable.
|
|
--signature-verified-sha256 SHA Artifact SHA-256 verified by the signature check.
|
|
-j, --jobs N Cargo parallel jobs.
|
|
--cargo-arg ARG Extra argument forwarded to cargo build.
|
|
-h, --help Show this help.
|
|
|
|
Outputs:
|
|
<out>/<platform>/<artifact>
|
|
<out>/<platform>/lite-backend-symbols.txt
|
|
<out>/<platform>/lite-backend-artifact-manifest.json
|
|
|
|
The script captures symbols, checksums, and optional read-only signature
|
|
verification metadata only. It does not load the library, resolve function
|
|
pointers, call SDXL, sign, upload, or publish artifacts.
|
|
EOF
|
|
}
|
|
|
|
info() { printf '[lite-backend] %s\n' "$*"; }
|
|
warn() { printf '[lite-backend] warning: %s\n' "$*" >&2; }
|
|
die() { printf '[lite-backend] ERROR: %s\n' "$*" >&2; exit 1; }
|
|
|
|
absolute_path() {
|
|
local path="$1"
|
|
if [[ "$path" = /* ]]; then
|
|
printf '%s\n' "$path"
|
|
else
|
|
printf '%s/%s\n' "$PWD" "$path"
|
|
fi
|
|
}
|
|
|
|
host_platform() {
|
|
case "$(uname -s)" in
|
|
Linux) printf 'linux\n' ;;
|
|
Darwin) printf 'macos\n' ;;
|
|
MINGW*|MSYS*|CYGWIN*) printf 'windows\n' ;;
|
|
*) die "unsupported host platform: $(uname -s)" ;;
|
|
esac
|
|
}
|
|
|
|
normalize_platform() {
|
|
case "$1" in
|
|
linux|Linux) printf 'linux\n' ;;
|
|
windows|win|Win|Windows) printf 'windows\n' ;;
|
|
macos|mac|darwin|Darwin) printf 'macos\n' ;;
|
|
"") host_platform ;;
|
|
*) die "unsupported platform: $1" ;;
|
|
esac
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--platform)
|
|
[[ $# -ge 2 ]] || die "--platform requires a value"
|
|
PLATFORM="$(normalize_platform "$2")"
|
|
shift 2
|
|
;;
|
|
--rust-target)
|
|
[[ $# -ge 2 ]] || die "--rust-target requires a value"
|
|
RUST_TARGET="$2"
|
|
shift 2
|
|
;;
|
|
--cargo-target-dir)
|
|
[[ $# -ge 2 ]] || die "--cargo-target-dir requires a value"
|
|
CARGO_TARGET_DIR_VALUE="$(absolute_path "$2")"
|
|
shift 2
|
|
;;
|
|
--backend-dir)
|
|
[[ $# -ge 2 ]] || die "--backend-dir requires a value"
|
|
BACKEND_DIR="$(absolute_path "$2")"
|
|
shift 2
|
|
;;
|
|
--silentdragonxlitelib-dir)
|
|
[[ $# -ge 2 ]] || die "--silentdragonxlitelib-dir requires a value"
|
|
BACKEND_DEPENDENCY_DIR="$(absolute_path "$2")"
|
|
BACKEND_DEPENDENCY_OVERRIDE_REQUESTED=true
|
|
shift 2
|
|
;;
|
|
--out-dir)
|
|
[[ $# -ge 2 ]] || die "--out-dir requires a value"
|
|
OUT_DIR="$(absolute_path "$2")"
|
|
shift 2
|
|
;;
|
|
--artifact)
|
|
[[ $# -ge 2 ]] || die "--artifact requires a value"
|
|
ARTIFACT_PATH="$(absolute_path "$2")"
|
|
BUILD_ARTIFACT=false
|
|
shift 2
|
|
;;
|
|
--no-build)
|
|
BUILD_ARTIFACT=false
|
|
shift
|
|
;;
|
|
--reproducible)
|
|
REPRODUCIBLE=true
|
|
shift
|
|
;;
|
|
--remap-path-prefix)
|
|
[[ $# -ge 2 ]] || die "--remap-path-prefix requires FROM=TO"
|
|
[[ "$2" == *=* ]] || die "--remap-path-prefix requires FROM=TO"
|
|
EXTRA_REMAP_PATH_PREFIXES+=("$2")
|
|
shift 2
|
|
;;
|
|
--builder)
|
|
[[ $# -ge 2 ]] || die "--builder requires a value"
|
|
BUILDER="$2"
|
|
shift 2
|
|
;;
|
|
--signature-required)
|
|
SIGNATURE_REQUIRED=true
|
|
shift
|
|
;;
|
|
--signature-file|--signature-path)
|
|
[[ $# -ge 2 ]] || die "$1 requires a value"
|
|
SIGNATURE_FILE="$(absolute_path "$2")"
|
|
shift 2
|
|
;;
|
|
--signature-format)
|
|
[[ $# -ge 2 ]] || die "--signature-format requires a value"
|
|
SIGNATURE_FORMAT="$2"
|
|
shift 2
|
|
;;
|
|
--signature-verification-tool|--signature-tool)
|
|
[[ $# -ge 2 ]] || die "$1 requires a value"
|
|
SIGNATURE_VERIFICATION_TOOL="$2"
|
|
shift 2
|
|
;;
|
|
--signature-verification-command)
|
|
[[ $# -ge 2 ]] || die "--signature-verification-command requires a value"
|
|
SIGNATURE_VERIFICATION_COMMAND="$2"
|
|
shift 2
|
|
;;
|
|
--signature-key-fingerprint)
|
|
[[ $# -ge 2 ]] || die "--signature-key-fingerprint requires a value"
|
|
SIGNATURE_KEY_FINGERPRINT="$2"
|
|
shift 2
|
|
;;
|
|
--signature-certificate-identity)
|
|
[[ $# -ge 2 ]] || die "--signature-certificate-identity requires a value"
|
|
SIGNATURE_CERTIFICATE_IDENTITY="$2"
|
|
shift 2
|
|
;;
|
|
--signature-certificate-issuer)
|
|
[[ $# -ge 2 ]] || die "--signature-certificate-issuer requires a value"
|
|
SIGNATURE_CERTIFICATE_ISSUER="$2"
|
|
shift 2
|
|
;;
|
|
--signature-transparency-log-url)
|
|
[[ $# -ge 2 ]] || die "--signature-transparency-log-url requires a value"
|
|
SIGNATURE_TRANSPARENCY_LOG_URL="$2"
|
|
shift 2
|
|
;;
|
|
--signature-verified-sha256)
|
|
[[ $# -ge 2 ]] || die "--signature-verified-sha256 requires a value"
|
|
SIGNATURE_VERIFIED_SHA256="$2"
|
|
shift 2
|
|
;;
|
|
-j|--jobs)
|
|
[[ $# -ge 2 ]] || die "--jobs requires a value"
|
|
JOBS="$2"
|
|
shift 2
|
|
;;
|
|
--cargo-arg)
|
|
[[ $# -ge 2 ]] || die "--cargo-arg requires a value"
|
|
EXTRA_CARGO_ARGS+=("$2")
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*) die "unknown option: $1" ;;
|
|
esac
|
|
done
|
|
|
|
PLATFORM="$(normalize_platform "$PLATFORM")"
|
|
BACKEND_SOURCE_DIR="$BACKEND_DIR"
|
|
BUILD_BACKEND_DIR="$BACKEND_SOURCE_DIR"
|
|
|
|
if [[ "$PLATFORM" == "windows" && -z "$RUST_TARGET" ]]; then
|
|
RUST_TARGET="x86_64-pc-windows-gnu"
|
|
fi
|
|
if [[ "$PLATFORM" == "macos" && -z "$RUST_TARGET" && "$(host_platform)" != "macos" ]]; then
|
|
die "macOS artifacts require --rust-target when not running on macOS"
|
|
fi
|
|
if [[ "$BUILD_ARTIFACT" == false && -z "$ARTIFACT_PATH" ]]; then
|
|
die "--no-build requires --artifact"
|
|
fi
|
|
|
|
backend_dependency_path_from_cargo() {
|
|
local cargo_toml="$1"
|
|
awk '
|
|
/^[[:space:]]*silentdragonxlitelib[[:space:]]*=/ {
|
|
original = $0
|
|
path = $0
|
|
sub(/.*path[[:space:]]*=[[:space:]]*"/, "", path)
|
|
sub(/".*/, "", path)
|
|
if (path != original) print path
|
|
exit
|
|
}
|
|
' "$cargo_toml"
|
|
}
|
|
|
|
canonical_dependency_path() {
|
|
local path="$1"
|
|
if [[ -d "$path" ]]; then
|
|
(cd "$path" && pwd -P)
|
|
else
|
|
absolute_path "$path"
|
|
fi
|
|
}
|
|
|
|
validate_backend_dependency_source() {
|
|
[[ -n "$BACKEND_DEPENDENCY_DIR" ]] || return
|
|
|
|
if [[ ! -f "$BACKEND_DEPENDENCY_DIR/Cargo.toml" ]]; then
|
|
if [[ "$BUILD_ARTIFACT" == true || "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == true ]]; then
|
|
die "Cargo.toml not found in $BACKEND_DEPENDENCY_DIR"
|
|
fi
|
|
warn "Cargo.toml not found in silentdragonxlitelib source: $BACKEND_DEPENDENCY_DIR"
|
|
return
|
|
fi
|
|
|
|
if ! grep -Eq '^[[:space:]]*name[[:space:]]*=[[:space:]]*"silentdragonxlitelib"' "$BACKEND_DEPENDENCY_DIR/Cargo.toml"; then
|
|
if [[ "$BUILD_ARTIFACT" == true || "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == true ]]; then
|
|
die "dependency path does not look like silentdragonxlitelib: $BACKEND_DEPENDENCY_DIR"
|
|
fi
|
|
warn "dependency path does not look like silentdragonxlitelib: $BACKEND_DEPENDENCY_DIR"
|
|
fi
|
|
}
|
|
|
|
prepare_backend_source() {
|
|
BUILD_BACKEND_DIR="$BACKEND_SOURCE_DIR"
|
|
|
|
if [[ "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == false ]]; then
|
|
if [[ -f "$BACKEND_SOURCE_DIR/Cargo.toml" ]]; then
|
|
local configured_dependency_path
|
|
configured_dependency_path="$(backend_dependency_path_from_cargo "$BACKEND_SOURCE_DIR/Cargo.toml")"
|
|
if [[ -n "$configured_dependency_path" ]]; then
|
|
if [[ "$configured_dependency_path" = /* ]]; then
|
|
BACKEND_DEPENDENCY_DIR="$(canonical_dependency_path "$configured_dependency_path")"
|
|
warn "backend Cargo.toml uses an absolute silentdragonxlitelib path; use --silentdragonxlitelib-dir for portable builders"
|
|
else
|
|
BACKEND_DEPENDENCY_DIR="$(canonical_dependency_path "$BACKEND_SOURCE_DIR/$configured_dependency_path")"
|
|
info "using relative silentdragonxlitelib dependency at $BACKEND_DEPENDENCY_DIR"
|
|
fi
|
|
validate_backend_dependency_source
|
|
fi
|
|
fi
|
|
return
|
|
fi
|
|
|
|
[[ -f "$BACKEND_SOURCE_DIR/Cargo.toml" ]] || die "Cargo.toml not found in $BACKEND_SOURCE_DIR"
|
|
validate_backend_dependency_source
|
|
[[ "$BACKEND_DEPENDENCY_DIR" != *\"* ]] || die "--silentdragonxlitelib-dir path cannot contain a double quote"
|
|
|
|
local prepared_root="$OUT_DIR/.prepared-backend/$PLATFORM"
|
|
[[ "$prepared_root" == */.prepared-backend/* ]] || die "refusing unsafe prepared backend path: $prepared_root"
|
|
rm -rf "$prepared_root"
|
|
mkdir -p "$prepared_root"
|
|
|
|
ln -s "$BACKEND_SOURCE_DIR/src" "$prepared_root/src"
|
|
[[ -f "$BACKEND_SOURCE_DIR/Cargo.lock" ]] && ln -s "$BACKEND_SOURCE_DIR/Cargo.lock" "$prepared_root/Cargo.lock"
|
|
[[ -d "$BACKEND_SOURCE_DIR/.cargo" ]] && ln -s "$BACKEND_SOURCE_DIR/.cargo" "$prepared_root/.cargo"
|
|
[[ -d "$BACKEND_SOURCE_DIR/libsodium-mingw" ]] && ln -s "$BACKEND_SOURCE_DIR/libsodium-mingw" "$prepared_root/libsodium-mingw"
|
|
[[ -f "$BACKEND_SOURCE_DIR/silentdragonxlitelib.h" ]] && ln -s "$BACKEND_SOURCE_DIR/silentdragonxlitelib.h" "$prepared_root/silentdragonxlitelib.h"
|
|
|
|
local replacement="silentdragonxlitelib = { path = \"$BACKEND_DEPENDENCY_DIR\" }"
|
|
awk -v replacement="$replacement" '
|
|
BEGIN { replaced = 0 }
|
|
/^[[:space:]]*silentdragonxlitelib[[:space:]]*=/ {
|
|
print replacement
|
|
replaced = 1
|
|
next
|
|
}
|
|
{ print }
|
|
END { if (replaced != 1) exit 42 }
|
|
' "$BACKEND_SOURCE_DIR/Cargo.toml" > "$prepared_root/Cargo.toml" \
|
|
|| die "failed to prepare backend Cargo.toml with portable silentdragonxlitelib path"
|
|
|
|
BUILD_BACKEND_DIR="$prepared_root"
|
|
info "prepared backend source at $BUILD_BACKEND_DIR with silentdragonxlitelib from $BACKEND_DEPENDENCY_DIR"
|
|
}
|
|
|
|
prepare_backend_source
|
|
|
|
artifact_kind() {
|
|
local name="${1##*/}"
|
|
case "$name" in
|
|
*.a|*.lib) printf 'static-library\n' ;;
|
|
*.so|*.dylib|*.dll) printf 'shared-library\n' ;;
|
|
*) printf 'unknown\n' ;;
|
|
esac
|
|
}
|
|
|
|
cargo_output_candidates() {
|
|
local cargo_target_root="$BUILD_BACKEND_DIR/target"
|
|
if [[ -n "$CARGO_TARGET_DIR_VALUE" ]]; then
|
|
cargo_target_root="$CARGO_TARGET_DIR_VALUE"
|
|
fi
|
|
|
|
local base="$cargo_target_root/release"
|
|
if [[ -n "$RUST_TARGET" ]]; then
|
|
base="$cargo_target_root/$RUST_TARGET/release"
|
|
fi
|
|
|
|
case "$PLATFORM" in
|
|
linux)
|
|
printf '%s\n' "$base/libsilentdragonxlite.a" "$base/silentdragonxlite.a" "$base/libsilentdragonxlite.so"
|
|
;;
|
|
windows)
|
|
printf '%s\n' "$base/silentdragonxlite.lib" "$base/libsilentdragonxlite.a" "$base/silentdragonxlite.dll"
|
|
;;
|
|
macos)
|
|
printf '%s\n' "$base/libsilentdragonxlite.a" "$base/silentdragonxlite.a" "$base/libsilentdragonxlite.dylib" "$base/silentdragonxlite.dylib"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
source_revision_for() {
|
|
local dir="$1"
|
|
local revision_file
|
|
for revision_file in "$dir/DRAGONX_SOURCE_REVISION" "$dir/../DRAGONX_SOURCE_REVISION"; do
|
|
if [[ -f "$revision_file" ]]; then
|
|
sed -n '1p' "$revision_file"
|
|
return
|
|
fi
|
|
done
|
|
|
|
if git -C "$dir" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
git -C "$dir" rev-parse HEAD 2>/dev/null || printf 'unknown'
|
|
else
|
|
printf 'unknown'
|
|
fi
|
|
}
|
|
|
|
default_source_date_epoch() {
|
|
if git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
git -C "$PROJECT_ROOT" log -1 --format=%ct 2>/dev/null || printf '0'
|
|
else
|
|
printf '0'
|
|
fi
|
|
}
|
|
|
|
append_rustflag() {
|
|
local rustflag="$1"
|
|
if [[ -n "${RUSTFLAGS:-}" ]]; then
|
|
export RUSTFLAGS="${RUSTFLAGS} ${rustflag}"
|
|
else
|
|
export RUSTFLAGS="$rustflag"
|
|
fi
|
|
}
|
|
|
|
append_rust_path_remap() {
|
|
local from_path="$1"
|
|
local to_path="$2"
|
|
[[ -n "$from_path" && -n "$to_path" ]] || return
|
|
append_rustflag "--remap-path-prefix=${from_path}=${to_path}"
|
|
}
|
|
|
|
apply_reproducible_rustflags() {
|
|
local cargo_target_root="$BUILD_BACKEND_DIR/target"
|
|
if [[ -n "$CARGO_TARGET_DIR_VALUE" ]]; then
|
|
cargo_target_root="$CARGO_TARGET_DIR_VALUE"
|
|
fi
|
|
|
|
append_rust_path_remap "$PROJECT_ROOT" "/dragonx-project"
|
|
append_rust_path_remap "$BACKEND_SOURCE_DIR" "/dragonx-lite-backend"
|
|
if [[ "$BUILD_BACKEND_DIR" != "$BACKEND_SOURCE_DIR" ]]; then
|
|
append_rust_path_remap "$BUILD_BACKEND_DIR" "/dragonx-lite-backend"
|
|
fi
|
|
append_rust_path_remap "$BACKEND_DEPENDENCY_DIR" "/dragonx-lite-backend-dependency"
|
|
for path_remap in "${EXTRA_REMAP_PATH_PREFIXES[@]}"; do
|
|
append_rustflag "--remap-path-prefix=${path_remap}"
|
|
done
|
|
|
|
local cargo_home="${CARGO_HOME:-}"
|
|
if [[ -z "$cargo_home" && -n "${HOME:-}" ]]; then
|
|
cargo_home="$HOME/.cargo"
|
|
fi
|
|
if [[ -n "$cargo_home" && -d "$cargo_home" ]]; then
|
|
append_rust_path_remap "$cargo_home" "/cargo-home"
|
|
fi
|
|
append_rust_path_remap "$cargo_target_root" "/dragonx-lite-cargo-target"
|
|
}
|
|
|
|
build_with_cargo() {
|
|
command -v cargo >/dev/null 2>&1 || die "cargo was not found"
|
|
[[ -f "$BUILD_BACKEND_DIR/Cargo.toml" ]] || die "Cargo.toml not found in $BUILD_BACKEND_DIR"
|
|
|
|
if [[ -z "$SOURCE_DATE_EPOCH_VALUE" ]]; then
|
|
SOURCE_DATE_EPOCH_VALUE="$(default_source_date_epoch)"
|
|
fi
|
|
|
|
export CARGO_INCREMENTAL=0
|
|
export SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH_VALUE"
|
|
if [[ -n "$CARGO_TARGET_DIR_VALUE" ]]; then
|
|
export CARGO_TARGET_DIR="$CARGO_TARGET_DIR_VALUE"
|
|
fi
|
|
if [[ "$REPRODUCIBLE" == true ]]; then
|
|
apply_reproducible_rustflags
|
|
fi
|
|
if [[ "$PLATFORM" == "windows" && -d "$BUILD_BACKEND_DIR/libsodium-mingw" ]]; then
|
|
export SODIUM_LIB_DIR="$BUILD_BACKEND_DIR/libsodium-mingw"
|
|
fi
|
|
|
|
local cargo_cmd=(cargo build --locked --lib --release)
|
|
if [[ -n "$RUST_TARGET" ]]; then
|
|
cargo_cmd+=(--target "$RUST_TARGET")
|
|
fi
|
|
if [[ -n "$JOBS" ]]; then
|
|
cargo_cmd+=(-j "$JOBS")
|
|
fi
|
|
cargo_cmd+=("${EXTRA_CARGO_ARGS[@]}")
|
|
|
|
info "building backend in $BUILD_BACKEND_DIR"
|
|
(cd "$BUILD_BACKEND_DIR" && "${cargo_cmd[@]}")
|
|
|
|
while IFS= read -r candidate; do
|
|
if [[ -f "$candidate" ]]; then
|
|
ARTIFACT_PATH="$candidate"
|
|
return
|
|
fi
|
|
done < <(cargo_output_candidates)
|
|
|
|
die "cargo finished, but no expected backend artifact was found under $BUILD_BACKEND_DIR/target"
|
|
}
|
|
|
|
select_nm_tool() {
|
|
if [[ "$PLATFORM" == "windows" ]] && command -v x86_64-w64-mingw32-nm >/dev/null 2>&1; then
|
|
printf 'x86_64-w64-mingw32-nm\n'
|
|
return
|
|
fi
|
|
if command -v llvm-nm >/dev/null 2>&1; then
|
|
printf 'llvm-nm\n'
|
|
return
|
|
fi
|
|
if command -v nm >/dev/null 2>&1; then
|
|
printf 'nm\n'
|
|
return
|
|
fi
|
|
die "no symbol inventory tool found; install nm, llvm-nm, or x86_64-w64-mingw32-nm"
|
|
}
|
|
|
|
compute_sha256() {
|
|
local file="$1"
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
sha256sum "$file" | awk '{print $1}'
|
|
elif command -v shasum >/dev/null 2>&1; then
|
|
shasum -a 256 "$file" | awk '{print $1}'
|
|
else
|
|
die "sha256sum or shasum is required"
|
|
fi
|
|
}
|
|
|
|
json_escape() {
|
|
local value="$1"
|
|
value="${value//\\/\\\\}"
|
|
value="${value//\"/\\\"}"
|
|
value="${value//$'\n'/\\n}"
|
|
value="${value//$'\r'/}"
|
|
value="${value//$'\t'/\\t}"
|
|
printf '"%s"' "$value"
|
|
}
|
|
|
|
json_array() {
|
|
local first=true
|
|
printf '['
|
|
for value in "$@"; do
|
|
if [[ "$first" == true ]]; then
|
|
first=false
|
|
else
|
|
printf ','
|
|
fi
|
|
json_escape "$value"
|
|
done
|
|
printf ']'
|
|
}
|
|
|
|
json_array_from_file() {
|
|
local file="$1"
|
|
local values=()
|
|
if [[ -f "$file" ]]; then
|
|
mapfile -t values < "$file"
|
|
fi
|
|
json_array "${values[@]}"
|
|
}
|
|
|
|
signature_metadata_requested() {
|
|
[[ "$SIGNATURE_REQUIRED" == true || \
|
|
-n "$SIGNATURE_FILE" || \
|
|
-n "$SIGNATURE_FORMAT" || \
|
|
-n "$SIGNATURE_VERIFICATION_TOOL" || \
|
|
-n "$SIGNATURE_VERIFICATION_COMMAND" || \
|
|
-n "$SIGNATURE_KEY_FINGERPRINT" || \
|
|
-n "$SIGNATURE_CERTIFICATE_IDENTITY" || \
|
|
-n "$SIGNATURE_CERTIFICATE_ISSUER" || \
|
|
-n "$SIGNATURE_TRANSPARENCY_LOG_URL" || \
|
|
-n "$SIGNATURE_VERIFIED_SHA256" ]]
|
|
}
|
|
|
|
validate_signature_metadata() {
|
|
SIGNATURE_REQUIRED_MANIFEST_VALUE=false
|
|
if [[ "$SIGNATURE_REQUIRED" == true ]]; then
|
|
SIGNATURE_REQUIRED_MANIFEST_VALUE=true
|
|
fi
|
|
|
|
if ! signature_metadata_requested; then
|
|
return
|
|
fi
|
|
|
|
[[ -n "$SIGNATURE_FILE" ]] || die "signature metadata requires --signature-file"
|
|
[[ -f "$SIGNATURE_FILE" ]] || die "signature file does not exist: $SIGNATURE_FILE"
|
|
[[ -n "$SIGNATURE_FORMAT" ]] || die "signature metadata requires --signature-format"
|
|
case "$SIGNATURE_FORMAT" in
|
|
minisign|gpg|sigstore|external|other) ;;
|
|
*) die "unsupported --signature-format: $SIGNATURE_FORMAT" ;;
|
|
esac
|
|
[[ -n "$SIGNATURE_VERIFICATION_TOOL" ]] || die "signature metadata requires --signature-verification-tool"
|
|
[[ -n "$SIGNATURE_VERIFIED_SHA256" ]] || die "signature metadata requires --signature-verified-sha256"
|
|
[[ "$SIGNATURE_VERIFIED_SHA256" == "$SHA256_DIGEST" ]] || die "signature verified SHA-256 does not match artifact SHA-256"
|
|
if [[ -z "$SIGNATURE_KEY_FINGERPRINT" && -z "$SIGNATURE_CERTIFICATE_IDENTITY" ]]; then
|
|
die "signature metadata requires --signature-key-fingerprint or --signature-certificate-identity"
|
|
fi
|
|
|
|
SIGNATURE_METADATA_PROVIDED=true
|
|
SIGNATURE_VERIFICATION_PERFORMED=true
|
|
SIGNATURE_VERIFICATION_STATUS="verified"
|
|
SIGNATURE_FILE_SHA256="$(compute_sha256 "$SIGNATURE_FILE")"
|
|
}
|
|
|
|
if [[ "$BUILD_ARTIFACT" == true ]]; then
|
|
build_with_cargo
|
|
fi
|
|
if [[ -z "$SOURCE_DATE_EPOCH_VALUE" ]]; then
|
|
SOURCE_DATE_EPOCH_VALUE="$(default_source_date_epoch)"
|
|
fi
|
|
|
|
[[ -f "$ARTIFACT_PATH" ]] || die "artifact not found: $ARTIFACT_PATH"
|
|
|
|
KIND="$(artifact_kind "$ARTIFACT_PATH")"
|
|
[[ "$KIND" != "unknown" ]] || die "artifact kind is unsupported: $ARTIFACT_PATH"
|
|
|
|
PLATFORM_OUT_DIR="$OUT_DIR/$PLATFORM"
|
|
mkdir -p "$PLATFORM_OUT_DIR"
|
|
|
|
ARTIFACT_NAME="$(basename "$ARTIFACT_PATH")"
|
|
ARTIFACT_OUTPUT="$PLATFORM_OUT_DIR/$ARTIFACT_NAME"
|
|
if [[ "$(absolute_path "$ARTIFACT_PATH")" != "$(absolute_path "$ARTIFACT_OUTPUT")" ]]; then
|
|
cp -p "$ARTIFACT_PATH" "$ARTIFACT_OUTPUT"
|
|
fi
|
|
|
|
SYMBOLS_FILE="$PLATFORM_OUT_DIR/lite-backend-symbols.txt"
|
|
RAW_SYMBOLS_FILE="$PLATFORM_OUT_DIR/lite-backend-symbols.raw.txt"
|
|
NM_TOOL="$(select_nm_tool)"
|
|
|
|
info "capturing exported symbols with $NM_TOOL"
|
|
if ! "$NM_TOOL" -g --defined-only "$ARTIFACT_OUTPUT" > "$RAW_SYMBOLS_FILE" 2> "$PLATFORM_OUT_DIR/lite-backend-symbols.err.txt"; then
|
|
die "symbol inventory failed; see $PLATFORM_OUT_DIR/lite-backend-symbols.err.txt"
|
|
fi
|
|
awk '{print $NF}' "$RAW_SYMBOLS_FILE" \
|
|
| sed 's/^_//' \
|
|
| grep -E '^(litelib_[A-Za-z0-9_]*|blake3_PW)$' \
|
|
| sort -u > "$SYMBOLS_FILE" || true
|
|
|
|
[[ -s "$SYMBOLS_FILE" ]] || die "no SDXL C ABI symbols were found in $ARTIFACT_OUTPUT"
|
|
|
|
MISSING_SYMBOLS=()
|
|
for required in "${REQUIRED_SYMBOLS[@]}"; do
|
|
if ! grep -Fxq "$required" "$SYMBOLS_FILE"; then
|
|
MISSING_SYMBOLS+=("$required")
|
|
fi
|
|
done
|
|
if [[ ${#MISSING_SYMBOLS[@]} -ne 0 ]]; then
|
|
printf '%s\n' "${MISSING_SYMBOLS[@]}" > "$PLATFORM_OUT_DIR/lite-backend-missing-symbols.txt"
|
|
die "artifact is missing required symbols; see $PLATFORM_OUT_DIR/lite-backend-missing-symbols.txt"
|
|
fi
|
|
|
|
SHA256_DIGEST="$(compute_sha256 "$ARTIFACT_OUTPUT")"
|
|
validate_signature_metadata
|
|
ARTIFACT_SIZE_BYTES="$(wc -c < "$ARTIFACT_OUTPUT" | tr -d ' ')"
|
|
PROJECT_REVISION="$(source_revision_for "$PROJECT_ROOT")"
|
|
BACKEND_REVISION="$(source_revision_for "$BACKEND_SOURCE_DIR")"
|
|
BACKEND_DEPENDENCY_REVISION=""
|
|
if [[ -n "$BACKEND_DEPENDENCY_DIR" ]]; then
|
|
BACKEND_DEPENDENCY_REVISION="$(source_revision_for "$BACKEND_DEPENDENCY_DIR")"
|
|
fi
|
|
ARTIFACT_SET_ID="$PLATFORM-${SHA256_DIGEST:0:16}"
|
|
REPRODUCIBLE_MANIFEST_VALUE=false
|
|
if [[ "$BUILD_ARTIFACT" == true && "$REPRODUCIBLE" == true ]]; then
|
|
REPRODUCIBLE_MANIFEST_VALUE=true
|
|
fi
|
|
PORTABLE_DEPENDENCY_OVERRIDE_MANIFEST_VALUE=false
|
|
if [[ "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == true ]]; then
|
|
PORTABLE_DEPENDENCY_OVERRIDE_MANIFEST_VALUE=true
|
|
fi
|
|
FILE_DESCRIPTION="unknown"
|
|
if command -v file >/dev/null 2>&1; then
|
|
FILE_DESCRIPTION="$(file -b "$ARTIFACT_OUTPUT")"
|
|
fi
|
|
|
|
MANIFEST_FILE="$PLATFORM_OUT_DIR/lite-backend-artifact-manifest.json"
|
|
{
|
|
printf '{\n'
|
|
printf ' "schema": "dragonx.lite.backend-artifact.v1",\n'
|
|
printf ' "generated_by": "scripts/build-lite-backend-artifact.sh",\n'
|
|
printf ' "read_only_inventory": true,\n'
|
|
printf ' "artifact_mutation_requested": false,\n'
|
|
printf ' "upload_requested": false,\n'
|
|
printf ' "signing_requested": false,\n'
|
|
printf ' "publication_requested": false,\n'
|
|
printf ' "signature_verification": {\n'
|
|
printf ' "policy_name": '; json_escape "$SIGNATURE_POLICY_NAME"; printf ',\n'
|
|
printf ' "policy_defined": %s,\n' "$SIGNATURE_POLICY_DEFINED_MANIFEST_VALUE"
|
|
printf ' "required_for_release": %s,\n' "$SIGNATURE_REQUIRED_MANIFEST_VALUE"
|
|
printf ' "metadata_read_only": true,\n'
|
|
printf ' "metadata_provided": %s,\n' "$SIGNATURE_METADATA_PROVIDED"
|
|
printf ' "verification_performed": %s,\n' "$SIGNATURE_VERIFICATION_PERFORMED"
|
|
printf ' "verification_status": '; json_escape "$SIGNATURE_VERIFICATION_STATUS"; printf ',\n'
|
|
printf ' "signature_format": '; json_escape "$SIGNATURE_FORMAT"; printf ',\n'
|
|
printf ' "signature_path": '; json_escape "$SIGNATURE_FILE"; printf ',\n'
|
|
printf ' "signature_file_sha256": '; json_escape "$SIGNATURE_FILE_SHA256"; printf ',\n'
|
|
printf ' "verification_tool": '; json_escape "$SIGNATURE_VERIFICATION_TOOL"; printf ',\n'
|
|
printf ' "verification_command": '; json_escape "$SIGNATURE_VERIFICATION_COMMAND"; printf ',\n'
|
|
printf ' "key_fingerprint": '; json_escape "$SIGNATURE_KEY_FINGERPRINT"; printf ',\n'
|
|
printf ' "certificate_identity": '; json_escape "$SIGNATURE_CERTIFICATE_IDENTITY"; printf ',\n'
|
|
printf ' "certificate_issuer": '; json_escape "$SIGNATURE_CERTIFICATE_ISSUER"; printf ',\n'
|
|
printf ' "transparency_log_url": '; json_escape "$SIGNATURE_TRANSPARENCY_LOG_URL"; printf ',\n'
|
|
printf ' "verified_artifact_sha256": '; json_escape "$SIGNATURE_VERIFIED_SHA256"; printf '\n'
|
|
printf ' },\n'
|
|
printf ' "abi_version": '; json_escape "$ABI_VERSION"; printf ',\n'
|
|
printf ' "link_mode": '; json_escape "$LINK_MODE"; printf ',\n'
|
|
printf ' "platform": '; json_escape "$PLATFORM"; printf ',\n'
|
|
printf ' "rust_target": '; json_escape "$RUST_TARGET"; printf ',\n'
|
|
printf ' "artifact": {\n'
|
|
printf ' "path": '; json_escape "$ARTIFACT_OUTPUT"; printf ',\n'
|
|
printf ' "kind": '; json_escape "$KIND"; printf ',\n'
|
|
printf ' "size_bytes": %s,\n' "$ARTIFACT_SIZE_BYTES"
|
|
printf ' "sha256": '; json_escape "$SHA256_DIGEST"; printf ',\n'
|
|
printf ' "file_description": '; json_escape "$FILE_DESCRIPTION"; printf '\n'
|
|
printf ' },\n'
|
|
printf ' "symbol_inventory": {\n'
|
|
printf ' "tool": '; json_escape "$NM_TOOL"; printf ',\n'
|
|
printf ' "symbols_path": '; json_escape "$SYMBOLS_FILE"; printf ',\n'
|
|
printf ' "raw_symbols_path": '; json_escape "$RAW_SYMBOLS_FILE"; printf ',\n'
|
|
printf ' "required_symbols": '; json_array "${REQUIRED_SYMBOLS[@]}"; printf ',\n'
|
|
printf ' "exported_symbols": '; json_array_from_file "$SYMBOLS_FILE"; printf ',\n'
|
|
printf ' "missing_required_symbols": []\n'
|
|
printf ' },\n'
|
|
printf ' "provenance": {\n'
|
|
printf ' "owner_ready": true,\n'
|
|
printf ' "metadata_provided": true,\n'
|
|
printf ' "source": '; json_escape "$BACKEND_SOURCE_DIR"; printf ',\n'
|
|
printf ' "cargo_build_source": '; json_escape "$BUILD_BACKEND_DIR"; printf ',\n'
|
|
printf ' "portable_dependency_override": %s,\n' "$PORTABLE_DEPENDENCY_OVERRIDE_MANIFEST_VALUE"
|
|
printf ' "silentdragonxlitelib_source": '; json_escape "$BACKEND_DEPENDENCY_DIR"; printf ',\n'
|
|
printf ' "builder": '; json_escape "$BUILDER"; printf ',\n'
|
|
printf ' "source_revision": '; json_escape "$BACKEND_REVISION"; printf ',\n'
|
|
printf ' "silentdragonxlitelib_revision": '; json_escape "$BACKEND_DEPENDENCY_REVISION"; printf ',\n'
|
|
printf ' "project_revision": '; json_escape "$PROJECT_REVISION"; printf ',\n'
|
|
printf ' "artifact_set_id": '; json_escape "$ARTIFACT_SET_ID"; printf ',\n'
|
|
printf ' "source_date_epoch": '; json_escape "$SOURCE_DATE_EPOCH_VALUE"; printf ',\n'
|
|
printf ' "reproducible": %s,\n' "$REPRODUCIBLE_MANIFEST_VALUE"
|
|
printf ' "redacted": true\n'
|
|
printf ' }\n'
|
|
printf '}\n'
|
|
} > "$MANIFEST_FILE"
|
|
|
|
info "artifact: $ARTIFACT_OUTPUT"
|
|
info "symbols: $SYMBOLS_FILE"
|
|
info "manifest: $MANIFEST_FILE"
|
|
info "sha256: $SHA256_DIGEST"
|
|
cat <<EOF
|
|
|
|
CMake configure example:
|
|
cmake -S "$PROJECT_ROOT" -B "$PROJECT_ROOT/build/lite" \\
|
|
-DDRAGONX_BUILD_LITE=ON \\
|
|
-DDRAGONX_ENABLE_LITE_BACKEND=ON \\
|
|
-DDRAGONX_LITE_BACKEND_LIBRARY="$ARTIFACT_OUTPUT" \\
|
|
-DDRAGONX_LITE_BACKEND_SYMBOLS_FILE="$SYMBOLS_FILE" \\
|
|
-DDRAGONX_LITE_BACKEND_MANIFEST="$MANIFEST_FILE" \\
|
|
-DDRAGONX_LITE_BACKEND_LINK_MODE=$LINK_MODE \\
|
|
-DDRAGONX_LITE_BACKEND_ABI=$ABI_VERSION
|
|
EOF |