I have multiple workspaces, one for the crate and others for examples which use that crate.
I tried speeding up the CI by setting CARGO_TARGET_DIR to a common folder, so that the main crate is not rebuilt multiple times. However, while it is now build only once for examples, it is still being build the second time when the crate itself is being built and I don't understand why.
Then I set CARGO_TARGET_DIR to a common folder like C:/temp and then run cargo build in both crates, which results in dependency being built twice. Why?
As a note, I know that putting the library and binary inside a single workspace will solve the issue, but I cannot do this in my case.
cargo checks several things to determine if it needs to rebuild a crate: in particular the set of enabled features is a common tripping hazard, but various environment variables also count. Here's all the horrible detail:
I tried verifying that this is not related to feature flags (at least directly) by creating multiple new crates and I can clearly see that dependency crate is built twice there as well.
But at the same time I clearly see two .fingerprint files. One is created when I build the dependency crate and another one I build one of many user crates.
I can see the difference is in lib-dependency.json:
In my experience a global CARGO_TARGET_DIR does not play well when you have multiple crates with the same name (including multiple path dependencies to the same crate).
In the real example the names are different.
What I do not understand is why for building a dependency separately and as a part of another crate, the different paths are used?
dependency on master [?] is 📦 v0.1.0 via 🦀 v1.83.0
> CARGO_TARGET_DIR="C:/test/dependency/target" CARGO_LOG=cargo::core::compiler::fingerprint=trace cargo build --release
... fingerprint at: ... .fingerprint\dependency-f700e09833da5ba7\lib-dependency
user on master [?] is 📦 v0.1.0 via 🦀 v1.83.0
> CARGO_TARGET_DIR="C:/test/dependency/target" CARGO_LOG=cargo::core::compiler::fingerprint=trace cargo build --release
... fingerprint at: ... .fingerprint\dependency-72d5426137986e35\lib-dependency
user1 on master [?] is 📦 v0.1.0 via 🦀 v1.83.0
> CARGO_TARGET_DIR="C:/test/dependency/target" CARGO_LOG=cargo::core::compiler::fingerprint=trace cargo build --release
... fingerprint at: ... .fingerprint\dependency-72d5426137986e35\lib-dependency
Cargo uses paths relative to the workspace root when building local (as in not from crates.io or a remote git repo) crates. When you don't explicitly use workspaces, each individual package is a workspace root. So if you build directly build dependency, cargo will cd into the dependency directory and do rustc src/lib.rs, while if you build user, then cargo will cd into the user directory and do rustc ../dependency/src/lib.rs for building dependency. This ensures diagnostics are always relative to the workspace root rather than the directory of the package that happened to be built.