Skip to content

feat(swift-interop): generate and link thunks in app builds (4/7) - #521

Draft
NathanWalker wants to merge 4 commits into
swift-interop/3-modules-protocolsfrom
swift-interop/4-app-builds
Draft

NathanWalker wants to merge 4 commits into
swift-interop/3-modules-protocolsfrom
swift-interop/4-app-builds

Conversation

@NathanWalker

@NathanWalker NathanWalker commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Swift interop stack — review bottom-up; each PR shows only its own commits. Merge in order; after a squash merge, rebase the next branch onto main. Design discussion: RFC NativeScript/rfcs#57.

  1. feat(metadata-generator): Swift symbol graphs to thunks and TypeScript declarations (Swift interop 1/7) #518 generator: symbol graphs → IR → thunks + .d.ts
  2. feat(runtime): ns:swift calls Swift through generated thunks (Swift interop 2/7) #519 runtime: ns:swift core
  3. feat(swift-interop): modules, generics, protocols, Observation and SwiftUI (3/7) #520 modules, generics, protocols, Observation, SwiftUI
  4. feat(swift-interop): generate and link thunks in app builds (4/7) #521 app builds ← this PR
  5. feat(swift-interop): returning closures, generic functions, tuples, Result and C structs (5/7) #522 more values: returning closures, generic functions, tuples, Result, C structs
  6. feat(swift-interop): adapter lifetime, cancellation, subscripts, Combine and operators (6/7) #523 adapter lifetime, cancellation, subscripts, Combine, operators
  7. feat(swift-interop): Any, UUID and Decimal, performance, and docs (Swift interop 7/7) #517 Any/UUID/Decimal, performance, docs

Apps get thunks for the Swift modules they name, and a benchmark compares the Swift path with the Objective-C one.

App_Resources/iOS/build.xcconfig
  NS_SWIFT_MODULES = WeatherKit MyPackage
nsld.sh (iOS and visionOS templates)
  build-step-swift-interop.py
    swift-symbolgraph-extract → generator --swift-verify → swiftc → link
    unchanged module → reuse the cached thunk object

The CLI needs no change. TestRunner/app/tests/SwiftInteropBenchmarks.js adds benchmarks of the same API through both paths.

Evidence

  • Before: thunks had to be generated and linked by hand.
    After: a real app (its own module, WeatherKit, a local SwiftPM package) builds through ns build ios and imports ns:swift in Debug and Release. App-level plugin modules and relative paths resolve. An unchanged module reuses its thunk object on relink.

Merge Danger

Door: two-way

Blast Radius: app builds

nsld.sh changes in the iOS and visionOS templates but does nothing unless NS_SWIFT_MODULES is set, so apps without it link exactly as before.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

SwiftInteropBenchmarks.js times matched operations through the
Objective-C/C metadata path and through Swift thunks:
- a function;
- class and instance methods;
- a string round trip;
- object construction;
- a property read.

It writes the results to Documents/swift-bench.txt and asserts nothing.
The fixture gains the Swift counterparts.

The benchmarks showed instance calls and property accesses copying their
member group on every call to filter a generic family's overloads by
receiver. Groups now record whether they mix owners, and only those are
filtered. With that, the Swift path matches or beats the Objective-C path
in a Debug simulator build (docs/swift-interop.md has the numbers).
Apps list the Swift modules JavaScript uses in NS_SWIFT_MODULES, in
App_Resources/iOS/build.xcconfig. SDK modules, SwiftPM packages and the
app's own module are all supported.

At link time, nsld.sh (iOS and visionOS templates) runs the new
build-step-swift-interop.py for each architecture, next to the
Objective-C metadata step:
- it extracts the modules' symbol graphs from the build products and the
  SDK;
- it generates and verifies them as one unit;
- it compiles the thunks to an object;
- it hands nsld the object and a -u flag per register symbol to link.

The script ships beside build-step-metadata-generator.py, so the CLI
needs no change.

Checked against Xcode-shaped environments: the SwiftDemo/SwiftDemoKit
modules and WeatherKit each produce an object that exports its register
symbols. A full `ns build` against a packed runtime has not been run yet.
The app build step now passes the app's header search paths to symbol
graph extraction and to the thunk compile, so clang modules from plugin
sources resolve. One example is @nativescript/core's NativeScriptEmbedder,
which an app's Swift module imports. Relative search paths are resolved
against SRCROOT, since the step runs from the metadata generator's
folder.

Validated with an app: the app's own Swift module plus WeatherKit, built
through `ns build ios` with the packed runtime. Debug and Release
simulator builds both pass a startup check of every ns:swift feature.
The app build step keys the generated object on a hash of the extracted
symbol graphs, the generator binary, the step itself, and the generator
and compiler command lines. A relink with the same key reuses the
previous object instead of regenerating, verifying and recompiling, so an
unchanged module costs only its symbol graph extraction.
@NathanWalker
NathanWalker force-pushed the swift-interop/4-app-builds branch from 91839dc to e76a9ec Compare October 21, 2026 16:44
@NathanWalker
NathanWalker force-pushed the swift-interop/3-modules-protocols branch from 39dac9d to 83c8aff Compare October 21, 2026 16:44
@NathanWalker NathanWalker added this to the 10.0 milestone Oct 21, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant