Tricking cargo into generating lock files for an old MSRV (for fun?? and profit??)
So uh. For /reasons/ that I might expand on in future blog posts1 I needed to work on an old (~4y old) library… Without a commited lock file… With some dependencies being yanked… And some dependencies requiring much newer MSRV…
How it started:
{library}depends onahash ^0.7.62ahash >= 0.6.0, <=0.7.6is yankedahash ^0.7.7has MSRV1.60.0{library}has MSRV1.59.03- uhhhhhhmmmmmmmmmm
So, I can’t update ahash to a newer version, because it would not be supported by rust 1.59.0. And I can’t keep it at 0.7.6, because the MSRV CI will not pass and thus I can’t merge the PR…
can’t you just raise the MSRV?
I- look-
uhuh?
Yes, I /could/4 but a) I didn’t think of that originally b) I never search for easy ways out c) it’s nice to keep MSRV as is d) :(
Anyway-
What I’m looking for is a way to get a Cargo.lock file which would
- contain
ahash =0.7.6(so thatcargoactually allows me to get it), and - only contain versions of libraries with MSRV <=
1.59.0
My first idea was to generate a lock file with a new version of cargo, and then manually downgrade ahash to 0.7.6. At first I couldn’t find how to downgrade things with cargo at all, but then a friend of mine, Jonathan Brouwer5, helped me find that the way to downgrade a dependency is cargo update {dependency} --precise {version}6.
However… That did not help much…
(this is not even a half of ithn…)
There are two problems with this approach:
- There are /so/ many dependencies that need to be downgraded
- Some dependencies are interconnected and hard to downgrade
- Crates with exact dependencies, like
serde x.y.zdepending onserde_code =x.y.zare /especially/ annoying - But even just “downgrading A requires downgrading B first because B depends on newer A than I want to downgrade to” can be tiring for popular crates
- Crates with exact dependencies, like
This is just completely impractical and I had to give up on this idea7.
When my idea did not work, I went to the rust community discord and asked how I could generate the lock file. To my surprise I got a response the same day from synapturanus zombie 𓆏 (frog), who recently helped someone else with a similar issue.
All that’s needed to generate an MSRV-compatible Cargo.lock is
- Make sure
package.rust-versionis set in theCargo.tomlto the MSRV - Remove existing
Cargo.lock(if it exists) CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS="fallback" cargo +nightly check- You can also set
resolver.incompatible-rust-version = "fallback"in the cargo config, but that’s mildly more annoying
- You can also set
- profit!
It’s that shrimple folks!
One caveat is that for this to work your dependencies need to set rust-version too. And since it only got introduced in Rust 1.56.0, this might not work very well for 1.56.0 and a few succeeding versions. Still, you can use this method as a start, and then downgrade the dependencies that don’t accurately set rust-version. As a data point, this method worked for me successfully on 1.65.0, but not on 1.59.0.
Moral of the story: commit your lock files. Also, asking for help leads to being helped. Crazy how that happens.
Thanks again to synapturanus zombie 𓆏 (frog) for helping with this; and thank you to Jonathan and Arya for reviewing this post <3
okmeowbye :3
-
me when i lie ↩
-
yes, it’s off by 1 version .-. ↩
-
and i actually ended up raising the MSRV in a case, before i found other ways to solve this ↩
-
nya :3 ↩
-
downgrading a dependency requires using
updatesubcommand?..shush
it makes sense, why would have a separate command for that?
also how are you in the footnotes??
↩:)
-
turns out i make a pretty bad dependency resolver ↩