Add source wrapper target for Tuist xcframework embedding#2
Add source wrapper target for Tuist xcframework embedding#2thomasflad wants to merge 1 commit intopowersync-ja:mainfrom
Conversation
Build tools like Tuist that resolve SPM packages into Xcode projects cannot embed a dynamic xcframework when the library product directly wraps a binaryTarget. The xcframework gets linked but not added to the app's "Embed Frameworks" build phase, causing a runtime crash: Library not loaded: @rpath/powersync-sqlite-core.framework/powersync-sqlite-core Adding a thin source wrapper target (following the pattern used by OneSignal-XCFramework) gives the build system the indirection it needs to correctly traverse the dependency graph and embed the xcframework. The product name (PowerSyncSQLiteCore) is unchanged — this is a non-breaking change for consumers. Ref: powersync-ja/powersync-kotlin#339 Ref: tuist/tuist#10296
There was a problem hiding this comment.
Pull request overview
Adds a thin source “wrapper” target so tools like Tuist correctly embed the powersync-sqlite-core.xcframework (dynamic framework) into app bundles, avoiding @rpath runtime load crashes.
Changes:
- Introduces a new source target
PowerSyncSQLiteCoreWrapperwith dummy.m/.hfiles. - Updates the
PowerSyncSQLiteCorelibrary product to vend the wrapper target (which depends on the binary target).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
Package.swift |
Adds the wrapper target and switches the library product to point at it. |
Sources/PowerSyncSQLiteCoreWrapper/dummy.m |
Dummy implementation file to make the wrapper a valid source target. |
Sources/PowerSyncSQLiteCoreWrapper/include/dummy.h |
Dummy public header to satisfy SwiftPM’s Clang target structure. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| .library( | ||
| name: packageName, | ||
| targets: [packageName] | ||
| targets: ["\(packageName)Wrapper"] | ||
| ), |
There was a problem hiding this comment.
The library product now exposes only the PowerSyncSQLiteCoreWrapper target. This changes the set of modules clients can import: import PowerSyncSQLiteCore will no longer be satisfied by this product (only PowerSyncSQLiteCoreWrapper is exported), which is a breaking change for any consumers that import the module directly. Consider restructuring so the exported module name remains PowerSyncSQLiteCore (e.g., make the wrapper target the one named PowerSyncSQLiteCore and rename the binary target, with the wrapper re-exporting/forwarding as needed), or otherwise ensure clients can still depend on the product and import the same module as before.
Problem
powersync-sqlite-core.xcframeworkis a dynamic library. When build tools like Tuist resolve SPM packages into Xcode projects, a library product that directly wraps abinaryTargetgets linked but not embedded in the app bundle. This causes a runtime crash:Xcode's Run action masks this by injecting
DYLD_FRAMEWORK_PATH, butsimctl launch, release builds, and App Store builds crash.Minimal reproduction: https://github.com/thomasflad/tuist-xcframework-embed-repro
Root cause
Tuist cannot correctly embed a dynamic xcframework when the dependency graph is
product → binaryTargetdirectly. It needs the indirection of a source wrapper target to traverse the graph and add the xcframework to the "Embed Frameworks" build phase.Tracked in:
Solution
Add a thin source wrapper target following the pattern used by OneSignal-XCFramework:
The wrapper contains only a dummy
.mand.hfile — no actual code. It exists purely to give the build system the dependency indirection it needs.Impact
PowerSyncSQLiteCoreis unchanged.package(url:)or.external(name: "PowerSyncSQLiteCore")continue working without changes