Files
bitchat/localPackages/Arti/build-ios.sh
T
jackandClaude Fable 5 4093ee6733 Rebuild Arti from audited source with enforced provenance
Vendored arti.xcframework rebuilt from source (Rust 1.96.0, normalized
archive metadata for reproducible hashes). New ARTI-BINARY-PROVENANCE.md
records toolchain, rebuild steps, and a SHA256 manifest for every file
in the xcframework. A new CI workflow turns that policy into a gate:
PRs must keep the binary matching the manifest, and binary changes must
ship with source/lockfile/build-script evidence.

Also raises TorManager.awaitReady's default timeout from 25s to 75s to
match the bootstrap monitor deadline - a shorter wait reported "not
ready" while Arti was still legitimately bootstrapping, silently
stranding queued relay work.

Privacy policy, Tor integration doc, and privacy assessment updated to
match the current implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:22:15 +01:00

382 lines
9.6 KiB
Bash
Executable File

#!/bin/bash
#
# Build arti-bitchat for iOS/macOS with aggressive size optimization
#
# Output: Frameworks/arti.xcframework containing static libraries for:
# - aarch64-apple-ios (iOS device)
# - aarch64-apple-ios-sim (iOS simulator, Apple Silicon)
# - x86_64-apple-ios (iOS simulator, Intel - optional)
# - aarch64-apple-darwin (macOS)
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Configuration
CRATE_NAME="arti-bitchat"
LIB_NAME="libarti_bitchat.a"
FRAMEWORK_NAME="arti"
OUTPUT_DIR="$SCRIPT_DIR/Frameworks"
# Targets to build
TARGETS=(
"aarch64-apple-ios" # iOS device
"aarch64-apple-ios-sim" # iOS simulator (Apple Silicon)
"aarch64-apple-darwin" # macOS
)
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Check prerequisites
check_prerequisites() {
log_info "Checking prerequisites..."
if ! command -v rustc &> /dev/null; then
log_error "Rust is not installed. Please install via rustup."
exit 1
fi
if ! command -v cargo &> /dev/null; then
log_error "Cargo is not installed. Please install via rustup."
exit 1
fi
# Check/install targets
for target in "${TARGETS[@]}"; do
if ! rustup target list --installed | grep -q "$target"; then
log_info "Installing target: $target"
rustup target add "$target"
fi
done
# Install cbindgen if needed
if ! command -v cbindgen &> /dev/null; then
log_info "Installing cbindgen..."
cargo install cbindgen
fi
log_info "Prerequisites OK"
}
# Set up aggressive size optimization flags and deployment targets
setup_rustflags() {
local target="$1"
# Base flags for size optimization
export RUSTFLAGS="-C opt-level=z -C lto=fat -C codegen-units=1 -C panic=abort -C strip=symbols"
# Set deployment targets to suppress linker warnings about version mismatches
case "$target" in
*-apple-ios-sim*)
export IPHONEOS_DEPLOYMENT_TARGET="16.0"
# Simulator uses iPhone SDK but needs the sim target
;;
*-apple-ios*)
export IPHONEOS_DEPLOYMENT_TARGET="16.0"
;;
*-apple-darwin*)
export MACOSX_DEPLOYMENT_TARGET="13.0"
;;
esac
log_info "RUSTFLAGS: $RUSTFLAGS"
log_info "Deployment target: MACOSX=$MACOSX_DEPLOYMENT_TARGET IPHONEOS=$IPHONEOS_DEPLOYMENT_TARGET"
}
# Build for a single target
build_target() {
local target="$1"
log_info "Building for target: $target"
setup_rustflags "$target"
# Build release
cargo build --release --target "$target" -p "$CRATE_NAME"
# Check output
local lib_path="target/$target/release/$LIB_NAME"
if [[ -f "$lib_path" ]]; then
local size=$(du -h "$lib_path" | cut -f1)
log_info "Built $lib_path ($size)"
else
log_error "Build failed: $lib_path not found"
exit 1
fi
}
# Create xcframework from built libraries
create_xcframework() {
log_info "Creating xcframework..."
local xcframework_path="$OUTPUT_DIR/$FRAMEWORK_NAME.xcframework"
# Remove existing xcframework
rm -rf "$xcframework_path"
mkdir -p "$OUTPUT_DIR"
# Build the xcodebuild command
local cmd="xcodebuild -create-xcframework"
for target in "${TARGETS[@]}"; do
local lib_path="$SCRIPT_DIR/target/$target/release/$LIB_NAME"
if [[ -f "$lib_path" ]]; then
# Strip the library for additional size reduction
log_info "Stripping $target library..."
strip -x "$lib_path" 2>/dev/null || true
# Normalize archive metadata so repeated rebuilds are byte-stable.
local normalized_path="$lib_path.normalized"
xcrun libtool -static -D -no_warning_for_no_symbols "$lib_path" -o "$normalized_path"
mv "$normalized_path" "$lib_path"
cmd="$cmd -library $lib_path"
# Add headers if they exist
local header_dir="$OUTPUT_DIR/include"
if [[ -d "$header_dir" ]]; then
cmd="$cmd -headers $header_dir"
fi
else
log_warn "Skipping missing library: $lib_path"
fi
done
cmd="$cmd -output $xcframework_path"
log_info "Running: $cmd"
eval "$cmd"
if [[ -d "$xcframework_path" ]]; then
cat > "$xcframework_path/Info.plist" << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AvailableLibraries</key>
<array>
<dict>
<key>BinaryPath</key>
<string>libarti_bitchat.a</string>
<key>HeadersPath</key>
<string>Headers</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>libarti_bitchat.a</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>libarti_bitchat.a</string>
<key>HeadersPath</key>
<string>Headers</string>
<key>LibraryIdentifier</key>
<string>ios-arm64-simulator</string>
<key>LibraryPath</key>
<string>libarti_bitchat.a</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>libarti_bitchat.a</string>
<key>HeadersPath</key>
<string>Headers</string>
<key>LibraryIdentifier</key>
<string>macos-arm64</string>
<key>LibraryPath</key>
<string>libarti_bitchat.a</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>macos</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>
EOF
local size=$(du -sh "$xcframework_path" | cut -f1)
log_info "Created $xcframework_path ($size)"
else
log_error "Failed to create xcframework"
exit 1
fi
}
# Generate C header using cbindgen
generate_header() {
log_info "Generating C header..."
local header_dir="$OUTPUT_DIR/include"
local header_path="$header_dir/arti.h"
mkdir -p "$header_dir"
# Create cbindgen.toml if it doesn't exist
if [[ ! -f "$CRATE_NAME/cbindgen.toml" ]]; then
cat > "$CRATE_NAME/cbindgen.toml" << 'EOF'
language = "C"
include_guard = "ARTI_H"
no_includes = true
sys_includes = ["stdint.h", "stdbool.h"]
[export]
include = ["arti_start", "arti_stop", "arti_is_running", "arti_bootstrap_progress", "arti_bootstrap_summary", "arti_go_dormant", "arti_wake"]
[fn]
args = "Auto"
[parse]
parse_deps = false
EOF
fi
cbindgen --config "$CRATE_NAME/cbindgen.toml" \
--crate "$CRATE_NAME" \
--output "$header_path"
if [[ -f "$header_path" ]]; then
log_info "Generated $header_path"
cat "$header_path"
else
log_warn "cbindgen did not generate header, creating manually..."
# Fallback: create header manually
cat > "$header_path" << 'EOF'
#ifndef ARTI_H
#define ARTI_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Start Arti with a SOCKS5 proxy.
*
* @param data_dir Path to data directory for Tor state (C string)
* @param socks_port Port for SOCKS5 proxy (e.g., 39050)
* @return 0 on success, negative on error
*/
int32_t arti_start(const char *data_dir, uint16_t socks_port);
/**
* Stop Arti gracefully.
*
* @return 0 on success, -1 if not running
*/
int32_t arti_stop(void);
/**
* Check if Arti is currently running.
*
* @return 1 if running, 0 if not running
*/
int32_t arti_is_running(void);
/**
* Get the current bootstrap progress (0-100).
*
* @return Progress percentage
*/
int32_t arti_bootstrap_progress(void);
/**
* Get the current bootstrap summary string.
*
* @param buf Buffer to write the summary into
* @param len Length of the buffer
* @return Number of bytes written, -1 on error
*/
int32_t arti_bootstrap_summary(char *buf, int32_t len);
/**
* Signal Arti to go dormant (reduce resource usage).
*
* @return 0 on success, -1 if not running
*/
int32_t arti_go_dormant(void);
/**
* Signal Arti to wake from dormant mode.
*
* @return 0 on success, -1 if not running
*/
int32_t arti_wake(void);
#ifdef __cplusplus
}
#endif
#endif /* ARTI_H */
EOF
log_info "Created manual header at $header_path"
fi
}
# Print size report
print_size_report() {
log_info "=== Size Report ==="
for target in "${TARGETS[@]}"; do
local lib_path="$SCRIPT_DIR/target/$target/release/$LIB_NAME"
if [[ -f "$lib_path" ]]; then
local size=$(du -h "$lib_path" | cut -f1)
echo " $target: $size"
fi
done
local xcframework_path="$OUTPUT_DIR/$FRAMEWORK_NAME.xcframework"
if [[ -d "$xcframework_path" ]]; then
local total_size=$(du -sh "$xcframework_path" | cut -f1)
echo " xcframework total: $total_size"
fi
}
# Main
main() {
log_info "Building arti-bitchat for iOS/macOS"
log_info "=================================="
check_prerequisites
generate_header
for target in "${TARGETS[@]}"; do
build_target "$target"
done
create_xcframework
print_size_report
log_info "Build complete!"
log_info "xcframework: $OUTPUT_DIR/$FRAMEWORK_NAME.xcframework"
}
# Run
main "$@"