Trying to get painless cross-platform sqlite

When I started using Rust, one of the major selling points I tried to drive home to people was that there would no longer have to be a bunch of .in files that the build system would use to build itself - differently - on different platforms.

Well, it didn't take long until I realized that this wasn't the entirely true. The point is still somewhat valid, because it's far less of an issue (we only need one currently). Anyway, this has caused some friction internally among people who aren't used to complicated build systems, so I thought I'd see if there are any good solutions to it.

Basically the problem can be summarized as:

  • we use rusqlite (and like it, thus want to keep using it)
  • on unixy platforms we want to use the shared library as installed by the platform's native package managing system (this is the default behavior, so everything is good)
  • on windows we want to dynamically link to the CRT, but statically link everything else (basically we want to avoid non-system DLL's).
  • features = ["bundled"] allows rusqlite to build sqlite from source and use that version. This is not perfect, but acceptable, for Windows builds -- but not for non-Windows platforms.

This is where I first noticed that the features in Cargo.toml have some slightly surprising semantics; they don't respect the platform-specific sections. (It was a while back that I did this, but I believe the feature being used is actually the union of all feature sections).

Anyway, it was at that point that I simply went with a Cargo.toml.in, and preprocess those files before builds so each platform got their appropriate features. For me, this is still a major win since its orders of magnitude less complicated that most build systems that need to work on both Unixy platforms and Windows, but others aren't as happy with it, and there's a wish to "just use plain Cargo.toml" files, which I obviously agree with would be optimal.

From time to time I have tried to use vcpkg. It seems promising, but I always end up spending way too long trying to bend it to my will, so I just go with custom build scripts for the libraries we need. (Again, this is acceptable to me, but not to those who aren't accustomed something more complicated than pressing F5 in Visual Studio).

So what I'm basically wondering is if there's some way to eliminate my Cargo.toml.in hack, but get static builds of sqlite for rusqlite on Windows (but with dynamic CRT, obviously), but regular dynamic builds on all other platforms?

The reason I mention vcpkg is because I read the vcpkg crate docs, which states:

The default 64-bit configuration is x64-windows-static-md which is a community supported configuration that is a good match for Rust - dynamically linking to the C runtime, and statically linking to the packages in vcpkg.

This sounds perfect -- but how do I use it? I know I build using .\vcpkg.exe install sqlite:x64-windows-static-md, but how do I make sure that the rusqlite picks this build?

Any other suggestions to get to the desired end goal?

Also, how do people handle this features quirk? When I started to think about it, I realized that there's bound to be plenty of situations where one want to build with different default features on different platforms. Is this something one can accomplish with build.rs?

1 Like

Cargo lacks support for platform-specific features. The implementation of features is being rewritten, so it may be fixed in the future.

Currently I solve that by adding my own feature to my project that enables static builds

[features]
static = ["rusqlite/bundled"]

and build on Windows with:

cargo build --features=static

It's not exactly pure cargo build on all platforms, but at least it doesn't require any .in files (eww!)

3 Likes

There is already a dedicated feature bundled-windows to use bundled sqlite only on windows platform.
See https://github.com/rusqlite/rusqlite/pull/537 and https://github.com/rusqlite/rusqlite/pull/682.

1 Like