mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-02-02 02:13:48 -05:00
757 lines
25 KiB
Bash
Executable File
757 lines
25 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e # Stop on error
|
|
set -u # Treat unset variables as errors
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Script directory
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Output directories
|
|
DIST_DIR="$SCRIPT_DIR/dist"
|
|
WASM_DIR="$DIST_DIR/wasm"
|
|
DOTNET_DIR="$DIST_DIR/dotnet"
|
|
IOS_DIR="$DIST_DIR/ios"
|
|
ANDROID_DIR="$DIST_DIR/android"
|
|
|
|
# Target directories in consumer apps
|
|
BROWSER_EXT_DIST="$SCRIPT_DIR/../../apps/browser-extension/src/utils/dist/core/rust"
|
|
BLAZOR_CLIENT_DIST="$SCRIPT_DIR/../../apps/server/AliasVault.Client/wwwroot/wasm"
|
|
IOS_APP_DIST="$SCRIPT_DIR/../../apps/mobile-app/ios/RustCoreFramework/RustCore"
|
|
ANDROID_APP_DIST="$SCRIPT_DIR/../../apps/mobile-app/android/app/src/main/jniLibs"
|
|
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE} AliasVault Rust Core Build Script${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo ""
|
|
|
|
# Check for required tools
|
|
check_tool() {
|
|
if ! command -v "$1" &> /dev/null; then
|
|
echo -e "${RED}Error: $1 is not installed${NC}"
|
|
echo "Please install $1 first:"
|
|
echo "$2"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Portable checksum function (works on macOS and Linux)
|
|
# Includes Rust sources AND Cargo.toml/Cargo.lock to detect dependency changes
|
|
# that can cause UniFFI checksum mismatches
|
|
compute_source_checksum() {
|
|
local dir="$1"
|
|
if [ -d "$dir" ]; then
|
|
# Combine checksums of:
|
|
# 1. All .rs source files
|
|
# 2. Cargo.toml and Cargo.lock (dependency changes affect UniFFI checksums)
|
|
{
|
|
find "$dir" -name "*.rs" -type f -print0 2>/dev/null | \
|
|
sort -z | \
|
|
xargs -0 shasum -a 256 2>/dev/null
|
|
# Include Cargo files from parent directory (where Cargo.toml lives)
|
|
local cargo_dir="$(dirname "$dir")"
|
|
shasum -a 256 "$cargo_dir/Cargo.toml" "$cargo_dir/Cargo.lock" 2>/dev/null
|
|
} | shasum -a 256 | cut -d' ' -f1
|
|
else
|
|
echo "unknown"
|
|
fi
|
|
}
|
|
|
|
echo -e "${YELLOW}Checking prerequisites...${NC}"
|
|
check_tool "rustc" "Visit https://rustup.rs"
|
|
check_tool "cargo" "Visit https://rustup.rs"
|
|
|
|
# Check Rust version
|
|
RUST_VERSION=$(rustc --version | cut -d' ' -f2)
|
|
echo -e " Rust version: ${GREEN}$RUST_VERSION${NC}"
|
|
|
|
# Build mode selection
|
|
BUILD_ALL=false
|
|
BUILD_BROWSER=false
|
|
BUILD_DOTNET=false
|
|
BUILD_IOS=false
|
|
BUILD_ANDROID=false
|
|
FAST_MODE=false
|
|
INCREMENTAL=false
|
|
FORCE_BUILD=false
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--browser)
|
|
BUILD_BROWSER=true
|
|
shift
|
|
;;
|
|
--dotnet)
|
|
BUILD_DOTNET=true
|
|
shift
|
|
;;
|
|
--ios)
|
|
BUILD_IOS=true
|
|
shift
|
|
;;
|
|
--android)
|
|
BUILD_ANDROID=true
|
|
shift
|
|
;;
|
|
--all)
|
|
BUILD_BROWSER=true
|
|
BUILD_DOTNET=true
|
|
BUILD_IOS=true
|
|
BUILD_ANDROID=true
|
|
shift
|
|
;;
|
|
--fast|--dev)
|
|
FAST_MODE=true
|
|
echo -e "${YELLOW}Fast/dev mode enabled${NC}"
|
|
shift
|
|
;;
|
|
--incremental)
|
|
INCREMENTAL=true
|
|
shift
|
|
;;
|
|
--force)
|
|
FORCE_BUILD=true
|
|
shift
|
|
;;
|
|
--help)
|
|
echo "Usage: $0 [options]"
|
|
echo ""
|
|
echo "Target options:"
|
|
echo " --browser Build WASM for browser extension and Blazor WASM client"
|
|
echo " --dotnet Build native library for .NET server-side use (macOS/Linux/Windows)"
|
|
echo " --ios Build for iOS (device + simulator arm64) with Swift bindings"
|
|
echo " --android Build for Android (arm64-v8a, armeabi-v7a, x86_64) with Kotlin bindings"
|
|
= echo " --all Build all targets"
|
|
echo ""
|
|
echo "Speed options:"
|
|
echo " --fast, --dev Faster builds (for development)"
|
|
echo " --incremental Skip build if sources unchanged (for Xcode build phases)"
|
|
echo " --force Force rebuild even with --incremental"
|
|
echo ""
|
|
echo "Other options:"
|
|
echo " --help Show this help message"
|
|
echo ""
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unknown option: $1${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# If no targets specified, show help
|
|
if ! $BUILD_BROWSER && ! $BUILD_DOTNET && ! $BUILD_IOS && ! $BUILD_ANDROID; then
|
|
echo "No target specified. Use --help for usage."
|
|
echo ""
|
|
echo "Quick start:"
|
|
echo " ./build.sh --browser # Build for browser extension"
|
|
echo " ./build.sh --dotnet # Build for .NET"
|
|
echo " ./build.sh --ios # Build for iOS"
|
|
echo " ./build.sh --android # Build for Android"
|
|
exit 0
|
|
fi
|
|
|
|
# ============================================
|
|
# Browser Extension Build (WASM)
|
|
# ============================================
|
|
build_browser() {
|
|
echo ""
|
|
echo -e "${BLUE}Building WASM for browser extension...${NC}"
|
|
|
|
local start_time=$(date +%s)
|
|
|
|
# Check for wasm-pack
|
|
if ! command -v wasm-pack &> /dev/null; then
|
|
echo -e "${YELLOW}Installing wasm-pack...${NC}"
|
|
cargo install wasm-pack
|
|
fi
|
|
|
|
# Ensure wasm target is installed
|
|
if ! rustup target list --installed 2>/dev/null | grep -q "wasm32-unknown-unknown"; then
|
|
echo -e " Installing wasm32-unknown-unknown target..."
|
|
rustup target add wasm32-unknown-unknown
|
|
fi
|
|
|
|
# Build with wasm-pack
|
|
echo -e " Running wasm-pack build..."
|
|
if $FAST_MODE; then
|
|
wasm-pack build --dev --target web --out-dir "$WASM_DIR" --features wasm
|
|
else
|
|
wasm-pack build --release --target web --out-dir "$WASM_DIR" --features wasm
|
|
fi
|
|
|
|
local end_time=$(date +%s)
|
|
local duration=$((end_time - start_time))
|
|
|
|
# Show output size
|
|
if [ -f "$WASM_DIR/aliasvault_core_bg.wasm" ]; then
|
|
WASM_SIZE=$(ls -lh "$WASM_DIR/aliasvault_core_bg.wasm" | awk '{print $5}')
|
|
echo -e "${GREEN}WASM build complete! (${duration}s)${NC}"
|
|
echo -e " Size: ${YELLOW}$WASM_SIZE${NC}"
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# Distribution
|
|
# ============================================
|
|
distribute_browser() {
|
|
echo ""
|
|
echo -e "${BLUE}Distributing to browser extension...${NC}"
|
|
|
|
if [ -d "$WASM_DIR" ] && [ -n "$(ls -A "$WASM_DIR" 2>/dev/null)" ]; then
|
|
rm -rf "$BROWSER_EXT_DIST"
|
|
mkdir -p "$BROWSER_EXT_DIST"
|
|
cp "$WASM_DIR"/aliasvault_core* "$BROWSER_EXT_DIST/"
|
|
cp "$WASM_DIR"/package.json "$BROWSER_EXT_DIST/"
|
|
|
|
# Create README
|
|
cat > "$BROWSER_EXT_DIST/README.md" << 'README_EOF'
|
|
# Rust Core WASM Module
|
|
|
|
Auto-generated from `/core/rust`. Do not edit manually.
|
|
|
|
## Regenerate
|
|
|
|
```bash
|
|
cd /core/rust
|
|
./build.sh --browser
|
|
```
|
|
README_EOF
|
|
|
|
echo -e "${GREEN}Distributed to: $BROWSER_EXT_DIST${NC}"
|
|
ls -lh "$BROWSER_EXT_DIST/"
|
|
|
|
# Also distribute to Blazor client
|
|
echo ""
|
|
echo -e "${BLUE}Distributing to Blazor client...${NC}"
|
|
rm -rf "$BLAZOR_CLIENT_DIST"
|
|
mkdir -p "$BLAZOR_CLIENT_DIST"
|
|
cp "$WASM_DIR"/aliasvault_core_bg.wasm "$BLAZOR_CLIENT_DIST/"
|
|
cp "$WASM_DIR"/aliasvault_core.js "$BLAZOR_CLIENT_DIST/"
|
|
|
|
echo -e "${GREEN}Distributed to: $BLAZOR_CLIENT_DIST${NC}"
|
|
ls -lh "$BLAZOR_CLIENT_DIST/"
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# .NET Build (Native Library with FFI)
|
|
# ============================================
|
|
build_dotnet() {
|
|
echo ""
|
|
echo -e "${BLUE}Building native library for .NET...${NC}"
|
|
|
|
local start_time=$(date +%s)
|
|
|
|
# Detect current platform
|
|
local os_name
|
|
local arch_name
|
|
local lib_name
|
|
local target_dir
|
|
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
os_name="macos"
|
|
lib_name="libaliasvault_core.dylib"
|
|
;;
|
|
Linux)
|
|
os_name="linux"
|
|
lib_name="libaliasvault_core.so"
|
|
;;
|
|
MINGW*|MSYS*|CYGWIN*)
|
|
os_name="windows"
|
|
lib_name="aliasvault_core.dll"
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unsupported OS: $(uname -s)${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "$(uname -m)" in
|
|
x86_64|amd64)
|
|
arch_name="x64"
|
|
;;
|
|
arm64|aarch64)
|
|
arch_name="arm64"
|
|
;;
|
|
*)
|
|
arch_name="$(uname -m)"
|
|
;;
|
|
esac
|
|
|
|
target_dir="$DOTNET_DIR/${os_name}-${arch_name}"
|
|
mkdir -p "$target_dir"
|
|
|
|
echo -e " Platform: ${YELLOW}${os_name}-${arch_name}${NC}"
|
|
|
|
# Build with cargo
|
|
echo -e " Running cargo build..."
|
|
if $FAST_MODE; then
|
|
cargo build --features ffi
|
|
local cargo_target="target/debug"
|
|
else
|
|
cargo build --release --features ffi
|
|
local cargo_target="target/release"
|
|
fi
|
|
|
|
# Copy the library
|
|
if [ -f "$cargo_target/$lib_name" ]; then
|
|
cp "$cargo_target/$lib_name" "$target_dir/"
|
|
local lib_size
|
|
lib_size=$(ls -lh "$target_dir/$lib_name" | awk '{print $5}')
|
|
echo -e "${GREEN}Native library built! ${NC}"
|
|
echo -e " Output: ${YELLOW}$target_dir/$lib_name${NC}"
|
|
echo -e " Size: ${YELLOW}$lib_size${NC}"
|
|
else
|
|
echo -e "${RED}Build failed: $lib_name not found${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
local end_time=$(date +%s)
|
|
local duration=$((end_time - start_time))
|
|
echo -e "${GREEN}.NET build complete! (${duration}s)${NC}"
|
|
}
|
|
|
|
# ============================================
|
|
# iOS Build (ARM64 only - device + simulator)
|
|
# ============================================
|
|
build_ios() {
|
|
echo ""
|
|
echo -e "${BLUE}Building for iOS...${NC}"
|
|
|
|
local start_time=$(date +%s)
|
|
|
|
# Check for Xcode (required for iOS builds)
|
|
if ! command -v xcrun &> /dev/null; then
|
|
echo -e "${RED}Error: Xcode command line tools not found${NC}"
|
|
echo "Install with: xcode-select --install"
|
|
exit 1
|
|
fi
|
|
|
|
# Incremental build check
|
|
local checksum_file="$IOS_APP_DIST/.rust-core-checksum"
|
|
local current_checksum=""
|
|
current_checksum=$(compute_source_checksum "$SCRIPT_DIR/src")
|
|
|
|
if $INCREMENTAL && [ "$FORCE_BUILD" = false ] && [ -f "$checksum_file" ] && [ -f "$IOS_APP_DIST/lib/device/libaliasvault_core.a" ]; then
|
|
local stored_checksum=$(cat "$checksum_file" 2>/dev/null || echo "")
|
|
if [ "$current_checksum" = "$stored_checksum" ]; then
|
|
echo -e "${GREEN}Rust Core is up to date, skipping build${NC}"
|
|
IOS_BUILD_SKIPPED=true
|
|
return 0
|
|
fi
|
|
fi
|
|
IOS_BUILD_SKIPPED=false
|
|
|
|
# Install iOS targets if needed (ARM64 only - no Intel simulator support)
|
|
echo -e " Checking iOS build targets..."
|
|
for target in aarch64-apple-ios aarch64-apple-ios-sim; do
|
|
if ! rustup target list --installed 2>/dev/null | grep -q "$target"; then
|
|
echo -e " Installing $target..."
|
|
rustup target add "$target"
|
|
fi
|
|
done
|
|
|
|
# Create output directories
|
|
mkdir -p "$IOS_DIR/device"
|
|
mkdir -p "$IOS_DIR/simulator"
|
|
mkdir -p "$IOS_DIR/swift"
|
|
|
|
local cargo_profile
|
|
if $FAST_MODE; then
|
|
cargo_profile="debug"
|
|
cargo_flags=""
|
|
else
|
|
cargo_profile="release"
|
|
cargo_flags="--release"
|
|
fi
|
|
|
|
# Build for iOS device (arm64)
|
|
# Note: Use only 'uniffi' feature for library builds (not uniffi-cli which includes heavy bindgen deps)
|
|
echo -e " Building for iOS device (aarch64-apple-ios)..."
|
|
cargo build $cargo_flags --target aarch64-apple-ios --features uniffi
|
|
|
|
# Build for iOS simulator (arm64 - Apple Silicon only)
|
|
echo -e " Building for iOS simulator arm64 (aarch64-apple-ios-sim)..."
|
|
cargo build $cargo_flags --target aarch64-apple-ios-sim --features uniffi
|
|
|
|
# Copy libraries (no lipo needed - single architecture for simulator)
|
|
cp "target/aarch64-apple-ios/$cargo_profile/libaliasvault_core.a" "$IOS_DIR/device/"
|
|
cp "target/aarch64-apple-ios-sim/$cargo_profile/libaliasvault_core.a" "$IOS_DIR/simulator/"
|
|
|
|
# Strip debug symbols from static libraries to reduce size
|
|
# Note: -S strips debug symbols but keeps the symbol table needed for linking
|
|
if ! $FAST_MODE; then
|
|
echo -e " Stripping debug symbols from libraries..."
|
|
strip -S "$IOS_DIR/device/libaliasvault_core.a" 2>/dev/null || true
|
|
strip -S "$IOS_DIR/simulator/libaliasvault_core.a" 2>/dev/null || true
|
|
fi
|
|
|
|
# Generate Swift bindings using UniFFI
|
|
# Note: Use uniffi-cli feature here since we need the bindgen CLI tool
|
|
echo -e " Generating Swift bindings..."
|
|
cargo run $cargo_flags --features uniffi-cli --bin uniffi-bindgen -- generate \
|
|
--library "target/aarch64-apple-ios/$cargo_profile/libaliasvault_core.a" \
|
|
--language swift \
|
|
--out-dir "$IOS_DIR/swift"
|
|
|
|
local end_time=$(date +%s)
|
|
local duration=$((end_time - start_time))
|
|
|
|
# Show output sizes
|
|
if [ -f "$IOS_DIR/device/libaliasvault_core.a" ]; then
|
|
local device_size=$(ls -lh "$IOS_DIR/device/libaliasvault_core.a" | awk '{print $5}')
|
|
local sim_size=$(ls -lh "$IOS_DIR/simulator/libaliasvault_core.a" | awk '{print $5}')
|
|
echo -e "${GREEN}iOS build complete! (${duration}s)${NC}"
|
|
echo -e " Device library: ${YELLOW}$device_size${NC}"
|
|
echo -e " Simulator library: ${YELLOW}$sim_size${NC}"
|
|
|
|
if [ -d "$IOS_DIR/swift" ] && [ -n "$(ls -A "$IOS_DIR/swift" 2>/dev/null)" ]; then
|
|
echo -e " Swift bindings: ${GREEN}Generated${NC}"
|
|
ls "$IOS_DIR/swift/"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# iOS Distribution
|
|
# ============================================
|
|
distribute_ios() {
|
|
echo ""
|
|
echo -e "${BLUE}Distributing to iOS app...${NC}"
|
|
|
|
mkdir -p "$IOS_APP_DIST/lib/device"
|
|
mkdir -p "$IOS_APP_DIST/lib/simulator"
|
|
mkdir -p "$IOS_APP_DIST/include"
|
|
mkdir -p "$IOS_APP_DIST/Generated"
|
|
|
|
# Copy libraries
|
|
if [ -f "$IOS_DIR/device/libaliasvault_core.a" ]; then
|
|
cp "$IOS_DIR/device/libaliasvault_core.a" "$IOS_APP_DIST/lib/device/"
|
|
echo -e " Copied device library"
|
|
fi
|
|
|
|
if [ -f "$IOS_DIR/simulator/libaliasvault_core.a" ]; then
|
|
cp "$IOS_DIR/simulator/libaliasvault_core.a" "$IOS_APP_DIST/lib/simulator/"
|
|
echo -e " Copied simulator library"
|
|
fi
|
|
|
|
# Copy headers and modulemap
|
|
if [ -d "$IOS_DIR/swift" ] && [ -n "$(ls -A "$IOS_DIR/swift" 2>/dev/null)" ]; then
|
|
# Copy C header to framework root (for public headers)
|
|
cp "$IOS_DIR/swift"/aliasvault_coreFFI.h "$IOS_APP_DIST/../" 2>/dev/null || true
|
|
|
|
# Create the framework modulemap at framework root
|
|
cat > "$IOS_APP_DIST/../module.modulemap" << 'EOF'
|
|
framework module RustCoreFramework {
|
|
umbrella header "RustCoreFramework.h"
|
|
export *
|
|
module * { export * }
|
|
}
|
|
EOF
|
|
echo -e " Copied headers and modulemap"
|
|
|
|
# Copy Swift bindings
|
|
cp "$IOS_DIR/swift"/*.swift "$IOS_APP_DIST/Generated/" 2>/dev/null || true
|
|
echo -e " Copied Swift bindings"
|
|
fi
|
|
|
|
# Save checksum for incremental builds
|
|
local current_checksum=""
|
|
current_checksum=$(compute_source_checksum "$SCRIPT_DIR/src")
|
|
echo "$current_checksum" > "$IOS_APP_DIST/.rust-core-checksum"
|
|
|
|
# Create README
|
|
cat > "$IOS_APP_DIST/README.md" << 'README_EOF'
|
|
# Rust Core iOS Library
|
|
|
|
Auto-generated from `/core/rust`. Do not edit manually.
|
|
|
|
## Contents
|
|
|
|
- `lib/device/libaliasvault_core.a` - Static library for iOS devices (arm64)
|
|
- `lib/simulator/libaliasvault_core.a` - Static library for iOS simulator (arm64 Apple Silicon)
|
|
- `Generated/` - Swift bindings generated by UniFFI
|
|
|
|
## Regenerate
|
|
|
|
```bash
|
|
cd /core/rust
|
|
./build.sh --ios
|
|
```
|
|
|
|
## Xcode Integration
|
|
|
|
The library is automatically built by the Xcode build phase which calls:
|
|
```bash
|
|
../../core/rust/build.sh --ios --incremental
|
|
```
|
|
|
|
Build settings use `RUST_LIB_PLATFORM` to select device vs simulator library.
|
|
README_EOF
|
|
|
|
echo -e "${GREEN}Distributed to: $IOS_APP_DIST${NC}"
|
|
ls -la "$IOS_APP_DIST/"
|
|
}
|
|
|
|
# ============================================
|
|
# Android Build (Multiple ABIs + Kotlin Bindings)
|
|
# ============================================
|
|
build_android() {
|
|
echo ""
|
|
echo -e "${BLUE}Building for Android...${NC}"
|
|
|
|
local start_time=$(date +%s)
|
|
|
|
# Incremental build check
|
|
local checksum_file="$ANDROID_APP_DIST/.rust-core-checksum"
|
|
local current_checksum=""
|
|
current_checksum=$(compute_source_checksum "$SCRIPT_DIR/src")
|
|
|
|
if $INCREMENTAL && [ "$FORCE_BUILD" = false ] && [ -f "$checksum_file" ] && [ -f "$ANDROID_APP_DIST/arm64-v8a/libaliasvault_core.so" ]; then
|
|
local stored_checksum=$(cat "$checksum_file" 2>/dev/null || echo "")
|
|
if [ "$current_checksum" = "$stored_checksum" ]; then
|
|
echo -e "${GREEN}Rust Core is up to date, skipping build${NC}"
|
|
ANDROID_BUILD_SKIPPED=true
|
|
return 0
|
|
fi
|
|
fi
|
|
ANDROID_BUILD_SKIPPED=false
|
|
|
|
# Check for Android NDK
|
|
if [ -z "${ANDROID_NDK_HOME:-}" ]; then
|
|
# Try to find NDK in common locations
|
|
if [ -d "$HOME/Library/Android/sdk/ndk" ]; then
|
|
# Find the latest NDK version
|
|
ANDROID_NDK_HOME=$(ls -d "$HOME/Library/Android/sdk/ndk"/*/ 2>/dev/null | sort -V | tail -1)
|
|
ANDROID_NDK_HOME="${ANDROID_NDK_HOME%/}"
|
|
elif [ -d "$HOME/Android/Sdk/ndk" ]; then
|
|
ANDROID_NDK_HOME=$(ls -d "$HOME/Android/Sdk/ndk"/*/ 2>/dev/null | sort -V | tail -1)
|
|
ANDROID_NDK_HOME="${ANDROID_NDK_HOME%/}"
|
|
fi
|
|
|
|
if [ -z "${ANDROID_NDK_HOME:-}" ]; then
|
|
echo -e "${RED}Error: Android NDK not found${NC}"
|
|
echo "Set ANDROID_NDK_HOME environment variable or install NDK via Android Studio"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
echo -e " Using Android NDK: ${YELLOW}$ANDROID_NDK_HOME${NC}"
|
|
|
|
# Install Android targets if needed
|
|
echo -e " Checking Android build targets..."
|
|
for target in aarch64-linux-android armv7-linux-androideabi x86_64-linux-android; do
|
|
if ! rustup target list --installed 2>/dev/null | grep -q "$target"; then
|
|
echo -e " Installing $target..."
|
|
rustup target add "$target"
|
|
fi
|
|
done
|
|
|
|
# Create output directories
|
|
mkdir -p "$ANDROID_DIR/arm64-v8a"
|
|
mkdir -p "$ANDROID_DIR/armeabi-v7a"
|
|
mkdir -p "$ANDROID_DIR/x86_64"
|
|
mkdir -p "$ANDROID_DIR/kotlin"
|
|
|
|
local cargo_profile
|
|
if $FAST_MODE; then
|
|
cargo_profile="debug"
|
|
cargo_flags=""
|
|
else
|
|
cargo_profile="release"
|
|
cargo_flags="--release"
|
|
fi
|
|
|
|
# Set up Android toolchain
|
|
local host_tag
|
|
case "$(uname -s)" in
|
|
Darwin) host_tag="darwin-x86_64" ;;
|
|
Linux) host_tag="linux-x86_64" ;;
|
|
*) host_tag="windows-x86_64" ;;
|
|
esac
|
|
|
|
local toolchain="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$host_tag"
|
|
local api_level=24 # Android 7.0 minimum
|
|
|
|
# Build for each ABI
|
|
# Note: Use only 'uniffi' feature for library builds (not uniffi-cli which includes heavy bindgen deps)
|
|
echo -e " Building for arm64-v8a..."
|
|
AR="$toolchain/bin/llvm-ar" \
|
|
CC="$toolchain/bin/aarch64-linux-android${api_level}-clang" \
|
|
CXX="$toolchain/bin/aarch64-linux-android${api_level}-clang++" \
|
|
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$toolchain/bin/aarch64-linux-android${api_level}-clang" \
|
|
cargo build $cargo_flags --target aarch64-linux-android --features uniffi
|
|
|
|
echo -e " Building for armeabi-v7a..."
|
|
AR="$toolchain/bin/llvm-ar" \
|
|
CC="$toolchain/bin/armv7a-linux-androideabi${api_level}-clang" \
|
|
CXX="$toolchain/bin/armv7a-linux-androideabi${api_level}-clang++" \
|
|
CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="$toolchain/bin/armv7a-linux-androideabi${api_level}-clang" \
|
|
cargo build $cargo_flags --target armv7-linux-androideabi --features uniffi
|
|
|
|
echo -e " Building for x86_64..."
|
|
AR="$toolchain/bin/llvm-ar" \
|
|
CC="$toolchain/bin/x86_64-linux-android${api_level}-clang" \
|
|
CXX="$toolchain/bin/x86_64-linux-android${api_level}-clang++" \
|
|
CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="$toolchain/bin/x86_64-linux-android${api_level}-clang" \
|
|
cargo build $cargo_flags --target x86_64-linux-android --features uniffi
|
|
|
|
# Copy libraries
|
|
cp "target/aarch64-linux-android/$cargo_profile/libaliasvault_core.so" "$ANDROID_DIR/arm64-v8a/"
|
|
cp "target/armv7-linux-androideabi/$cargo_profile/libaliasvault_core.so" "$ANDROID_DIR/armeabi-v7a/"
|
|
cp "target/x86_64-linux-android/$cargo_profile/libaliasvault_core.so" "$ANDROID_DIR/x86_64/"
|
|
|
|
# Strip debug symbols from shared libraries using NDK strip
|
|
# This removes debug info while keeping symbols needed for JNI
|
|
if ! $FAST_MODE; then
|
|
echo -e " Stripping debug symbols from libraries..."
|
|
local llvm_strip="$toolchain/bin/llvm-strip"
|
|
if [ -x "$llvm_strip" ]; then
|
|
"$llvm_strip" --strip-debug "$ANDROID_DIR/arm64-v8a/libaliasvault_core.so" 2>/dev/null || true
|
|
"$llvm_strip" --strip-debug "$ANDROID_DIR/armeabi-v7a/libaliasvault_core.so" 2>/dev/null || true
|
|
"$llvm_strip" --strip-debug "$ANDROID_DIR/x86_64/libaliasvault_core.so" 2>/dev/null || true
|
|
fi
|
|
fi
|
|
|
|
# Generate Kotlin bindings using UniFFI
|
|
# Note: We need to build a native library first because UniFFI bindgen
|
|
# cannot extract metadata from cross-compiled libraries
|
|
echo -e " Generating Kotlin bindings..."
|
|
|
|
# Detect platform-specific library extension
|
|
local native_lib_name
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
native_lib_name="libaliasvault_core.dylib"
|
|
;;
|
|
Linux)
|
|
native_lib_name="libaliasvault_core.so"
|
|
;;
|
|
MINGW*|MSYS*|CYGWIN*)
|
|
native_lib_name="aliasvault_core.dll"
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unsupported OS for Kotlin bindgen: $(uname -s)${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Build native library for bindgen (if not already built)
|
|
if [ ! -f "target/debug/$native_lib_name" ]; then
|
|
echo -e " Building native library for bindgen..."
|
|
cargo build --features uniffi --lib
|
|
fi
|
|
|
|
# Generate bindings from native library
|
|
cargo run --features uniffi-cli --bin uniffi-bindgen -- generate \
|
|
--library "target/debug/$native_lib_name" \
|
|
--language kotlin \
|
|
--out-dir "$ANDROID_DIR/kotlin"
|
|
|
|
local end_time=$(date +%s)
|
|
local duration=$((end_time - start_time))
|
|
|
|
# Show output sizes
|
|
echo -e "${GREEN}Android build complete! (${duration}s)${NC}"
|
|
for abi in arm64-v8a armeabi-v7a x86_64; do
|
|
if [ -f "$ANDROID_DIR/$abi/libaliasvault_core.so" ]; then
|
|
local size=$(ls -lh "$ANDROID_DIR/$abi/libaliasvault_core.so" | awk '{print $5}')
|
|
echo -e " $abi: ${YELLOW}$size${NC}"
|
|
fi
|
|
done
|
|
|
|
if [ -d "$ANDROID_DIR/kotlin" ] && [ -n "$(ls -A "$ANDROID_DIR/kotlin" 2>/dev/null)" ]; then
|
|
echo -e " Kotlin bindings: ${GREEN}Generated${NC}"
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# Android Distribution
|
|
# ============================================
|
|
distribute_android() {
|
|
echo ""
|
|
echo -e "${BLUE}Distributing to Android app...${NC}"
|
|
|
|
# Copy native libraries to jniLibs
|
|
for abi in arm64-v8a armeabi-v7a x86_64; do
|
|
if [ -f "$ANDROID_DIR/$abi/libaliasvault_core.so" ]; then
|
|
mkdir -p "$ANDROID_APP_DIST/$abi"
|
|
cp "$ANDROID_DIR/$abi/libaliasvault_core.so" "$ANDROID_APP_DIST/$abi/"
|
|
echo -e " Copied $abi library"
|
|
fi
|
|
done
|
|
|
|
# Copy Kotlin bindings to app source
|
|
# UniFFI generates bindings in uniffi/aliasvault_core/ directory structure
|
|
local kotlin_dist="$SCRIPT_DIR/../../apps/mobile-app/android/app/src/main/java/net/aliasvault/app/rustcore"
|
|
if [ -d "$ANDROID_DIR/kotlin/uniffi" ]; then
|
|
mkdir -p "$kotlin_dist"
|
|
# Copy the entire uniffi directory to preserve package structure
|
|
cp -r "$ANDROID_DIR/kotlin/uniffi" "$kotlin_dist/"
|
|
echo -e " Copied Kotlin bindings to $kotlin_dist/uniffi/"
|
|
|
|
# List what was copied
|
|
if [ -d "$kotlin_dist/uniffi/aliasvault_core" ]; then
|
|
ls -lh "$kotlin_dist/uniffi/aliasvault_core"/*.kt 2>/dev/null || true
|
|
fi
|
|
else
|
|
echo -e "${RED}Warning: Kotlin bindings not found at $ANDROID_DIR/kotlin/uniffi${NC}"
|
|
fi
|
|
|
|
# Save checksum for incremental builds
|
|
local current_checksum=""
|
|
current_checksum=$(compute_source_checksum "$SCRIPT_DIR/src")
|
|
echo "$current_checksum" > "$ANDROID_APP_DIST/.rust-core-checksum"
|
|
|
|
echo -e "${GREEN}Distributed to: $ANDROID_APP_DIST${NC}"
|
|
}
|
|
|
|
# ============================================
|
|
# Main Build Process
|
|
# ============================================
|
|
TOTAL_START=$(date +%s)
|
|
|
|
if $BUILD_BROWSER; then
|
|
build_browser
|
|
distribute_browser
|
|
fi
|
|
|
|
if $BUILD_DOTNET; then
|
|
build_dotnet
|
|
# Note: dotnet native libs are built to dist/dotnet/ but not distributed
|
|
# Blazor WASM uses the WASM module via JS interop instead
|
|
echo -e "${YELLOW}Note: Native library built to dist/dotnet/ (for server-side .NET use)${NC}"
|
|
fi
|
|
|
|
if $BUILD_IOS; then
|
|
IOS_BUILD_SKIPPED=false
|
|
build_ios
|
|
if [ "$IOS_BUILD_SKIPPED" = false ]; then
|
|
distribute_ios
|
|
fi
|
|
fi
|
|
|
|
if $BUILD_ANDROID; then
|
|
build_android
|
|
distribute_android
|
|
fi
|
|
|
|
TOTAL_END=$(date +%s)
|
|
TOTAL_DURATION=$((TOTAL_END - TOTAL_START))
|
|
|
|
echo ""
|
|
echo -e "${GREEN}========================================${NC}"
|
|
echo -e "${GREEN} Build completed in ${TOTAL_DURATION}s${NC}"
|
|
echo -e "${GREEN}========================================${NC}"
|