Where can a dependency be specified if not in Cargo.toml? - rust

I'm looking at the ring crate. In its Dependencies tab I see there is a dependency to the web-sys crate. But in ring's Cargo.toml I don't see web-sys mentioned anywhere. So where does that dependency come from?

You're comparing apples to oranges. You're seeing the dependencies of version 0.16.20 and comparing that with the current Cargo.toml even when there are nearly two years of difference between them.
If you look at the repository at the 0.16.20 release, you'll see that Cargo.toml does have a web-sys dependency: https://github.com/briansmith/ring/tree/9cc0d45f4d8521f467bb3a621e74b1535e118188

Related

Is it possible to specify version for feature in dependency in Cargo.toml?

For example, I use barcoders crate:
barcoders = {version = "0.10.0", features = ["image",]}
Is it possible to specify which version of image this dependency should use?
Something like
barcoders = {version = "0.10.0", features = ["image=0.22.3",]}
Because it uses image crate version 0.18.0 and in my project I use latest 0.22.3.
Does it mean that there's only 2 ways to resolve that:
I downgrade version in my package
Barcoders dependency get updated
No, there is no way to specify the version for a dependency's (optional) dependency. This makes sense, as your dependency run their tests only against the version they specify in their Cargo.toml. In this case, as it appears everything you're doing uses open source, you could fork barcoders, update the dependency, run the test suite and if it passes, use your fork. It would also be polite to open an issue in that case.
If barcoders wasn't open-source, so you couldn't fork it, your best bet would be to switch to the version of image that barcoders uses. If your crate is a library, it may be annoying to expose a public interface that uses outdated libraries, but that's life. The "proper" solution to this problem is to wait until image has a 1.0 release, which is basically a forward compatibility promise, then barcoders can specify image = "^1" (i.e. >=1.0.0 <2.0.0). I mention this "solution" only because you appear to have commit privileges on barcoders, in fact you solved your own problem by updating the image dependency in barcoders.
As one of the comments points out, this version compatibility issue is less fragile that it at first seems. So long as types from different versions of some dependency crate don't cross api boundaries, your project can include any number of versions of that dependency simultaneously. Working with multiple versions of libraries took some work from the rust team on name mangling, which you can read about here
No, you can't, and shouldn't, and shouldn't worry.
Libraries were developed at a single point in time, used dependencies with a certain API. The dependency is likely to change some of that between major versions (changing the type a function returns, exposing different patterns, or whatever). This may make it unable to compile anymore. To really update something, you might need to change parts of the code that is using the dependency in the first place.
This is open source world, so you can do so and publish a pull request in the original crate to update. It might be appreciated, but don't underestimate the care that needs to be taken to not break other people's crates yourself when doing so.
Or make your own fork of the crate that updates it just for you.
But you are probably just worried seeing duplicates of the same crate with different versions during compilation. Cargo indeed compiles with different versions, so all calls to the dependended crate will receive what the developer expected when he/she wrote it. This is not a problem, in performance, or amount of instructions that end up in the binary. Just stop worrying.

Is it documented that Cargo can download and bundle multiple versions of the same crate?

By forking and playing with some code, I noticed that Cargo can download and bundle multiple versions of the same crate in the same project (native-tls 0.1.5 and 0.2.1, for example). I have wasted so much time by looking at the documentation of the wrong version.
I have looked for some information about this behaviour but I was not able to find anything. Is this documented somewhere?
Is there an easy way to determine/detect the version used by the code you're working on (current edited file)? Or can we tell Cargo to show some warnings/prevent the build if two versions the same crate are required?
It was a conscious decision when designing Rust to allow multiple versions of the same crate.
You have probably heard of Dependency Hell before, which occurs when 2 (or more) dependencies A and B have a common dependency C but each require a version which is incompatible with the other.
Rust was designed to ensure that this would not be an issue.
In general, cargo will attempt to find a common version which satisfies all requirements. As long as crate authors use SemVer correctly, and the requirements give enough leeway, a single version of the dependency can be computed and used successfully.
Sometimes, however, multiple versions of the same dependency are necessary, such as in your case since 0.1.x and 0.2.x are considered two different major versions. In this case, Rust has two features to allow the two versions to be used within the same binary:
a unique hash per version is appended to each symbol.
the type system considers the same type Foo from two versions of C to be different types.
There is a limitation, of course. If a function of A returns an instance of C::Foo and you attempt to pass it to a function of B, the compiler will refuse it (it considers the two types to be different). This is an intractable problem1.
Anytime the dependency on C is internal, or the use of C is isolated, it otherwise works automatically. As your experience shows, it is so seamless that the user may not even realize it is happening.
1 See the dtolnay trick that crate authors can use to allow some types to be interchangeable.
Cargo can indeed link multiple versions of some crate, but only one of those versions can be a direct dependency. The others are indirect references.
The direct reference is always the version referenced by Cargo.toml and on top-level of Cargo.lock (while the indirect references are in the dependencies subsections).
I am not sure how much it is documented, unfortunately.

Is it possible to run cargo install with a specific date instead of version numbers?

I want to install a package and all its dependencies as they were at a specific date and time in the past.
I need to use a slightly older version of rustc-nightly, and therefore I need to make sure that all dependencies pulled by cargo install compile against that old version of the compiler.
Currently, when I specify the version of the top-level package to install, it still seems to pull the latest version of some dependencies, which don't build with the old compiler.
No, this is not possible.
Your best options are:
Upgrade the compiler. If you "can't" do this, evaluate why you can't and decide how much benefit you are getting from that.
Add the dependencies to your own Cargo.toml pinned to an older version that does work.
You can try forking the crate index and rolling it back, but there's no guarantee that will work either.
seems to pull the latest version of some dependencies
Yes, most libraries specify dependencies with a semver-compatible range, such as my-library = "1.0". This will allow any version from 1.0.0 to 1.x.y.
Unfortunately, there's no consensus on whether requiring a new version of Rust constitutes a semver-breaking change yet.
See also:
What exactly is considered a breaking change to a library crate?
How to generate Cargo.lock based on last month's crates.io?

How can I find out whether a crate is compatible with a specific Rust version?

If I find a crate I'd like to use, how can I find out with which versions of Rust the crate works as expected?
Right now, you either read the crate's documentation or test it yourself. Many larger crates test against an older pinned version of Rust in CI when they make a stability claim.
There is a proposed RFC that would add the Rust version to the Cargo.toml file.

Check for unwanted wildcard dependencies recursively

I have a library and want to make sure that none of the dependencies in my dependency-tree uses wildcard dependencies. Wildcard dependencies are evil :(
Can I check this recursively with cargo in the command line? Or can I check it manually in Cargo.lock?
EDIT: While crates.io rejects crates with wildcard dependencies since the release Rust 1.6 (approximately, thanks Steve Klabnik), there are still old crates on crates.io that do have wildcard dependencies. I can upload my own crate that depends on such an old crate. Therefore my crate indirectly also depends on wildcard dependencies. This is what I want to avoid and check for.
I have written a small script that takes the crates.io-index and reads the current information for all packages. If a package has a direct wildcard dependency on another package there is a line printed in the format crate-name -> wildcard-dependency, another-one.
There are 995 current packages with wildcard dependencies. The list is exhaustive and will only decrease in length if the packages are updated.
You can go manually through all dependencies in your Cargo.lock and check if they are mentioned in the list. Note that you must use the most current version of your dependencies to assure that you are not depending on an outdated package with wildcard dependencies.
As of a few months back, Cargo no longer allows for wildcard dependencies. So you don't need to do this yourself.
This is a crates.io feature, not a Rust or Cargo feature, so it's not associated with any particular version of these tools. The update happened around the time we released Rust 1.6.

Resources