Hello, Jordan, thanks
Your simplified version isn't quite correct, because SQLITE_VERSION_NUMBER is (hypothetically) resolved at compile time but @available can be paired with #available. That's a big difference for all of them except f2.
I'm sorry, I do not understand. The "simplified version" is pseudo-C, which can access C macros, and thus avoid code duplication.
To focus on a single example, can the following code be simplified in order to avoid code duplication?
#if CUSTOM_SQLITE_BUILD // Set in OTHER_SWIFT_FLAGS
func f1() { 🐵 }
#else
@available(...)
func f1() { 🐵 }
#endif
The problem with depending on C macros is it means you can't ship your library as a self-contained unit. That's not supported today, sure, but we don't want to add features to the language that make it harder. You really are choosing whether to build with a bundled SQLite—with a particular configuration—or with the system one, and unlike search paths or imports this is a choice that affects clients of your library as well.
This is true. GRDB ships with three flavors:
- GRDB, available on CocoaPods and SPM, links against the system SQLite
- GRDBCipher, available on CocoaPods, links against SQLCipher
- GRDBCustomSQLite, available through manual Xcode integration, links against a customized SQLite build
Those are all three independent targets and frameworks, which share the same code, though. Their behaviors and public apis depend on OTHER_SWIFT_FLAGS and availability checks.
In particular, GRDBCustomSQLite doesn't depend on C macros (it can't): instead, a remarquable bridge named swiftlyfalling/SQLiteLib allows the host library (GRDB) and even the application to know about the enabled SQLite options. This is how the Swift apis for FTS5 (the latest full-text search engine) are enabled today:
#if SQLITE_ENABLE_FTS5 // Set in OTHER_SWIFT_FLAGS by swiftlyfalling/SQLiteLib
...
#endif
It's hard to imagine the amount of energy which is spent in order to achieve our goals, isn't it? 
Now FTS5 is enabled by default in macOS 10.13. It would be nice to expose it from the regular GRDB framework, when available. But since C macros are not exposed, the code has to perform availability checks:
#if CUSTOM_SQLITE_BUILD
// Custom SQLite
#if SQLITE_ENABLE_FTS5 // Set in OTHER_SWIFT_FLAGS by swiftlyfalling/SQLiteLib
/* duplicated FTS5 code */
#endif
#else
// Stock SQLite
@available(...)
/* duplicated FTS5 code */
#endif
This is what I'm somewhat reluctant to do now, because of the huge amount of duplicated code. Meanwhile, FTS5 is still not activated for the library users.
That said, there are still some interesting things that could be done:
- Allow if around attributes (something that's been asked for for plenty of other reasons).
Yes, this would help a lot:
#if !CUSTOM_SQLITE_BUILD || SQLITE_ENABLE_FTS5
#if !CUSTOM_SQLITE_BUILD
@available(...)
#endif
/* non-duplicated FTS5 code */
#endif
- Some way to get configuration options en masse, rather than having to put each one on the command line. Maybe even from reading C headers (but done more explicitly than with import). I don't know what this looks like.
Me neither. But some configuration flags depend the operating system: at 1st sight, allowing if around @available looks more promising.