Skip to content

Declare StructuredQueriesCore so SQLiteData links as a dynamic framework - #514

Closed
jonphillips wants to merge 1 commit into
pointfreeco:mainfrom
jonphillips:declare-structured-queries-core
Closed

jonphillips wants to merge 1 commit into
pointfreeco:mainfrom
jonphillips:declare-structured-queries-core

Conversation

@jonphillips

Copy link
Copy Markdown

Summary

SQLiteData's sources reference StructuredQueriesCore symbols directly, but the target declares only StructuredQueriesSQLite. That is fine for swift build / swift test, and it breaks as soon as the product is built as a dynamic framework — which Xcode does for every package product in the graph the moment a test bundle enters the build.

This revives #441, which was closed on the understanding that #467 had resolved it. #467 is in 1.6.6; we are on 1.6.6 (and reproduce identically against 1.8.1), and the failure is unchanged. I suspect that reporter's configuration differed — the manifest omission itself is still present on main today.

Answering the question from #441

Because StructuredQueriesSQLite re-exports those two libraries, so it should be sufficient to just depend on the one.

That holds for the compiler and not for the linker. @_exported import is a compile-time re-export: it makes the names visible to the type checker. It is not -reexport_framework, so StructuredQueriesSQLite.framework does not vend StructuredQueriesCore's symbols on SQLiteData.framework's behalf. When every product is a separate dylib, SQLiteData.framework's link line contains only its declared dependencies, and the direct references go unresolved.

A static build hides it completely, because every transitive archive is on the same link line anyway. That is why swift build, swift test, and a plain xcodebuild build are all green while build-for-testing fails — and, I suspect, why this has stayed latent.

Reproduction

No complex project needed. The trigger is simply a test bundle in an Xcode graph:

  1. An Xcode project with an app target that depends on a local SwiftPM package.
  2. That package depends on sqlite-data and defines any @Table type.
  3. Add a unit-test bundle target to the project.
  4. xcodebuild build-for-testing -scheme <App> -destination 'platform=iOS Simulator,...'

Step 3 is the whole trick: adding the test bundle flips every package product from static to dynamic. Without it the same project builds clean.

The failure

Undefined symbols for architecture arm64:
  "protocol conformance descriptor for Foundation.Data : StructuredQueriesCore.QueryBindable in StructuredQueriesCore",
      referenced from: ... in SQLiteData.o
  "(extension in StructuredQueriesCore):Foundation.Data.queryBinding.getter : StructuredQueriesCore.QueryBinding",
      referenced from: SQLiteData._SystemFieldsRepresentation.queryBinding.getter ... in SQLiteData.o
                       SQLiteData._AllFieldsRepresentation.queryBinding.getter ... in SQLiteData.o
  "protocol conformance descriptor for Foundation.UUID : StructuredQueriesCore.QueryRepresentable in StructuredQueriesCore", ...
ld: symbol(s) not found for architecture arm64
Ld .../PackageFrameworks/SQLiteData.framework/SQLiteData normal (in target 'SQLiteDatadynamic-product' from project 'sqlite-data')

Note the referencing objects are SQLiteData.o itself — _SystemFieldsRepresentation, _AllFieldsRepresentation, and the CKSyncEngine.PendingRecordZoneChange extension — so this is not a consumer reaching through SQLiteData for something; it is SQLiteData's own code needing a library it does not declare.

Verification

Applying this change to a local checkout makes SQLiteData.framework link, and build-for-testing then completes.

Environment: Xcode 27.0 beta / iOS 27 simulator SDK, sqlite-data 1.6.6 and 1.8.1, swift-structured-queries 0.31.3 and 0.34.0. Both version pairs fail identically and are fixed identically.

SQLiteData's sources reference StructuredQueriesCore symbols directly, but the
target declares only StructuredQueriesSQLite. That is fine for a static build,
where every transitive archive is on the same link line anyway, and it breaks
once the product is built as a dynamic framework: `@_exported import` is a
compile-time re-export rather than `-reexport_framework`, so
StructuredQueriesSQLite.framework does not vend StructuredQueriesCore's symbols
on SQLiteData.framework's behalf, and the direct references go unresolved.

Xcode builds every package product as a dynamic framework as soon as a test
bundle enters the graph, so `xcodebuild build-for-testing` fails while
`swift build`, `swift test` and a plain `xcodebuild build` all pass.
@jonphillips

Copy link
Copy Markdown
Author

P.S. Love what you guys do.

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