#!/usr/bin/env bash # # build-libs.sh — build libvoicecat for each supported client platform and # stage the artifacts under dist/lib/. # # Artifacts per platform: # macos → dist/lib/macos/ libvoicecat.a + libvoicecat-fat.a + voicecat.h + module.modulemap # ios → dist/lib/ios-device/ (arm64-ios slice) # ios-sim → dist/lib/ios-sim/ (arm64-ios-sim slice) # windows → dist/lib/windows/ voicecat.dll + voicecat.h # xcframework → dist/lib/VoiceCatCore.xcframework/ (stitched Apple slices) # # The Apple slices + XCFramework are produced by clients/apple/scripts/ # build-xcframework.sh (the validated flow); this script drives it and stages # the outputs. The Windows DLL comes from the `windows-client` preset. # # Usage: # scripts/build-libs.sh # host default (macos on macOS, windows on Windows) # scripts/build-libs.sh --platform macos # scripts/build-libs.sh --platform ios # scripts/build-libs.sh --platform ios-sim # scripts/build-libs.sh --platform windows # scripts/build-libs.sh --all-apple # macos + ios + ios-sim + xcframework (macOS host) # scripts/build-libs.sh --all # everything buildable on this host # scripts/build-libs.sh --dist /out --no-configure # scripts/build-libs.sh -h|--help # # Platform availability: macos / ios / ios-sim require a macOS host; windows # requires a Windows host. Requires VCPKG_ROOT. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VC_SCRIPT_NAME="build-libs" source "$SCRIPT_DIR/common.sh" PLATFORMS=() DO_CONFIGURE=true while [[ $# -gt 0 ]]; do case "$1" in --dist) vc_set_dist "$2"; shift 2 ;; --no-configure) DO_CONFIGURE=false; shift ;; --platform) PLATFORMS+=( "$2" ); shift 2 ;; --all-apple) PLATFORMs_all_apple=1; shift ;; --all) PLATFORMS=( all-host ); shift ;; -h|--help) vc_print_help "$0"; exit 0 ;; *) vc_die "unknown arg: $1 (try --help)" ;; esac done HOST="$(vc_host_os)" # --all-apple expands to the three Apple platforms. if [[ -n "${PLATFORMs_all_apple:-}" ]]; then PLATFORMS=( macos ios ios-sim ) fi # Default: host-appropriate single platform. if [[ ${#PLATFORMS[@]} -eq 0 ]]; then case "$HOST" in macos) PLATFORMS=( macos ) ;; windows) PLATFORMS=( windows ) ;; *) vc_die "no default library platform for host '$HOST'. Pass --platform explicitly." ;; esac fi # Expand the meta-target. if [[ " ${PLATFORMS[*]} " == *" all-host "* ]]; then PLATFORMS=() case "$HOST" in macos) PLATFORMS=( macos ios ios-sim ) ;; windows) PLATFORMS=( windows ) ;; *) vc_die "--all: nothing buildable on host '$HOST'." ;; esac fi vc_log "dist dir: $VC_DIST_DIR" vc_log "platforms: ${PLATFORMS[*]}" # Validate platform availability against host. for p in "${PLATFORMS[@]}"; do case "$p" in macos|ios|ios-sim) [[ "$HOST" == "macos" ]] || vc_die "platform '$p' requires a macOS host." ;; windows) [[ "$HOST" == "windows" ]] || vc_die "platform '$p' requires a Windows host." ;; *) vc_die "unknown platform '$p' (try --help)" ;; esac done HAVE_APPLE=false HAVE_WINDOWS=false for p in "${PLATFORMS[@]}"; do case "$p" in macos|ios|ios-sim) HAVE_APPLE=true ;; windows) HAVE_WINDOWS=true ;; esac done # ── Apple slices + XCFramework ────────────────────────────────────────────────── # Stage one slice's .a + headers + module map into dist/lib/. stage_apple_slice() { local preset="$1" sub="$2" local lib="$VC_REPO_ROOT/build/$preset/lib/libvoicecat.a" local fat="$VC_REPO_ROOT/build/$preset/lib/libvoicecat-fat.a" local out; out="$(vc_dist_subdir "lib/$sub")" [[ -f "$lib" ]] || vc_die "expected $lib not found (did the xcframework build run?)" cp "$lib" "$out/" [[ -f "$fat" ]] && cp "$fat" "$out/" || true cp "$VC_REPO_ROOT/core/include/voicecat.h" "$out/" cat > "$out/module.modulemap" <<'MM' module VoiceCatC { header "voicecat.h" export * } MM vc_ok "$sub: libvoicecat.a ($(vc_file_size "$lib") bytes) -> $out" } if $HAVE_APPLE; then vc_resolve_vcpkg_root apple-dev vc_step "build Apple slices via build-xcframework.sh" ALL_THREE=false if [[ " ${PLATFORMS[*]} " == *" macos "* && " ${PLATFORMS[*]} " == *" ios "* && " ${PLATFORMS[*]} " == *" ios-sim "* ]]; then ALL_THREE=true fi xcfw_invoke() { local args=() $DO_CONFIGURE || args+=( --no-configure ) args+=( "$@" ) "$VC_REPO_ROOT/clients/apple/scripts/build-xcframework.sh" "${args[@]}" } if $ALL_THREE; then xcfw_invoke --all stage_apple_slice apple-dev macos stage_apple_slice apple-ios ios-device stage_apple_slice apple-ios-sim ios-sim else for p in "${PLATFORMS[@]}"; do case "$p" in macos) xcfw_invoke --preset apple-dev; stage_apple_slice apple-dev macos ;; ios) xcfw_invoke --preset apple-ios; stage_apple_slice apple-ios ios-device ;; ios-sim) xcfw_invoke --preset apple-ios-sim; stage_apple_slice apple-ios-sim ios-sim ;; esac done fi # Stage the stitched XCFramework (whatever slices the last call produced). XCFW="$VC_REPO_ROOT/clients/apple/VoiceCatCore.xcframework" [[ -d "$XCFW" ]] || vc_die "xcframework not found at $XCFW" LIB_DIR="$VC_DIST_DIR/lib" mkdir -p "$LIB_DIR" rm -rf "$LIB_DIR/VoiceCatCore.xcframework" cp -R "$XCFW" "$LIB_DIR/" vc_ok "VoiceCatCore.xcframework -> $LIB_DIR/" fi # ── Windows DLL ───────────────────────────────────────────────────────────────── if $HAVE_WINDOWS; then vc_resolve_vcpkg_root windows-client vc_step "build Windows DLL (preset: windows-client)" if $DO_CONFIGURE; then cmake --preset windows-client fi cmake --build --preset windows-client DLL="$VC_REPO_ROOT/build/windows-client/bin/voicecat.dll" [[ -f "$DLL" ]] || vc_die "expected $DLL not found" OUT="$(vc_dist_subdir lib/windows)" cp "$DLL" "$OUT/" cp "$VC_REPO_ROOT/core/include/voicecat.h" "$OUT/" vc_ok "windows: voicecat.dll ($(vc_file_size "$DLL") bytes) -> $OUT" fi vc_ok "done -> $VC_DIST_DIR/lib"