-
-
Couldn't load subscription status.
- Fork 795
SQLCipher (Official) Swift Package Manager Integration #1827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Conversation
… package trait is enabled - Package.swift -- Updates swift-tools-version to 6.1 to support traits -- Adds https://github.com/sqlcipher/SQLCipher.swift dependency -- Adds SQLCipher trait -- Adds SQLCipher dependency to GRDB target when SQLCipher trait is enabled -- Adds SQLCipherConfig library target to expose SQLCipher_config.h functions to swift with pass through to C variadic functions -- Adds SQLCipherConfig library depdency to GRDB target when SQLCipher trait is enabled -- Adds SQLCIPHER_HAS_CODEC swiftSettings/cSettings to GRDB target when SQLCipher trait is enabled -- Adds SQLCIPHER swiftSettings to GRDB target when SQLCipher trait is enabled -- Adds GRDBCIPHER_USE_ENCRYPTION to GRDBTests target when SQLCipher trait is enabled - Adjusts imports to check `#if SQLCIPHER` before `#if SWIFT_PACKAGE` - Adds Database+SQLCipher extension with SQLCipher operations, enabled by `#if SQLITE_HAS_CODEC` - Adds test_SPM_SQLCipher Makefile task and adds it as a dependent task of smokeTest Resolves groue#1772
… enabled (SQLCIPHER swiftSetting is set).
…bled - Removes SQLCipher related methods from Database as they are now moved to Database+SQLCipher - Adds SQLITE_DISABLE_SNAPSHOT swiftSetting to Package.swift when SQLCipher trait is enabled
…to test installing GRDB with SQLCipher trait - Adds test_install_SPM_SQLCipher Makefile task called as dependent task of test_install_SPM - Adjusts README.md SQLCipher example AppDependencies Package.swift to match GRDB platform versions
|
🥳 Thank you @R4N! I'm very happy we are converging. I'll review this great PR shortly! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm so very glad. Thank you @R4N, for your time, your work, and you very good ideas and improvements.
I have a few suggested changes and questions, but honestly we're very close to a successful merge :-)
- Removes exposing SQLCipherConfig shim package publicly in Package.swift - Calls dropAllDatabaseObjects from Database.erase() method when `#if SQLITE_HAS_CODEC` (SQLCipher enabled) - Adds `--traits SQLCipher` to swift build commands in test_SPM_SQLCipher Makefile task - Fixes formatting of XCODEBUILD commands in test_install_SPM_SQLCipher Makefile task - Removes setting SQLCIPHER swiftSetting in favor of using SQLCipher trait directly in import statements - Removes unneeded `#if SQLITE_VERSION_NUMBER >= 3029000` from SQLCipherConfig shim - Adjusts SQLCipher Information Accessors example code to use try variants in README.md - Adds details/summary to cipher_logging Example output in README.md - Adds cipherVersion display to sqlcipher SPM install test project - Removes references to Database+SQLCipher from GRDB.xcodeproj (only used for SPM) - Removes duplicate reference to AppDependencies in sqlcipher.xcodeproj (SQLCipher SPM example project)
…et/sqlcipher in README.md SQLCipher encryption section
…tion This is necessary for inheriting the SQLCipher passphrase. Also, update DatabaseConfigurationTests.testPrepareDatabase() so that it accurately counts the number of prepareDatabase invocations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! @R4N this is a great pull request :-)
I did not take the time to answer to this paragraph yet! Thank you very much! @R4N and @sjlombardo, you both have wonderfully found your way in this library. |
|
@R4N, Bad news. The test ( To reproduce, start from a clean stage (run You can also open This is a blocker 😬 [EDIT]
[EDIT] With Xcode 16.4, Indeed the demo app is linked against SQLCipher: // prints "4.11.0 community"
let version = try String.fetchOne(db, sql: "PRAGMA cipher_version")
print(version)In summary, we have two blockers:
The first blocker is not due to this pull request. It was already there in #1826, where package traits were introduced. My personal focus is now to restore this basic functionality. Everything else is secondary (this pull request, #1825 and #1708). Unfortunately, we just can not go faster than Xcode. |
|
This seems like another scenario where importing packages within the Xcode UI doesn't play nice with package traits (even the default ones specified) yet. When I try running that make task using Xcode 26.x it complained about the missing module The issue seems to be that the default trait is not be getting setup properly so the dependency condition for GRDBSQLite isn't being met and hence not added: I had previously tested using GRDB with some of my modifications to include the SQLCipher trait both with the trait enabled (using the wrapper package) and without the trait enabled (both with the wrapper package and directly import using the Xcode UI which both worked prior). This was prior to the addition of the default GRDBSQLite trait. One immediate option that I see is removing the i.e. Remove the And then always include With these adjustments in place, I was able to successfully run
This configuration will:
I hope that Xcode will improve their support for adding swift Packages with traits in the near future (I'm surprised it's not already in Xcode 26!) When I ran This is why both One approach would be to update the swift-tools-version to 6.2, although that would require Xcode 26+ for consumers whereas 6.1 requires Xcode 16.4. |
|
I don't see how linking SQLCipher (or even a custom build of SQLite) with GRDB can be done reliably considering how dyld and swift currently works. |
|
To follow up on my previous comment with additional investigation results: Testing Proper Linking Without The Default Trait
When including GRDB directly in the Xcode UI (unable to set any traits on it) When including GRDB in a wrapper package with no traits set and then consuming the wrapper package in Xcode UI When including GRDB in a wrapper package with SQLCipher trait set and the consuming the wrapper package in Xcode UI This output confirms:
Dependency scanning should omit the sqlite3 link when none of the source files depend on the module as outlined in this Apple documentation: https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies When the SQLCipher trait is enabled, there is no
|
@R4N I agree wholeheartedly with point 1 & 2. If SQLCipher is built as a dylib Framework and is linked as a framework called Also, if GRDB links SQLite/SQLCipher statically as a private dependency this should also work (assuming there was no inline functions). Things get very hairy if any of your app's dependencies link in sqlite statically but also export those functions. We're experiencing that issue with a 3rd party vendor lib. I was just concerned that the efforts here might be potentially creating a similar issue. |
|
I'm following this conversation closely, and I appreciate that we're balancing between optimism and fair concerns. @R4N I admit I do not understand how removing the default trait can guarantee that GRDB+SQLCipher will be linked against SQLCipher when the package verbatim does not disable the GRDBSQLite target (which brings in the system SQLite3) with an SPM condition. I do appreciate that you did test the actual output with Please excuse this pile of questions, I'm just exploring the so many reasons it could turn wrong, and I'm trying to evaluate the risks. If what we're working with is a fragile pile of half-finished beta tools, and if tipping a GRDB toe there is bound to burst in my face, I'll seriously consider postponing our work to some future year, when Apple tooling is ready. The fact that Xcode 16.3/16.4 is able to link the demo app with SQLCipher, despite SQLCipher being guarded by traits, proves that traits are not reliable, and that the mere presence of SQLCipher in Package.swift can break apps that do not even know about SQLCipher. I mean, this is seriously concerning, right? @orj GRDB does inline calls to The GRDB module does not export ( |
|
This is desperate. I'm considering closing all those (lovely) pull requests, and suggest to open AS MANY tickets as possible at https://feedbackassistant.apple.com, and to report their IDs here. Please do not expect an answer before a few days. I'm so bored with this lame shit. So much energy wasted, and so many people begging for a fucking working solution. FFS, we deserve better. And I totally refuse to be held responsible for the delay providing a satisfying solution. |
|
@R4N If you decide to create a fork of GRDB to experiment with this alternative structure, I would genuinely love to try it out in production right away. It would be a huge help for teams who need a working SQLCipher integration now, without waiting for Apple to ship reliable trait support. I’d be happy to contribute testing or feedback if you move forward with it. @groue If you decide to open a Feedback Assistant report or a public thread about this SwiftPM traits situation, I’ll gladly support it and upvote it. But at the same time, I have to admit — based on experience, I don’t have much faith in Apple fixing these things quickly. In 2023 I reported a serious bug related to interactive widgets in iOS 17. Apple ignored the report for months, and only partially fixed the issue a year later in iOS 18. So yeah… I’m not optimistic about waiting for Apple to solve this in the short term. That’s why I really hope we can find a practical workaround together as a community — something we can use today so development doesn’t get blocked for months by tooling instability. GRDB is an amazing library and I’d love to see it continue moving forward despite Apple’s roadblocks. |
|
@R4N The separate GRDBSQLCipher target you describe above would not bring SQLCipher to related libraries (GRDBQuery for SwiftUI helpers, GRDBSnapshotTesting for testing helpers, SQLiteData for iCloud sync, etc) unless those related libraries would make a similar dance. Your idea is clever and has benefits, but it is gaming SPM and playing against it. That's why I'm not thrilled. |
|
And I'm not mentioning that SPM downloads and builds unneeded dependencies, which means that users who do not need SQLCipher would have to download it, see SQLCipher built for no reason, see SQLCipher in their package list in Xcode, etc. So many bugs to report (some are reported already). With no real hope that they are fixed one day - in SPM, and in Xcode. I'm afraid we're back to the beginning: the only clean solution is a fork (as well as forks of related repositories). |
|
Another issue with the separate GRDBSQLCipher target is that it does not scale: Linux and Android versions need a distinct flavor of SQLCipher, which can be built from source (#1708). That would be another target, another dependency, and more SPM useless work (download, build, etc.) |
Thanks for your support, @mezhevikin. I agree that hoping for a fast response from Apple won't lead us anywhere. Until someone at Apple is able to tackle the many issues we are facing (both in will and in action), nothing will happen, and our complaints will just be received as useless whining from toxic people. I don't have anyone from Apple in my contacts, and anyway, I don't think they're organized to do what we need. I also read here and there signs of fossilization of SPM which do not make me optimistic. And waiting for 2, 3, ♾️ years is not quite ideal. One possible way forward could be:
|
|
Hello @R4N, @marcprux. I'd be happy to get your feedback on the previous message at some point. The general idea is that supporting SQLCipher is a team effort, with contributions from Zetetic for the official SQLCipher distribution, from the Swift Android Workgroup for the alternative SQLCipher distribution that builds on Linux and Android, and from your humble servant for the general integration of these new features in the existing GRDB landscape. It would be beneficial if we would all agree of some key points:
The first two points are not subject to debate. That's how GRDB is managed, by me. The third one is very disappointing, but I also do not think that it is open to debate. We tried, and saw the issues. The fourth point is more subjective, and I can imagine that some people would not care about those undesired SPM behaviors, or the presence of extra dependencies. I'm willing to stand by it, though. My quality ideals have well served the users of this library for many years, and are part of the reasons why you're here in this discussion today. So. That's how I'm currently describing our playground. If you think I am missing something, please tell! If I do not, I do not see any other solution than the one I outlined above. It's a solution that's imperfect in many ways for the GRDB/SQLCipher users, and that gives me a lot of extra work. Again, I may be missing something. In all cases, and because you all showed a lovely engagement in helping bringing GRDB to new places, I have to ask your opinion 🙏 |
I have been following these ongoing threads, but have been unable to engage much or offer any help due to time constraints. I share your dismay at the state of Swift package traits and Xcode and regret that it doesn't look like it will be a viable solution in the near future (maybe Swift 6.3 will improve things). Additionally I see how the inability to exclude the presence of a package dependency using traits also makes this an undesirable route, since I agree that vestigial dependencies have bad optics. Since you asked about alternative solutions, I was thinking more on my predecessor to #1708 and your proposal for a I don't even think we need the complexity of parameterizing the GRDB types with the protocol (like the suggestion for It might be worthwhile to take another look at #1701 and think more about how it could be made to work. IIRC, it was mostly working and had good performance, but some of the "specialty" SQLite structs like those supporting FTS5 made it tricky to abstract into a protocol. Obviously, it would be a big refactoring of GRDB, but I remember that I had a shim implementation that left global-looking functions Anyway, that's my 2 centimes. If you're interested in dusting off that PR and giving it another go, I'd be happy to help get it back into shape for testing and evaluation. I'd also like to hear from @R4N about whether such a solution might work for the SQLCipher team. |
Agreed, I was hopeful that traits would be better supported. Your thoughts are inline with the conclusions we've come to during our work to attempt to integrate via traits. Too many workarounds required to resolve bugs and no direct Xcode integration for trait selection (or using the default specified traits) are real blockers there. For number 4, we are definitely open to utilizing an official fork if that's the preferred path forward. We do have a couple of comments/questions related to the conclusions there for using a fork vs using separate products/targets:
This definitely occurs with the approach for using separate products/targets (in the core repo), but would have also occurred when using Package traits. When adding a Package, Swift Package Manager will download all defined dependencies (and transitive dependencies) to prioritze the complete availability of the dependency graph. Because of this, I would think this is the "acceptable" behavior. I could see it adding to some confusion for folks not utilizing SQLCipher though, it would be nice at some point if SPM optimized that behavior to de-prioritize downloading all dependencies and only download dependencies which are referenced in products/targets which are consumed by the consuming project.
I couldn't find any references which specify this behavior. My understanding was that the explicit dependencies drive what is built. So if in Xcode, you choose to add the standard GRDB product (when adding the GRDB Package), it will only build that (and not the SQLCipher product). Similar to what is described in this Apple documentation: https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies For the preferred path moving forwards, if we roll with an official GRDB fork to support Official SQLCipher, would we also re-use the repo for the Swift Android Workgroup's product/target? Or a separate fork? If we re-use the same repo, would we be back in a similar situation as we are currently where we'd need to use separate products/targets in the same forked repo since traits are still pretty broken? If we use a separate fork (for each SQLCipher flavor), it seems like a lot of maintanence for you. We are happy to proceed however you see fit (fork or standalone products/targets in the core repo), but just wanted to add our feedback on your comments and bring up that the benefits of a separate fork might not constitute the extra maintanence required. |
|
I'll address your feedback with more details soon @R4N 👍 Just a quick note on two points:
I understand. I also think that the negative consequences for GRDB users that I described are real. The tolerance to "acceptable"-with-quotes is, IMHO, one of the problems we have to deal with.
Various occurrences of this behavior can be found in the comments of this forum thread https://forums.swift.org/t/swift-test-tries-to-build-all-targets-instead-of-just-those-needed-for-testing/82803. I wholeheartedly relate to this quote:
|

Adds SQLCipher.swift Swift Package Manager integration when SQLCipher package trait is enabled
Changes
#if SQLITE_HAS_CODECResolves #1772
Pull Request Checklist
developmentbranch.make smokeTestterminal command runs without failure.Ongoing Support
The SQLCipher Team is committed to updating and supporting the official
SQLCipher.swiftSwift Package. We're happy to assist with any GitHub issues related to integration or troubleshooting usingGRDB.swiftwithSQLCipher.swiftpackage dependency. Please feel free to raise an issue in the Official SQLCipher.swift repo