Swift Package Manager and Linux "availability checks"


#1

Hello,

I'm currently working with a fellow githuber on having GRDB.swift, a Swift library around SQLite, run on Linux: https://github.com/groue/GRDB.swift/pull/205

To this end, there is a system package https://github.com/groue/CSQLite.git whose Package.swift specifies that sqlite should be provided by apt on Linux:

  import PackageDescription
  
  let package = Package(
      name: "CSQLite",
      providers: [
          .Apt("libsqlite3-dev")
      ]
  )

So far, so good: this works almost perfectly. There is an important caveat, though :

SQLite features depend on its version. For example, the version of sqlite that ships in iOS has evolved from 3.7.13 to 3.14.0 since iOS 8. The Darwin version of GRDB uses Swift availability checks in order to hide sqlite APIs that are not available on a specific system version.

Now enters Linux. The Apt provider does not tell which version of sqlite is used. On the Ubuntu operating system, sqlite belongs to the "core system libraries": it is uneasy to install a custom version of sqlite. We thus generally have a GRDB Swift package that loads an *unknow* version of sqlite.

How can GRDB adapt? It could give up on static checks, and use runtime checks - assuming we avoid linker errors.

But can you help us figuring out a way to use static checks? I wish the Swift code would look similar to:

  #if os(Linux)
    #if FEATURE_AVAILABLE
      func f() { ... }
    #endif
  #else
    // Assume Darwin
    @available(iOS 9.0, OSX 10.11, watchOS 3.0, *)
    func f() { ... }
  #endif

I've tried to put #define macros in the CSQLite C header, but thoses macro are not converted into usable Swift compilation conditions when this header is loaded into Swift. A rookie's mistake, of course:

  #include <sqlite3.h>
  #define FEATURE_AVAILABLE ...

One can give `swift build` some options. But then what happens when GRDB is used as a dependency of another package (it's a library, after all)?

Is it possible to have GRDB *automatically and statically* adapt to the SQLite version? What would you recommend?

Thanks in advance,
Gwendal Roué


#2

(Crossposted to swift-users@swift.org)

Hello,

I'm currently working with a fellow githuber on having GRDB.swift, a Swift library around SQLite, run on Linux: https://github.com/groue/GRDB.swift/pull/205

To this end, there is a system package https://github.com/groue/CSQLite.git whose Package.swift specifies that sqlite should be provided by apt on Linux:

  import PackageDescription
  
  let package = Package(
      name: "CSQLite",
      providers: [
          .Apt("libsqlite3-dev")
      ]
  )

So far, so good: this works almost perfectly. There is an important caveat, though :

SQLite features depend on its version. For example, the version of sqlite that ships in iOS has evolved from 3.7.13 to 3.14.0 since iOS 8. The Darwin version of GRDB uses Swift availability checks in order to hide sqlite APIs that are not available on a specific system version.

Now enters Linux. The Apt provider does not tell which version of sqlite is used. On the Ubuntu operating system, sqlite belongs to the "core system libraries": it is uneasy to install a custom version of sqlite. We thus generally have a GRDB Swift package that loads an *unknow* version of sqlite.

How can GRDB adapt? It could give up on static checks, and use runtime checks - assuming we avoid linker errors.

But can you help us figuring out a way to use static checks? I wish the Swift code would look similar to:

  #if os(Linux)
    #if FEATURE_AVAILABLE
      func f() { ... }
    #endif
  #else
    // Assume Darwin
    @available(iOS 9.0, OSX 10.11, watchOS 3.0, *)
    func f() { ... }
  #endif

I've tried to put #define macros in the CSQLite C header, but thoses macro are not converted into usable Swift compilation conditions when this header is loaded into Swift. A rookie's mistake, of course:

  #include <sqlite3.h>
  #define FEATURE_AVAILABLE ...

One can give `swift build` some options. But then what happens when GRDB is used as a dependency of another package (it's a library, after all)?

Is it possible to have GRDB *automatically and statically* adapt to the SQLite version? What would you recommend?

Thanks in advance,
Gwendal Roué