Two dependencies linking the same dynamic library

I want to use two crates dependencies, however there is a version (or linker?) conflict. One crate depends on the crate rusqlite and the other on the crate sqlite3-src. The issue seems to be that both rusqlite and sqlite3-src directly link to the sqlite system library without a common dependency linking to it, so cargo doesn't allow linking either as there may be a conflict.

I would assume this is not a very uncommon situation, and I'm wondering whether there is any possibility for me to solve this without changing any of the two dependencies in a major way?

E.g. by telling cargo to build sqlite itself instead of linking to the dynamic library or "sandbox" dependencies or whatever...

It is always very helpful to attach the error message :slight_smile:

Preferably in a details block
[details="Error message"]
Oh no!
[/details]

Rusqlite depends on sqlite3-sys, while some other crate likely depends on libsqlite3-sys. This is going to lead to conflicts. The whole split between foo and foo-sys across the ecosystem exists to reduce the occurence of these conflicts by allowing multiple high level bindings to depend on the same -sys crate for linking. It seems that for sqlite we have got two competing -sys crates.

I'm sorry I did not think of that! Here we go:

Error message
$ cargo build
    Updating crates.io index
error: failed to select a version for `libsqlite3-sys`.
    ... required by package `rusqlite v0.28.0`
    ... which satisfies dependency `rusqlite = "^0.28"` of package `deadpool-sqlite v0.5.0`
    ... which satisfies dependency `deadpool-sqlite = "^0.5.0"` of package `matrix-sdk-sqlite v0.1.0 (https://github.com/matrix-org/matrix-rust-sdk.git#784171e2)`
    ... which satisfies git dependency `matrix-sdk-sqlite` (locked to 0.1.0) of package `matrix-sdk v0.6.2 (https://github.com/matrix-org/matrix-rust-sdk.git#784171e2)`
    ... which satisfies git dependency `matrix-sdk` (locked to 0.6.2) of package `ubisync v0.1.0 (/home/a-0/git/ubisync)`
versions that meet the requirements `^0.25.0` are: 0.25.2, 0.25.1, 0.25.0

the package `libsqlite3-sys` links to the native library `sqlite3`, but it conflicts with a previous package which links to `sqlite3` as well:
package `sqlite3-src v0.5.1`
    ... which satisfies dependency `sqlite3-src = "^0.5.1"` of package `cozo v0.7.5`
    ... which satisfies dependency `cozo = "^0.7.5"` of package `ubisync v0.1.0 (/home/a-0/git/ubisync)`
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the links ='libsqlite3-sys' value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.

failed to select a version for `libsqlite3-sys` which could resolve this conflict
1 Like

I had a look at crates.io, hoping that one of these options is far more popular so I could ask the maintainers of the crate depending on the other to switch. Turns out that the conflict is between the sqlite and rusqlite crates - which are both vastly popular!

I guess the lang (or cargo, more precisely) needs to have a solution for this then, because the whole crates universe splits in halves otherwise :confused:

More accurately, the conflict is between libsqlite3-sys and sqlite3-sys. Usually it's not a problem to have different crates for the same purpose but for simple bindings like these there really should just be the one unless there's some good reason. libsqlite3-sys is older and more widely used*, in my opinion the solution is to just use that.

The reason why sqlite doesn't use it seems to just be that it would disturb the ecosystem: Replace sqlite3-sys with libsqlite3-sys by busyboredom · Pull Request #66 · stainless-steel/sqlite · GitHub Looking at the PR, it seems like it's just a two line change, so if I was in your situation and the PR worked just like that I would fork sqlite and use Cargo's patch feature.

*Looking at the download numbers and dependents, you can see sqlite3-sys is mainly used by sqlite (which is used by 50 other crates on crates.io) while libsqlite3-sys is used not just by rusqlite but by other very popular crates such as sqlx (used by over 400 other crates on crates.io), diesel (almost 300 crates), and over 50 other crates.

2 Likes

So, this kind of worked. I need to do without cozo's sqlite backend now, because that depends on sqlite3-src, but putting the following into my Cargo.toml did the trick:

matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", features = [ ] }
# Prevent cozo from depending on sqlite3-src, which conflicts with matrix-sdk's dependency on libsqlite3-sys
cozo = { version = "0.7.5", default_features = false, features = [ "storage-rocksdb", "requests", "graph-algo" ] }

# Rewrite sqlite's dependency on sqlite3-sys to libsqlite3-sys, which is compatible with matrix-sdk
[patch."https://github.com/stainless-steel/sqlite"]
sqlite = { git = "https://github.com/busyboredom/sqlite", branch = "libsqlite3-sys" }

Thanks for your guidance @Heliozoa ! I would still love to see this better integrated into cargo, but I'm not enough of a rustacean to come up with a good solution. This works for now, as long as I update the overwritten sqlite dependency often enough :slight_smile:

2 Likes

Ah, that's right. I think you could possibly fork sqlite3-src and in the fork remove the build.rs file and [build-dependencies] from Cargo.toml, then add libsqlite3-sys as a dependency, change the bundled feature to bundled = ["libsqlite3-sys/bundled"] (so that the feature is appropriately "forwarded") and rewrite lib.rs to be

pub use libsqlite3_sys::*;

The idea is that the fork would make sqlite3-src a thin wrapper around libsqlite3-sys, and so any crate depending on it would really be depending on libsqlite3-sys.

I'll note that down for the glorious future where I may be interested in sqlite support :slight_smile: Thanks so much for your support, rust compiler+linking is pretty daunting at first...

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.