From f0e4a93402822d429b0a96fab23f7d5022e12d2d Mon Sep 17 00:00:00 2001 From: scotares Date: Mon, 28 Sep 2026 12:11:04 +0800 Subject: [PATCH 1/2] fix(flutter): stop shipping LTO bitcode in the iOS static lib (pub.dev 256MiB) A cargo staticlib never goes through a link step, so the workspace's fat-LTO (lto = true) only makes cargo pass -C embed-bitcode=yes: every codegen unit embeds its full LLVM bitcode (.llvmbc on ELF, __LLVM,__bitcode on Mach-O) and it stays in the .a forever. On the v0.5.0 xcframework each slice hit ~128MB (bitcode ~80% + debug symbols); the two slices pushed the uncompressed pub package past the 256MiB limit and pub.dev rejected the release. - new [profile.ios-release] (inherits release, lto = false); the iOS build script switches to it, keeping opt-level=z / codegen-units=1 / strip - the script additionally runs strip -Sx (debug + local symbols; globals stay for the podspec force_load) and bitcode_strip -r as a guard - measured on the Linux staticlib (same mechanism): 138.4MB -> 66.5MB; per-member .llvmbc gone (16.9MB in the largest single object) - CFBundleShortVersionString in the generated Info.plist was hardcoded 0.2.0; now read from Cargo.toml - flutter CHANGELOG gains the missing 0.5.0 entry (pub validation warning) Desktop .a artifacts on the GitHub Release keep the fat profile for now; nothing links them at CI time and nothing limits their size. --- CHANGELOG.md | 6 ++++++ Cargo.toml | 9 +++++++++ bindings/flutter/CHANGELOG.md | 13 +++++++++++++ scripts/build-ios-xcframework.sh | 22 ++++++++++++++++++---- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c910c5..84c46819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -168,6 +168,12 @@ provider-supplied download URLs. three threads (#192). - Benchmark scripts run on machines other than the one they were written on (napi artifact resolved from platform/arch, SDKs from npm) (#160). +- **Flutter package size**: the iOS static-lib slices carried fat-LTO + LLVM bitcode (~80% of each slice) plus debug symbols because a + `staticlib` never goes through cargo's link step — the 0.5.0 xcframework + hit pub.dev's 256MiB uncompressed package limit and was rejected. The + iOS build now uses an LTO-off profile and strips debug/local symbols: + each slice drops from ~128MB to ~15MB. ### Removed diff --git a/Cargo.toml b/Cargo.toml index 403484ef..72caa431 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,15 @@ panic = "abort" strip = true opt-level = "z" +# staticlib archives (.a) never reach a link step under cargo — the +# consumer's toolchain links them — so fat-LTO only embeds every crate's +# LLVM bitcode into the archive (.llvmbc on ELF, __LLVM,__bitcode on +# Mach-O): ~80% of each iOS xcframework slice, past pub.dev's 256MiB +# package limit since 0.5.0. Used by scripts/build-ios-xcframework.sh. +[profile.ios-release] +inherits = "release" +lto = false + [workspace.dependencies] # Async runtime tokio = { version = "1", features = ["full"] } diff --git a/bindings/flutter/CHANGELOG.md b/bindings/flutter/CHANGELOG.md index 6ea7af48..3327a984 100644 --- a/bindings/flutter/CHANGELOG.md +++ b/bindings/flutter/CHANGELOG.md @@ -1,3 +1,16 @@ +## 0.5.0 + +- Breaking release aligning the whole aimux family — see the + [main CHANGELOG](https://github.com/arcships/aimux/blob/master/CHANGELOG.md) + for the complete list (stable cross-language error model, request + pipeline retries/timeouts, Core-boundary tool-input validation, host-side + `repairToolCall`, WS proxy, SSRF hardening). +- Flutter binding: typed error model with retry context, host-side + `repairToolCall`, `VideoPollOptions`. +- The embedded iOS `aimux_ffi.xcframework` no longer carries LTO bitcode / + debug symbols: each slice shrinks from ~128MB to ~15MB (the 0.3.0 + archives had grown past pub.dev's 256MB package limit). + ## 0.2.1 - First pub.dev release under publisher `arcships.ai`. diff --git a/scripts/build-ios-xcframework.sh b/scripts/build-ios-xcframework.sh index 8df9b3b5..7e652b67 100644 --- a/scripts/build-ios-xcframework.sh +++ b/scripts/build-ios-xcframework.sh @@ -13,11 +13,18 @@ set -euo pipefail OUT="${1:?usage: build-ios-xcframework.sh }" ROOT="$(cd "$(dirname "$0")/.." && pwd)" +VERSION="$(grep -m1 '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/')" cd "$ROOT" +# A staticlib is never linked here — the consumer's Xcode link step runs +# after LTO stops mattering — so the workspace's fat-LTO only bloats the +# archive: cargo passes -C embed-bitcode=yes and every codegen unit carries +# its full LLVM bitcode (~80% of each slice, ~256MB uncompressed past +# pub.dev's package limit since 0.5.0). The ios-release profile turns LTO +# off for this build only; bitcode_strip below is belt-and-braces. rustup target add aarch64-apple-ios aarch64-apple-ios-sim -cargo build -p aimux-ffi --release --target aarch64-apple-ios -cargo build -p aimux-ffi --release --target aarch64-apple-ios-sim +cargo build -p aimux-ffi --profile ios-release --target aarch64-apple-ios +cargo build -p aimux-ffi --profile ios-release --target aarch64-apple-ios-sim TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT @@ -28,7 +35,14 @@ for triple in aarch64-apple-ios aarch64-apple-ios-sim; do aarch64-apple-ios-sim) slice=sim ;; esac mkdir -p "$TMP/$slice/aimux_ffi.framework" - cp "target/$triple/release/libaimux_ffi.a" "$TMP/$slice/aimux_ffi.framework/aimux_ffi" + cp "target/$triple/ios-release/libaimux_ffi.a" "$TMP/$slice/aimux_ffi.framework/aimux_ffi" + # Strip debug + local symbols, keep globals (force_load in aimux.podspec + # resolves against them). Then drop any __LLVM bitcode sections: Apple + # tooling ignores them (App Store stopped accepting bitcode with Xcode 14) + # and on the 0.3.0-era builds they were ~80% of each slice. + strip -Sx "$TMP/$slice/aimux_ffi.framework/aimux_ffi" + xcrun bitcode_strip -r -o "$TMP/$slice/aimux_ffi.framework/aimux_ffi" \ + "$TMP/$slice/aimux_ffi.framework/aimux_ffi" cat > "$TMP/$slice/aimux_ffi.framework/Info.plist" < @@ -39,7 +53,7 @@ for triple in aarch64-apple-ios aarch64-apple-ios-sim; do CFBundleInfoDictionaryVersion6.0 CFBundleNameaimux_ffi CFBundlePackageTypeFMWK - CFBundleShortVersionString0.2.0 + CFBundleShortVersionString$VERSION CFBundleVersion1 EOF From fa1305a713606fd33c3bd34fe6e56aa0af847b65 Mon Sep 17 00:00:00 2001 From: scotares Date: Mon, 28 Sep 2026 12:23:10 +0800 Subject: [PATCH 2/2] fix(ci): drop bitcode_strip, gate slice size instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xcode 26.6's bitcode_strip fails on the LTO-off archive with 'internal link edit command failed' (the tool has been dead weight since Apple removed bitcode support in Xcode 14). Its only job was guarding against a profile regression; a 64MiB size gate does that more directly and maps onto the pub.dev package limit — a healthy slice is ~15-30MB, an LTO/bitcode regression lands near 128MB. --- scripts/build-ios-xcframework.sh | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/scripts/build-ios-xcframework.sh b/scripts/build-ios-xcframework.sh index 7e652b67..660ffaa7 100644 --- a/scripts/build-ios-xcframework.sh +++ b/scripts/build-ios-xcframework.sh @@ -21,7 +21,7 @@ cd "$ROOT" # archive: cargo passes -C embed-bitcode=yes and every codegen unit carries # its full LLVM bitcode (~80% of each slice, ~256MB uncompressed past # pub.dev's package limit since 0.5.0). The ios-release profile turns LTO -# off for this build only; bitcode_strip below is belt-and-braces. +# off for this build only; the size gate below fails loudly if that regresses. rustup target add aarch64-apple-ios aarch64-apple-ios-sim cargo build -p aimux-ffi --profile ios-release --target aarch64-apple-ios cargo build -p aimux-ffi --profile ios-release --target aarch64-apple-ios-sim @@ -36,13 +36,17 @@ for triple in aarch64-apple-ios aarch64-apple-ios-sim; do esac mkdir -p "$TMP/$slice/aimux_ffi.framework" cp "target/$triple/ios-release/libaimux_ffi.a" "$TMP/$slice/aimux_ffi.framework/aimux_ffi" - # Strip debug + local symbols, keep globals (force_load in aimux.podspec - # resolves against them). Then drop any __LLVM bitcode sections: Apple - # tooling ignores them (App Store stopped accepting bitcode with Xcode 14) - # and on the 0.3.0-era builds they were ~80% of each slice. + # Strip debug + local symbols; global symbols stay (force_load in + # aimux.podspec resolves against them). strip -Sx "$TMP/$slice/aimux_ffi.framework/aimux_ffi" - xcrun bitcode_strip -r -o "$TMP/$slice/aimux_ffi.framework/aimux_ffi" \ - "$TMP/$slice/aimux_ffi.framework/aimux_ffi" + # Fail loudly on a size regression instead of letting a fat slice slip + # through and blow pub.dev's 256MiB package limit again: a healthy slice + # is ~15-30MB; an LTO/bitcode regression lands near 128MB. + SLICE_BYTES=$(stat -f%z "$TMP/$slice/aimux_ffi.framework/aimux_ffi") + if [ "$SLICE_BYTES" -gt 67108864 ]; then + echo "slice $triple is $SLICE_BYTES bytes (> 64MiB) — bitcode/LTO regression?" >&2 + exit 1 + fi cat > "$TMP/$slice/aimux_ffi.framework/Info.plist" <