Problem
In Cargo, currently the crate name you use in [dependencies] marks where the crate is supposed to come from; it matches the package.name key in the dependency's Cargo.toml.
The crate name you use in extern crate foo or foo:: has to match the actual on-disk compiled artifact name. This is _not_ the package name, but is instead the lib.name key in the dependency's Cargo.toml.
If these don't match, you can have unexpected behavior (being unable to use crates by the name you'd expect them to use) as well as nonlocal bugs where one transitive dependency can break another by choosing the same [lib]
Steps
package keys but the same lib keymultiple rlib candidates error:error[E0465]: multiple rlib candidates for `manish_test_crate_clashes` found
--> src/main.rs:1:1
|
1 | extern crate manish_test_crate_clashes;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: candidate #1: /home/manishearth/sand/bar/crates/manish_test/target/debug/deps/libmanish_test_crate_clashes-6647f0eb7f7797e9.rlib
--> src/main.rs:1:1
|
1 | extern crate manish_test_crate_clashes;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2: /home/manishearth/sand/bar/crates/manish_test/target/debug/deps/libmanish_test_crate_clashes-a2862f19598a10de.rlib
--> src/main.rs:1:1
|
1 | extern crate manish_test_crate_clashes;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Possible Solution(s)
I'm not actually sure if this _is_ a bug: Having this ability doesn't seem _completely_ useless. And for unpublished git/path packages the lib name does matter.
It may be worth forbidding crates with a lib.name that doesn't match package.name from being published, after checking crates.io for any offenders. https://github.com/messense/rustc-test is one (and is how I discovered this bug, we've been confused about a libtest thing for a while and it seems like this crate is the culprit)
Notes
Output of cargo version: cargo 1.34.0-nightly (5c6aa46e6 2019-02-22)
Overall I've always found the lib.name key to be super confusing because it adds to the dashes-vs-underscore ambiguity, which sometimes crops up with crates which use dashes in package.name and underscores in lib.name and while that kind of works it doesn't _always_ work because now you need to use lib.name for specifying patches.
I think it is fairly common, I found about 569 crates on crates.io which do this. An additional 476 crates only differ in - vs _.
It might be worthwhile to peruse that list to get a better understanding why some people do this. I fear some of them are done because of crates.io namespace collisions.
The crate name you use in
extern crate fooorfoo::has to match the actual on-disk compiled artifact name.
This isn't always true. Things such as crate renaming can use different names. Crate renaming should also provide a workaround to avoid the multiple rlib candidate error. I'm wondering if there would be a way to provide a better error message?
I use this infrequently but to what I consider desirable effect.
In https://github.com/dtolnay/syn/commit/606e794df4d6b76eecd36538cd4bba71f952e001 I was able to publish some early iteration on a major version of Syn under a different name to experiment with it in the ecosystem, without requiring any Rust code change in my example code or in downstream imports.
In proc-macro-workshop's test runner: Cargo.toml and test code.
This isn't always true. Things such as crate renaming can use different names
Right, but that kinda makes it _worse_, since the impression given off by this feature is that "the package name is the crate name, unless you explicitly rename it", which isn't true. The lib name is the crate name, unless you explicitly rename it.
was able to publish some early iteration on a major version of Syn under a different name to experiment with it in the ecosystem,
Hmm, this seems to be a valid use case.
We should at least warn in cases where it's more than just underscores, though.
I think it is fairly common, I found about 569 crates on crates.io which do this. An additional 476 crates only differ in
-vs_.
@ehuss do you happen to still have the code that generated this list...? asking for a friend
I don't remember for sure, but I have the source for all the crates.io crates extracted locally. I then have a small rust script which uses walkdir to find all Cargo.toml files, then uses toml to parse them, and then it is a simple matter of comparing the package name to the lib name and seeing if they are different.
Here, I'll just recreate it real quick:
script: https://gist.github.com/ehuss/b65122f9bfd835da1c612aa71b1efd28
output: https://gist.github.com/ehuss/831d311fb3985483d16600a36fa32a5f
Thanks a ton!
I wonder if we should try and fix this sooner rather than later to avoid more of it happening. At least with a warning.
It might also help to just improve diagnostics around this situation.
Just wanted to chime in that the "package.name != lib.name" is useful when you're dealing in both rlib and cdylib; if my package is called libexample and the crate_types include "cdylib" then the resulting shared object has the name liblibexample.so. To normalize it back you have to set lib.name to example, e.g.
master # md@PC:~/code/md/libexample$ cat Cargo.toml
[package]
name = "libexample"
version = "0.1.0"
authors = ["Max Dymond"]
edition = "2018"
publish = false
[lib]
name = "example"
crate_type = ["cdylib", "lib"]
master # md@PC:~/code/md/libexample$ cargo build
Compiling libexample v0.1.0 (/home/md/code/md/libexample)
Finished dev [unoptimized + debuginfo] target(s) in 0.75s
master # md@PC:~/code/md/libexample$ ls target/debug/
build deps examples incremental libexample.d libexample.rlib libexample.so
Most helpful comment
I use this infrequently but to what I consider desirable effect.
In https://github.com/dtolnay/syn/commit/606e794df4d6b76eecd36538cd4bba71f952e001 I was able to publish some early iteration on a major version of Syn under a different name to experiment with it in the ecosystem, without requiring any Rust code change in my example code or in downstream imports.
In proc-macro-workshop's test runner: Cargo.toml and test code.