Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prevent Cargo from merging the same dependency with different features?

After figuring out cargo build of the same code: spurious compile time errors?, I want to know how to prevent such a problem:

$ cargo new feature_merge
$ cargo add nmea
$ cargo check > /dev/null 2>&1 && echo "success"
success
$ cargo add cexpr
$ cargo check > /dev/null 2>&1 || echo "failed"
failed
$ cargo rm cexpr && cargo check > /dev/null 2>&1 && echo "success"
success

I remove/add the dependency without any code modification and this influences the build result.

The source of problem, as I described, is that cexpr depends on nom like this:

nom = {version = "^3", features = ["verbose-errors"] }

while nmea describes the dependency like this:

nom = "3.1.0"

With only nmea as a dependency, Cargo builds nom with one set of features, while Cargo builds cexpr and nmea against nom with another set of features.

I want a way to prevent such wrong usage of the nmea crate which I maintain.

I'd like a compile time error like "`nom` compiled with wrong features", or force Cargo to build two variants of nom.

I tried such thing in nmea/Cargo.toml:

nom = { version = "3.1.0", default-features = false }

This changed nothing; there's still a compile time error when cexpr and nmea are combined.

like image 525
fghj Avatar asked Jul 24 '17 18:07

fghj


1 Answers

It is known issue, related links:

cargo issue 1

cargo issue 2

cargo rfc

the short summary:

crate's features are supposed to be additive

In other words each feature in crate should only append functionality, not change API. Unfortunately there no good documentation descrbing this problem, and no automation for testing of this invariant at least at this moment. This particular issue is related to nom bug (github issue), quote from there:

The problem here is that, when using "simple errors", the type nom::simple_errors::Err<E> is simply a type alias of nom::ErrorKind<E>, while with "verbose errors" the type nom::verbose_errors::Err<E> is a dedicated enum, so the "with-feature" and "without-feature" interfaces are incompatible.

like image 126
fghj Avatar answered Oct 24 '22 03:10

fghj