Skip to content

UniFFI: Swift release follow-ups#1091

Merged
pblazej merged 14 commits into
mainfrom
blaze/fix-workflow-permissions
May 22, 2026
Merged

UniFFI: Swift release follow-ups#1091
pblazej merged 14 commits into
mainfrom
blaze/fix-workflow-permissions

Conversation

@pblazej
Copy link
Copy Markdown
Contributor

@pblazej pblazej commented May 14, 2026

Follow-up fixes surfaced while validating the publish pipeline against livekit/livekit-uniffi-xcframework#12.

Workflow

  • drop nested-job contents: write (blocked startup after the CodeQL autofix in UniFFI: Publish Swift packages #1078)
  • drop duplicate --force arg now that cargo-make adds its own
  • repin cargo-swift to upstream main (antoniusnaumann/cargo-swift@fe7becf — fork retired)
  • switch to macos-26-xlarge for ~½ wall-clock

Build output

  • bump Package.swift to swift-tools 6.0
  • clean tera whitespace so no stray blank line lands in .binaryTarget
  • include PrivacyInfo.xcprivacy in the publish set
  • inject CARGO_PROFILE_RELEASE_{DEBUG=limited,SPLIT_DEBUGINFO=packed} into the swift-xcframework task so each per-arch dylib gets a sidecar .dSYM (~8.5 MB × 11 targets, ~94 MB raw) without touching the workspace's lean Cargo.toml profile

Docs

  • document the dev-vs-release modes + local deps
  • symlink AGENTS.md → README.md

After merge: re-dispatch UniFFI packages with dry_run=false on a fresh test version to confirm end-to-end.

@pblazej pblazej requested a review from ladvoc as a code owner May 14, 2026 11:14
The CodeQL autofix landed in #1078 added `permissions: contents: read`
at the top level of uniffi-packages.yml, which then forbids any
nested job (including the called workflow uniffi-swift.yml) from
requesting higher permissions — workflow validation fails with:

  Error calling workflow ... The nested job 'build-and-publish' is
  requesting 'contents: write', but is only allowed 'contents: read'.

Neither job actually needs write: `gh release list` in resolve-tag is
read-only, and the publish step authenticates to the hosting repo
with UNIFFI_XCFRAMEWORK_PAT (not GITHUB_TOKEN). Drop the elevation
on both so the workflow can start.
@pblazej pblazej force-pushed the blaze/fix-workflow-permissions branch from d78bf92 to a60f3a8 Compare May 14, 2026 11:15
pblazej added 3 commits May 14, 2026 13:34
cargo-make 0.37.25+ adds its own --force when running install_crate,
so the explicit --force here makes cargo install reject the duplicate
argument with exit 105.
LiveKit's feature/framework-wrapping branch (PR #96 against
antoniusnaumann/cargo-swift) has been merged upstream. Point at the
upstream merge commit fe7becf so the fork dependency goes away.
Multi-arch xcframework build is the long pole. -xlarge is arm64 +
paid; expect roughly half the wall-clock of the default macos-26
runner.
@pblazej pblazej changed the title fix(uniffi): drop unneeded contents:write permissions UniFFI: Fix Swift workflow issues May 14, 2026
pblazej added 4 commits May 14, 2026 14:39
Dedent the if/elif/else/endif tags to column 0 and use {%- consistently
so the rendered Package.swift no longer emits a blank line between
.target and .binaryTarget. Verified locally — diff against the existing
hosting-repo manifest now shows only the intended version/checksum
changes.

Add the built PrivacyInfo.xcprivacy to the publish files list so the
hosting repo's copy stays in sync if the source manifest ever changes
(today it's identical, but the workflow shouldn't depend on that).
build-and-publish:
name: Build & publish Swift xcframework
runs-on: macos-26
runs-on: macos-26-xlarge
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems it leverages the cache heavily now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inject CARGO_PROFILE_RELEASE_DEBUG=limited and
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=packed into the swift-xcframework
task only, gated on the cargo-make release profile. Cargo treats them
as [profile.release] overrides during this build, so dsymutil emits a
sidecar .dSYM next to each per-arch dylib at
target/<arch>/release/deps/liblivekit_uniffi.dylib.dSYM (~8.5 MB each,
~94 MB across the 11 Apple targets).

Scoping via env vars keeps the workspace Cargo.toml profile lean —
FFI, node, and Linux/Windows/Android release builds stay stripped and
debug-info-free. limited (line tables + types) is ~3× smaller than full.

Verified locally with a clean rebuild.
@pblazej pblazej changed the title UniFFI: Fix Swift workflow issues fix(uniffi): unblock publish workflow + polish output May 15, 2026
# Linux/Windows/Android) remain on the lean Cargo.toml profile.
# `split-debuginfo = "packed"` triggers dsymutil → produces .dSYM bundles next
# to each per-arch .dylib at target/<arch>/release/deps/lib<name>.dylib.dSYM.
CARGO_PROFILE_RELEASE_DEBUG = { value = "limited", condition = { profiles = ["release"] } }
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wdyt @ladvoc?

It's not integrated into cargo-swift yet (needs another patch) but would be good to have, especially during initial adoption.

I confirmed it works locally.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also tackle that in a separate PR.

pblazej added 2 commits May 21, 2026 09:22
Add `--debug-symbols` to the cargo-swift invocation so each
xcframework slice gets a sidecar dSYMs/<framework>.framework.dSYM
bundle with the matching UUIDs (single-arch slices get the per-arch
dSYM, universal slices get a lipo'd fat-Mach-O dSYM). Xcode and App
Store Connect auto-load these for crash symbolisation; previously
all Rust frames showed as hex addresses.

`--debug-symbols` is the new flag added in
livekit/cargo-swift#feature/dsyms (f94e766). Repin the install_crate
to that revision until the patch lands upstream — the prior pin to
antoniusnaumann/cargo-swift@fe7becf doesn't expose the flag.

Expected size impact: xcframework.zip grows from ~5 MB to ~25 MB.
About 90% of consumers won't ever inspect the dSYMs, but the cost
is acceptable for the symbolisation win on the long tail.
tera-cli's --env mode warns 'unknown environment variable' for any
env var name matching SWIFT_DEBUG_*. The conditional flag passed to
cargo-swift was named SWIFT_DEBUG_SYMBOLS_FLAG and got flagged three
times per swift-generate-manifest run (one per .tera render).
Bisected by name — SWIFT_DSYMS_FLAG (and anything else not matching
SWIFT_DEBUG_*) passes silently. Place it right next to the existing
SWIFT_RELEASE_FLAG since both gate on the same release profile and
land in the same cargo-swift invocation.
@pblazej pblazej force-pushed the blaze/fix-workflow-permissions branch from 4d482a0 to e052fb1 Compare May 21, 2026 07:39
pblazej added 2 commits May 21, 2026 09:47
Adds a swift-check-size cargo-make task that runs between
swift-xcframework and swift-zip-xcframework on the release profile.

It measures the stripped, single-arch Mach-O at
  ios-arm64/Rust<name>.framework/Rust<name>
inside the produced xcframework. That binary equals the bytes a
typical iPhone user downloads after App Store thinning, so it's the
most meaningful proxy for the dep's app-size impact. Universal /
simulator slices are ~2x larger (two archs in one Mach-O) and would
overcount.

Default budget is 1 MiB. Current size is 932 KiB (88 KiB headroom)
— tight enough to catch regressions, loose enough to absorb
incremental uniffi-bindgen / std growth between releases. Bump
SPM_SIZE_LIMIT_BYTES on the cargo-make invocation to land an
intentional size jump.
Adds a swift-bloat cargo-make task that runs immediately after
swift-xcframework and before swift-check-size, printing sections /
compileunits / top-15 symbols from the iPhone-arm64 framework binary.

Why bloaty over cargo-bloat:
- analyses the actually shipped Mach-O (post-LTO, post-strip,
  post-lipo) instead of rebuilding a separate target
- works with our [lib] crate-type = [cdylib, staticlib, lib]
  (cargo-bloat refuses: 'only bin/dylib/cdylib supported')
- consumes the .dSYM we already embed via --debug-symbols for
  per-crate attribution at no extra cost

Auto-installs via brew when missing; degrades to skip with a hint
if neither bloaty nor brew is around so non-Mac contributors aren't
blocked.

Running before swift-check-size means a failing size gate ends with
the diagnostic already in the log — no need to rerun anything to
investigate.
@pblazej
Copy link
Copy Markdown
Contributor Author

pblazej commented May 21, 2026

2 notable mentions:

=== RustLiveKitUniFFI (ios-arm64) — bloaty -d symbols ===
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  74.8%   673Ki  73.8%   673Ki    [5150 Others]
   4.8%  43.3Ki   4.7%  43.3Ki    curve25519_dalek::backend::serial::u64::constants::ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN::h8cbef9b962a30404
   2.2%  19.8Ki   3.5%  32.0Ki    [__LINKEDIT]
   3.1%  28.1Ki   3.1%  28.1Ki    [__TEXT,__eh_frame]
   2.3%  21.0Ki   2.3%  21.0Ki    jsonwebtoken::crypto::rust_crypto::DEFAULT_PROVIDER::hd42c647c88b82832
   1.9%  17.1Ki   1.9%  17.1Ki    [__TEXT,__cstring]
   1.8%  16.0Ki   1.8%  16.0Ki    [__TEXT]
   1.4%  12.5Ki   0.0%      24    __MergedGlobals.1330
   0.0%       0   1.4%  12.5Ki    [__DATA]
   1.4%  12.3Ki   1.3%  12.3Ki    [__TEXT,__unwind_info]
   1.2%  10.9Ki   1.2%  10.9Ki    [__DATA_CONST,__const]
   1.1%  10.2Ki   1.1%  10.2Ki    __RNvNtNtNtCs4C5O66Rcvz4_4core3num7dec2flt5table17POWER_OF_FIVE_128
   1.1%  9.71Ki   1.1%  9.71Ki    zmij::POW10_SIGNIFICANDS::hae2125afb432ed44
   1.0%  9.39Ki   1.0%  9.39Ki    __RNvNtNtNtCskZn6J6i4cQL_3std12backtrace_rs9symbolize5gimli7resolve
   0.9%  8.41Ki   0.9%  8.41Ki    zmij::DIGITS2::h88ccc8ddf3258ce1
   0.9%  7.71Ki   0.8%  7.71Ki    __RNvMs_NtNtNtCskZn6J6i4cQL_3std12backtrace_rs9symbolize5gimliNtB4_7Context3new
 100.0%   899Ki 100.0%   912Ki    TOTAL

@pblazej pblazej changed the title fix(uniffi): unblock publish workflow + polish output UniFFI: Swift release follow-ups May 21, 2026
@pblazej pblazej requested review from 1egoman and davidliu May 21, 2026 08:23
@pblazej pblazej added the internal to tag changes that don't require changelog documentation label May 21, 2026
Copy link
Copy Markdown
Contributor

@davidliu davidliu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I'll see if I can get size and debug symbols stuff into android as well.

Move the Swift mode/dependency details out of the main README into a
dedicated support/swift/README.md, and include the consumer-side
Package.swift dependency snippet for local iteration. README points to
it with a one-liner, matching the Android convention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pblazej
Copy link
Copy Markdown
Contributor Author

pblazej commented May 22, 2026

Merging, I split the README for Swift - similarly to Android (better choice).

@pblazej pblazej merged commit 61e6040 into main May 22, 2026
23 checks passed
@pblazej pblazej deleted the blaze/fix-workflow-permissions branch May 22, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal to tag changes that don't require changelog documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants