I've seen Rust users struggle when trying to use less-than-the-latest compiler version, and subsequently ask for some kind of "long term support" version of the compiler that would be usable for longer than 6 weeks.
The thing is, old Rust compilers actually work fine. The problem is with the crates that don't support the old compilers.
While there could be an LTS edition of the compiler, it would be only an indirect way to pressure crate authors to support old compilers. BUT we don't need this! We can keep crates compatible without asking anyone! With a small trick, it's possible to give old Rust compiler versions ability to use all the crates they can handle, without running into unsupported ones.
The solution is:
-
Make a fork of the crates-io registry and remove crates/crate versions that aren't compatible with the desired old compiler version.
-
Make Cargo use the fork instead of the full registry.
The second step is surprisingly simple! It doesn't need any of the new alternative registry machinery. It works since an ancient Rust 1.13! In .cargo/config
set:
[source.crates-io]
replace-with = "lts-repo-replacement"
[source.lts-repo-replacement]
registry = "https://github.com/kornelski/crates.io-index"
And for a proof of concept I've prepared a registry fork with crates compatible with Rust 1.24 (that is old enough to be compatible with oldstable Debian).
As a bonus, I've also yanked defunct crates that were published before Rust 1.0. This makes -Z minimal-versions
flag work much more reliably.
To generate the config, and also add a couple of hacky symlinks to make Cargo work faster with it, I've made a tool:
So you can use it by:
cargo install lts
cargo lts "https://github.com/kornelski/crates.io-index"
And a cool thing about it is that once you generate Cargo.lock
, you don't even need the custom registry config. It will get the right crates straight from crates-io.
You can verify that the registry fork has the same checksums as the original, and the registry config file points to crates-io, so you're getting the exact same crates (the only difference is you're not seeing the wrong crates).
Current issues/limitations:
- To verify which crates are compatible I'm using JSON output of
cargo check
. It's quite useful, because I get precise machine-readable compilation errors. The JSON output was added around 1.22, so I can't easily make a filtered index for older Rust versions (but I have data to make registries for all newer versions) - I'm ignoring crates that require nightly features. They could theoretically be supported, but it's whole another dimension to think about.
- I'm running compatibility testing on Linux, so non-Linux crates are problematic. And so are -sys crates that have unusual dependencies. So I still hope for RFC 2495 to make it easy for me.
- Crates are generally bad at specifying their true dependency versions. I've found lots of cases where they don't actually work with the versions they say they work, e.g.
Cargo.toml
saysfoo = "1.0"
, but the crate uses functions added infoo 1.2
. - Very old cargo ignores
edition = "2018"
and happens to work with some "2018" crates. That complicates my classification
So if you're using an ancient Rust version, I'd love your feedback. Is this good enough? Are there still some broken crates that slipped through? Any missing?