Different ways of specifying dependencies( path vs version ) make different compilations

lens-rs_test and lens-rs are in the same workspace. The former depends on the latter:

In lens-rs_test's Cargo.toml:

lens-rs = { path = "../lens-rs" }
structx = { version = "0.1", optional = true }

The structx crate's build.rs will generate bindings.rs composed of some struct definitions which will #[derive( lens_rs::Lens )].

If tested lens-rs_test with cargo test test_structx --all-features, the bindings.rs will be generated as expected( containing #[derive( lens_rs::Lens )] ), but deriving of lens_rs::Lens will not happen.

All will be fine if change the dependency of lens-rs in lens-rs_test's Cargo.toml:

lens-rs = "0.3"

Is it a bug of cargo?

2 Likes

The different compilations is not caused by the difference of lens-rs in github an in crates.io. I have downloaded lens-rs.0.3.1 from crates.io and replaced the local repository's lens-rs directory. The same result: path failed and version passed.

While your project uses lens-rs via a path dependency, structx still uses it via crates.io. So your project includes two different libraries named lens-rs. The structx bindings implement traits from one of these libraries, while your code uses traits from the other.

To fix this, you can use a patch override to make structx use your local copy of lens-rs. Add the following to the Cargo.toml file at the top level of your workspace:

[patch.crates-io]
lens-rs = { path = "lens-rs" }

[Note: This type of question might be more appropriate for the users forum.]

4 Likes

Thanks for your explanations! I didn't notice that two lens-rs existed.

However, I think it is not worth patching structx to use the local copy of lens-rs just for lens-rs_test working with local copy of lens-rs. According to the cargo book:

It is convenient not to change Cargo.toml for switching development/publishing. Patching structx's workspace brings this inconvenience back again. Unfortunately, structx and lens-rs belongs to different repos/workspaces.

You don't need to make any changes to any structx files. Inserting a [patch] section in the lens-rs workspace's Cargo.toml will affect everything that uses lens-rs when you run Cargo commands within that workspace.

You don't need to make any changes for development versus publication, since the [patch] section there is used only when building within that repo. It won't affect users of the published crates.

Perfect. Thanks for your detailed answer!

To scan for this, you could install cargo-tree with cargo install cargo-tree. When used in a directory that is a rust crate, it will display all dependencies, both direct and transitive, as a tree rooted in the current crate.

The cargo tree command is now built-in, by the way.

3 Likes

Thanks. In fact I knew this tool, but didn't realize it's helpful to analyze my problem.

(I googled some tool for developing a crate supporting reverse dependencies. Firstly found cargo-tree, but finally cargo_metadata was chosen.)