Version control confusion in Cargo.lock and Cargo.toml?

It is said when you write

rand = "0.8.3"

in Cargo.toml file, you will get a 0.9>version number>=0.8.3.

yes, I noticed I get rand="0.8.5", and it is written to the Cargo.lock, which means next time 0.8.5 will be used no matter what. I got no problem with these.

But in case I really want 0.8.3 instead of 0.8.5, how can I write it in Cargo.toml? Thanks.

For almost all cases where you want to use a specific version that isn't the newest, I would suggest cargo update -p rand --precise 0.8.3, which will set that version in the lockfile. That way, you build with rand 0.8.3, but you don't prevent anyone from using a different version if they need to.

What problem are you trying to solve?

2 Likes

Thanks!

So I need to use a command line to do that? Can't I write something to Cargo.toml like

rand=precicse "0.8.3"

or

rand="precise 0.8.3"

to finish that?

It's possible to set specific version numbers or ranges in Cargo.toml. Doing that will tend to make your crate incompatible with other crates in the ecosystem (consider what would happen if something wanted rand 0.8.3 and something else wanted rand 0.8.5), so it's not recommended.

1 Like

Thanks.

In case, someone need 0.8.3 and some else need 0.8.5, or someone need 0.8.~ and some else need 0.9.~, I guess, the two versions of crates will be downloaded into /target/debug/deps/

As a rust noob, I didn't see much damage of doing this, if you can specify which package use which version in toml file, unless you cannot specify. That will be disaster, I agree.

But this greater equal mechanism of version control look like cannot deal with this situation:

If a package need use a special API only available in thecrate 0.8.~, while I want use a special API only available in thecrate v0.9.~. And the package wrote something like thecrate="0.8.0" in his toml file, and I write thecrate="0.9.0" in my toml file.

What cargo will do in that case?

By design, you can't use two different compatible versions of the same crate in the same build; if something is using 0.8.3, nothing else can use 0.8.5, and vice versa. You can use both 0.8.x and 0.9.y at the same time, but not 0.8.x and 0.8.y. Hence the recommendation against restricting the use of newer compatible versions.

5 Likes

Thanks!

Doesn't rand = "=0.8.3" work as you require?

1 Like

Thanks!

I tested it, it downloads exactly 0.8.3 and works.

I didn't know the syntax, I just read two chapters of Rust knowledge book. You answered the other half of my question.

Why do you want to use 0.8.3 instead of 0.8.5? What problem are you trying to solve?

7 Likes

I believe it is quite consistent syntax for server-style dependencies, such as npm, Node, etc.

The syntax for specifying version ranges is documented in the Cargo book.

Also note for the future that questions about using Rust, as this one is, are better suited for the Users' forum-- this forum is mostly for people working on Rust itself.

6 Likes

Right, the user forum, Thanks Guys!

BTW, the exact version syntax is problematic and is very likely to break projects.

If you write rand = "=0.8.3" then your entire project will fail to compile, and break most Cargo commands with a huge error about conflicting requirements, if any dependency, or dependency of dependency, anywhere in your project ever asks for 0.8.4 or any newer 0.8 version. It will also totally break if anyone else asks for rand = "=0.8.2".

Basically = means it's either exact version or fail. If you do this in your library that's a dependency in someone else's project, you will be breaking someone else's project too.

So exact versions are fragile and disruptive. Unless you have to quickly work around some terribly broken crate, you shouldn't use them.

If an upgrade of a dependency breaks something for you, it's best to report this to the crate's author and convince them yank the newer breaking version, instead of you requiring an exact older version.

Locking versions using Cargo.lock is fine though.

4 Likes

Actually, this brings up an interesting thought experiment. What if you know that some version is horribly broken, but not yanked, so there is a possibility of accidentally downloading it. Could we implement something that let's you specify multiple disjoint ranges? E.g. rand = {versions = [">= 0.8.0, < 0.8.3", "> 0.8.5, < 0.9.0"]}? Precise convention to use up for bikeshedding.

2 Likes

The only situation where I needed this was when a dependency contained a bug which I had a workaround for. I knew that the workaround would stop working when the bug was fixed, so I used an exact version requirement to prevent cargo from updating it when the bugfix landed:

foo = "=0.4.3"