TL;DR: cargo test
is compiling too much, for nothing.
State of the Art
I was running cargo test
again today, and again I found myself sighing as cargo test
was recompiling everything, for nothing.
While the test binary that is produced only contains tests for the current crate, cargo will still instruct rustc to build all the upstream crates in test mode just in case:
- Said crates happen to export more items in test mode, some test-specific API.
- Upstream crates happen to use said test-specific API.
Nifty, ain't it?
Frequency
While the above is convenient, for anyone using a test-specific API, I suspect the reality is that:
- Very few crates export any test-specific API, or behave in any way differently when compiled in test mode.
- Even fewer crates use any test-specific API from an upstream dependency.
This is certainly true for the codebases I maintain at work. Over the few hundreds of crates I maintain:
- Maybe a handful export a test-specific API.
- Maybe a handful use a test-specific API from an upstream dependency, and none come from 3rd-party dependencies.
Which leads me to questioning whether forwarding the "test mode" is the right choice, and whether it should not, instead, be opt-in.
Let's not!
I don't know about you, but I'd be quite happy to save up half my disk space, and a good chunk of compilation time!
And in a world where crates compiled in test mode depended on the regular version of their dependencies, it would just happen...
... but of course that'd break backward compatibility. Damned!
Automatic Detection
Detecting whether compiling a crate with or without test mode makes any difference may actually be... complicated.
If this could be done, then cargo
could write some metadata next to the local copy of the source files indicating there's no need to re-compile that crate in test mode -- it's all the same. Sweet, no?
But I have great doubts:
- It would require compiling in test mode at least once. May not seem like a big deal, but CI without caching wouldn't benefit.
- It would require a reachability analysis, comparing not only the API, but also the implementation of reachable items.
- It would notably require ensuring that nobody smuggled a reachable trait impl in test mode.
Explicit opt-in
Unless someone has a miracle solution for the above, the best solution may be to switch to opt-in propagation on an edition boundary, such as edition 2027.
A crate in edition 2027 compiled in test mode would, by default, depend on the non test-mode versions of its dependencies.
There would then be an option in Cargo.toml to enable test mode on a per-dependency basis when compiled in test mode.