Skip to content

Add source wrapper target for Tuist xcframework embedding#2

Open
thomasflad wants to merge 1 commit intopowersync-ja:mainfrom
thomasflad:add-source-wrapper-for-tuist-embedding
Open

Add source wrapper target for Tuist xcframework embedding#2
thomasflad wants to merge 1 commit intopowersync-ja:mainfrom
thomasflad:add-source-wrapper-for-tuist-embedding

Conversation

@thomasflad
Copy link
Copy Markdown

Problem

powersync-sqlite-core.xcframework is a dynamic library. When build tools like Tuist resolve SPM packages into Xcode projects, a library product that directly wraps a binaryTarget gets linked but not embedded in the app bundle. This causes a runtime crash:

Library not loaded: @rpath/powersync-sqlite-core.framework/powersync-sqlite-core

Xcode's Run action masks this by injecting DYLD_FRAMEWORK_PATH, but simctl 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 → binaryTarget directly. 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:

product "PowerSyncSQLiteCore"
  └─ target "PowerSyncSQLiteCoreWrapper" (source, dummy .m/.h)
       └─ target "PowerSyncSQLiteCore" (binaryTarget, xcframework)

The wrapper contains only a dummy .m and .h file — no actual code. It exists purely to give the build system the dependency indirection it needs.

Impact

  • Non-breaking — the product name PowerSyncSQLiteCore is unchanged
  • Consumers using .package(url:) or .external(name: "PowerSyncSQLiteCore") continue working without changes
  • Fixes xcframework embedding for Tuist projects

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
Copilot AI review requested due to automatic review settings April 16, 2026 13:22
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 PowerSyncSQLiteCoreWrapper with dummy .m/.h files.
  • Updates the PowerSyncSQLiteCore library 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.

Comment thread Package.swift
Comment on lines 12 to 15
.library(
name: packageName,
targets: [packageName]
targets: ["\(packageName)Wrapper"]
),
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
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.

2 participants