From f60cd1cb2a6768923f465c02a5ef797c1eaccb9f Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Fri, 2 Jan 2026 16:24:46 +0100 Subject: [PATCH] Simplify Rust build for iOS (#1404) --- .../ios/AliasVault.xcodeproj/project.pbxproj | 52 ++--- .../mobile-app/ios/Scripts/build-rust-core.sh | 187 ++---------------- core/rust/Cargo.lock | 124 ------------ core/rust/Cargo.toml | 8 +- core/rust/build.sh | 112 +++++++---- 5 files changed, 117 insertions(+), 366 deletions(-) diff --git a/apps/mobile-app/ios/AliasVault.xcodeproj/project.pbxproj b/apps/mobile-app/ios/AliasVault.xcodeproj/project.pbxproj index 3fc35dc56..0b31e2857 100644 --- a/apps/mobile-app/ios/AliasVault.xcodeproj/project.pbxproj +++ b/apps/mobile-app/ios/AliasVault.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 60; + objectVersion = 70; objects = { /* Begin PBXBuildFile section */ @@ -1275,10 +1275,7 @@ PRODUCT_BUNDLE_IDENTIFIER = net.aliasvault.app; PRODUCT_NAME = AliasVault; PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_INCLUDE_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/VaultStoreKit/RustCore/include"; SWIFT_OBJC_BRIDGING_HEADER = "AliasVault/AliasVault-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -1314,10 +1311,7 @@ OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; PRODUCT_BUNDLE_IDENTIFIER = net.aliasvault.app; PRODUCT_NAME = AliasVault; - SWIFT_INCLUDE_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/VaultStoreKit/RustCore/include"; SWIFT_OBJC_BRIDGING_HEADER = "AliasVault/AliasVault-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1644,6 +1638,10 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", + ); INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 17.0; @@ -1652,13 +1650,11 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/VaultStoreKit/RustCore/lib/$(RUST_LIB_PLATFORM)", + "$(PROJECT_DIR)/VaultStoreKit/RustCore/lib/device", + "$(PROJECT_DIR)/VaultStoreKit/RustCore/lib/simulator", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; @@ -1678,10 +1674,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INCLUDE_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/VaultStoreKit/RustCore/include"; SWIFT_INSTALL_MODULE = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -1715,6 +1708,10 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", + ); INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 17.0; @@ -1723,13 +1720,11 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/VaultStoreKit/RustCore/lib/$(RUST_LIB_PLATFORM)", + "$(PROJECT_DIR)/VaultStoreKit/RustCore/lib/device", + "$(PROJECT_DIR)/VaultStoreKit/RustCore/lib/simulator", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; @@ -1748,10 +1743,7 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INCLUDE_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/VaultStoreKit/RustCore/include"; SWIFT_INSTALL_MODULE = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_VERSION = 5.0; @@ -2070,10 +2062,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INCLUDE_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/VaultStoreKit/RustCore/include"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -2118,10 +2107,7 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INCLUDE_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/VaultStoreKit/RustCore/include", - ); + SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/VaultStoreKit/RustCore/include"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/apps/mobile-app/ios/Scripts/build-rust-core.sh b/apps/mobile-app/ios/Scripts/build-rust-core.sh index 5c7aa0d1f..f3ae2f16d 100755 --- a/apps/mobile-app/ios/Scripts/build-rust-core.sh +++ b/apps/mobile-app/ios/Scripts/build-rust-core.sh @@ -1,206 +1,51 @@ #!/bin/bash -# Build Rust Core for iOS and output static libraries -# This script is designed to be called from Xcode build phases +# Thin wrapper that calls the main Rust core build script +# This is called by Xcode build phases # # Usage: -# ./build-rust-core.sh [--force] [--release] +# ./build-rust-core.sh [--force] [--release|--debug] # -# Options: -# --force Force rebuild even if sources haven't changed -# --release Build release configuration (default for non-Debug builds) +# The main build script lives at: /core/rust/build.sh set -e # Ensure cargo is in PATH (for Xcode build phases) export PATH="$HOME/.cargo/bin:/usr/local/bin:/opt/homebrew/bin:$PATH" -# Colors for output (only if terminal supports it) -if [ -t 1 ]; then - RED='\033[0;31m' - GREEN='\033[0;32m' - YELLOW='\033[1;33m' - BLUE='\033[0;34m' - NC='\033[0m' -else - RED='' - GREEN='' - YELLOW='' - BLUE='' - NC='' -fi - -# Script location and paths +# Script location SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -IOS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -RUST_CORE_DIR="$(cd "$IOS_DIR/../../../core/rust" && pwd)" +RUST_CORE_DIR="$(cd "$SCRIPT_DIR/../../../../core/rust" && pwd)" -# Output directories - separate device and simulator libraries -RUST_CORE_OUTPUT="$IOS_DIR/VaultStoreKit/RustCore" -DEVICE_LIB_OUTPUT="$RUST_CORE_OUTPUT/lib/device" -SIMULATOR_LIB_OUTPUT="$RUST_CORE_OUTPUT/lib/simulator" -HEADERS_OUTPUT="$RUST_CORE_OUTPUT/include" -SWIFT_BINDINGS_OUTPUT="$RUST_CORE_OUTPUT/Generated" - -# Parse arguments -FORCE_BUILD=false -BUILD_RELEASE=true +# Parse arguments to pass through +EXTRA_ARGS="" +FORCE_FLAG="" # Check Xcode environment for configuration if [ "${CONFIGURATION:-}" = "Debug" ]; then - BUILD_RELEASE=false + EXTRA_ARGS="--fast" fi while [[ $# -gt 0 ]]; do case $1 in --force) - FORCE_BUILD=true + FORCE_FLAG="--force" shift ;; --release) - BUILD_RELEASE=true + EXTRA_ARGS="" shift ;; --debug) - BUILD_RELEASE=false + EXTRA_ARGS="--fast" shift ;; *) - echo -e "${RED}Unknown option: $1${NC}" - exit 1 + shift ;; esac done -echo -e "${BLUE}========================================${NC}" -echo -e "${BLUE} Building Rust Core for iOS${NC}" -echo -e "${BLUE}========================================${NC}" - -# Check for Rust toolchain -if ! command -v rustc &> /dev/null; then - echo -e "${RED}Error: Rust is not installed${NC}" - echo "Install Rust from https://rustup.rs" - exit 1 -fi - -if ! command -v cargo &> /dev/null; then - echo -e "${RED}Error: Cargo is not installed${NC}" - exit 1 -fi - -# Check if rebuild is needed -CHECKSUM_FILE="$RUST_CORE_OUTPUT/.rust-core-checksum" -CURRENT_CHECKSUM="" - -if [ -d "$RUST_CORE_DIR/src" ]; then - # Calculate checksum of Rust source files and Cargo.toml - CURRENT_CHECKSUM=$(find "$RUST_CORE_DIR/src" -name "*.rs" -type f -exec md5 -q {} \; 2>/dev/null | md5 -q || echo "unknown") -fi - -if [ "$FORCE_BUILD" = false ] && [ -f "$CHECKSUM_FILE" ] && [ -f "$DEVICE_LIB_OUTPUT/libaliasvault_core.a" ]; then - 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}" - exit 0 - fi -fi - -echo -e "${YELLOW}Rust source changed, rebuilding...${NC}" - -# Determine build profile -if [ "$BUILD_RELEASE" = true ]; then - CARGO_FLAGS="--release" - CARGO_PROFILE="release" - echo -e " Build mode: ${GREEN}Release${NC}" -else - CARGO_FLAGS="" - CARGO_PROFILE="debug" - echo -e " Build mode: ${YELLOW}Debug${NC}" -fi - +# Call the main build script with incremental mode cd "$RUST_CORE_DIR" - -# Ensure iOS targets are installed -echo -e "${YELLOW}Checking iOS build targets...${NC}" -for target in aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios; 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 "$DEVICE_LIB_OUTPUT" "$SIMULATOR_LIB_OUTPUT" "$HEADERS_OUTPUT" "$SWIFT_BINDINGS_OUTPUT" - -# Create temp directory for intermediate files -TEMP_DIR=$(mktemp -d) -trap "rm -rf $TEMP_DIR" EXIT - -# Build for iOS device (arm64) -echo -e "${YELLOW}Building for iOS device (aarch64-apple-ios)...${NC}" -cargo build $CARGO_FLAGS --target aarch64-apple-ios --features uniffi - -# Build for iOS simulator (arm64 - Apple Silicon) -echo -e "${YELLOW}Building for iOS simulator arm64...${NC}" -cargo build $CARGO_FLAGS --target aarch64-apple-ios-sim --features uniffi - -# Build for iOS simulator (x86_64 - Intel Macs) -echo -e "${YELLOW}Building for iOS simulator x86_64...${NC}" -cargo build $CARGO_FLAGS --target x86_64-apple-ios --features uniffi - -# Copy device library -cp "target/aarch64-apple-ios/$CARGO_PROFILE/libaliasvault_core.a" "$DEVICE_LIB_OUTPUT/" - -# Create universal simulator library -echo -e "${YELLOW}Creating universal simulator library...${NC}" -lipo -create \ - "target/aarch64-apple-ios-sim/$CARGO_PROFILE/libaliasvault_core.a" \ - "target/x86_64-apple-ios/$CARGO_PROFILE/libaliasvault_core.a" \ - -output "$SIMULATOR_LIB_OUTPUT/libaliasvault_core.a" - -# Strip debug symbols in release mode -if [ "$BUILD_RELEASE" = true ]; then - echo -e "${YELLOW}Stripping debug symbols...${NC}" - strip -S "$DEVICE_LIB_OUTPUT/libaliasvault_core.a" 2>/dev/null || true - strip -S "$SIMULATOR_LIB_OUTPUT/libaliasvault_core.a" 2>/dev/null || true -fi - -# Generate Swift bindings -echo -e "${YELLOW}Generating Swift bindings...${NC}" -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 "$TEMP_DIR" - -# Copy headers -cp "$TEMP_DIR/aliasvault_coreFFI.h" "$HEADERS_OUTPUT/" - -# Create module.modulemap for the C header -# Note: Module name must match what UniFFI generates in Swift: aliasvault_coreFFI -cat > "$HEADERS_OUTPUT/module.modulemap" << 'EOF' -module aliasvault_coreFFI { - header "aliasvault_coreFFI.h" - export * -} -EOF - -# Copy Swift bindings -cp "$TEMP_DIR/aliasvault_core.swift" "$SWIFT_BINDINGS_OUTPUT/" - -echo -e "${GREEN}Swift bindings copied to: $SWIFT_BINDINGS_OUTPUT${NC}" - -# Store checksum for incremental builds -echo "$CURRENT_CHECKSUM" > "$CHECKSUM_FILE" - -# Show sizes -DEVICE_SIZE=$(ls -lh "$DEVICE_LIB_OUTPUT/libaliasvault_core.a" 2>/dev/null | awk '{print $5}' || echo "N/A") -SIM_SIZE=$(ls -lh "$SIMULATOR_LIB_OUTPUT/libaliasvault_core.a" 2>/dev/null | awk '{print $5}' || echo "N/A") - -echo "" -echo -e "${GREEN}========================================${NC}" -echo -e "${GREEN} Build Complete!${NC}" -echo -e "${GREEN}========================================${NC}" -echo -e " Device library: ${YELLOW}$DEVICE_SIZE${NC}" -echo -e " Simulator library: ${YELLOW}$SIM_SIZE${NC}" -echo -e " Output: ${YELLOW}$RUST_CORE_OUTPUT${NC}" -echo "" +exec ./build.sh --ios --incremental $FORCE_FLAG $EXTRA_ARGS diff --git a/core/rust/Cargo.lock b/core/rust/Cargo.lock index 128cf311d..2fc5c1a7c 100644 --- a/core/rust/Cargo.lock +++ b/core/rust/Cargo.lock @@ -16,15 +16,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anstream" version = "0.6.21" @@ -190,16 +181,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cc" -version = "1.2.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" -dependencies = [ - "find-msvc-tools", - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -212,12 +193,8 @@ version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "iana-time-zone", - "js-sys", "num-traits", "serde", - "wasm-bindgen", - "windows-link", ] [[package]] @@ -276,18 +253,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "find-msvc-tools" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" - [[package]] name = "fs-err" version = "2.11.0" @@ -320,30 +285,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "iana-time-zone" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -366,12 +307,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "libc" -version = "0.2.178" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" - [[package]] name = "log" version = "0.4.29" @@ -563,12 +498,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "siphasher" version = "0.3.11" @@ -844,65 +773,12 @@ dependencies = [ "nom", ] -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.61.2" diff --git a/core/rust/Cargo.toml b/core/rust/Cargo.toml index cc4ca6697..99ef3d90e 100644 --- a/core/rust/Cargo.toml +++ b/core/rust/Cargo.toml @@ -30,8 +30,8 @@ ffi = [] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -# Date/time handling for LWW comparison -chrono = { version = "0.4", features = ["serde"] } +# Date/time handling for LWW comparison (minimal features for smaller binary) +chrono = { version = "0.4", default-features = false, features = ["serde", "now"] } # Error handling thiserror = "1.0" @@ -68,7 +68,7 @@ incremental = true # Release profile - optimized for size [profile.release] opt-level = "z" -lto = true +lto = "fat" codegen-units = 1 panic = "abort" -strip = true +strip = "symbols" diff --git a/core/rust/build.sh b/core/rust/build.sh index 5013ab820..82466c5bd 100755 --- a/core/rust/build.sh +++ b/core/rust/build.sh @@ -57,6 +57,8 @@ BUILD_DOTNET=false BUILD_IOS=false BUILD_ANDROID=false FAST_MODE=false +INCREMENTAL=false +FORCE_BUILD=false # Parse arguments while [[ $# -gt 0 ]]; do @@ -94,19 +96,29 @@ while [[ $# -gt 0 ]]; do 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) with Swift bindings" + 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 " --mobile Build for both iOS and Android" 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" @@ -296,7 +308,7 @@ build_dotnet() { } # ============================================ -# iOS Build (Universal Binary + Swift Bindings) +# iOS Build (ARM64 only - device + simulator) # ============================================ build_ios() { echo "" @@ -311,9 +323,26 @@ build_ios() { exit 1 fi - # Install iOS targets if needed + # Incremental build check + local checksum_file="$IOS_APP_DIST/.rust-core-checksum" + local current_checksum="" + if [ -d "$SCRIPT_DIR/src" ]; then + current_checksum=$(find "$SCRIPT_DIR/src" -name "*.rs" -type f -exec md5 -q {} \; 2>/dev/null | md5 -q || echo "unknown") + fi + + 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 x86_64-apple-ios; do + 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" @@ -339,23 +368,13 @@ build_ios() { 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) + # 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 - # Build for iOS simulator (x86_64 - Intel Macs) - echo -e " Building for iOS simulator x86_64 (x86_64-apple-ios)..." - cargo build $cargo_flags --target x86_64-apple-ios --features uniffi - - # Copy device library + # Copy libraries (no lipo needed - single architecture for simulator) cp "target/aarch64-apple-ios/$cargo_profile/libaliasvault_core.a" "$IOS_DIR/device/" - - # Create universal simulator library (arm64 + x86_64) - echo -e " Creating universal simulator library..." - lipo -create \ - "target/aarch64-apple-ios-sim/$cargo_profile/libaliasvault_core.a" \ - "target/x86_64-apple-ios/$cargo_profile/libaliasvault_core.a" \ - -output "$IOS_DIR/simulator/libaliasvault_core.a" + 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 @@ -398,29 +417,47 @@ distribute_ios() { echo "" echo -e "${BLUE}Distributing to iOS app...${NC}" - mkdir -p "$IOS_APP_DIST/device" - mkdir -p "$IOS_APP_DIST/simulator" - mkdir -p "$IOS_APP_DIST/swift" + 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/device/" + 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/simulator/" + cp "$IOS_DIR/simulator/libaliasvault_core.a" "$IOS_APP_DIST/lib/simulator/" echo -e " Copied simulator library" fi - # Copy Swift bindings + # Copy headers and modulemap if [ -d "$IOS_DIR/swift" ] && [ -n "$(ls -A "$IOS_DIR/swift" 2>/dev/null)" ]; then - cp "$IOS_DIR/swift"/*.swift "$IOS_APP_DIST/swift/" 2>/dev/null || true - cp "$IOS_DIR/swift"/*.h "$IOS_APP_DIST/swift/" 2>/dev/null || true - cp "$IOS_DIR/swift"/*.modulemap "$IOS_APP_DIST/swift/" 2>/dev/null || true + cp "$IOS_DIR/swift"/*.h "$IOS_APP_DIST/include/" 2>/dev/null || true + + # Create module.modulemap for the C header + cat > "$IOS_APP_DIST/include/module.modulemap" << 'EOF' +module aliasvault_coreFFI { + header "aliasvault_coreFFI.h" + 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="" + if [ -d "$SCRIPT_DIR/src" ]; then + current_checksum=$(find "$SCRIPT_DIR/src" -name "*.rs" -type f -exec md5 -q {} \; 2>/dev/null | md5 -q || echo "unknown") + fi + echo "$current_checksum" > "$IOS_APP_DIST/.rust-core-checksum" + # Create README cat > "$IOS_APP_DIST/README.md" << 'README_EOF' # Rust Core iOS Library @@ -429,9 +466,10 @@ Auto-generated from `/core/rust`. Do not edit manually. ## Contents -- `device/libaliasvault_core.a` - Static library for iOS devices (arm64) -- `simulator/libaliasvault_core.a` - Universal static library for iOS simulator (arm64 + x86_64) -- `swift/` - Swift bindings generated by UniFFI +- `lib/device/libaliasvault_core.a` - Static library for iOS devices (arm64) +- `lib/simulator/libaliasvault_core.a` - Static library for iOS simulator (arm64 Apple Silicon) +- `include/` - C headers and modulemap for UniFFI bindings +- `Generated/` - Swift bindings generated by UniFFI ## Regenerate @@ -440,11 +478,14 @@ cd /core/rust ./build.sh --ios ``` -## Integration +## Xcode Integration -1. Add the static library to your Xcode project -2. Add the Swift bindings to your project -3. Import `aliasvault_core` in your Swift code +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}" @@ -626,8 +667,11 @@ if $BUILD_DOTNET; then fi if $BUILD_IOS; then + IOS_BUILD_SKIPPED=false build_ios - distribute_ios + if [ "$IOS_BUILD_SKIPPED" = false ]; then + distribute_ios + fi fi if $BUILD_ANDROID; then