rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.84k stars 2.43k forks source link

Regression (?) with resolver=2, cargo build -p, and workspaces #9696

Open Manishearth opened 3 years ago

Manishearth commented 3 years ago

Problem

Let's say you have a workspace that contains a library (library) and some tooling (tool). Something like this. You want the library to support no_std, but the tooling does not. (In general, this isn't specific to tooling, perhaps a subset of your workspace supports no_std)

One would expect that building library for a baremetal target would work (and build serde with no_std), and building the entire workspace or tool for a baremetal target would not. Furthermore, it's common to use cargo build -p serde to just build serde; and it's useful if it builds the serde that-would-be-built-by-running-cargo build-in-the-same-folder, because it helps for things like incrementally getting dependencies to work with no_std.

This is indeed how it works on resolver = "1", note that cargo check and cargo check -p serde both succeed from the library folder, but not the root folder:

``` [10:09:15] मanishearth@manishearth-glaptop ~/sand/workspace-test/library ^_^ $ cargo check --target thumbv7m-none-eabi (succeeds) [10:09:22] मanishearth@manishearth-glaptop ~/sand/workspace-test/library ^_^ $ cargo check --target thumbv7m-none-eabi -p serde (succeeds) [10:09:27] मanishearth@manishearth-glaptop ~/sand/workspace-test/library ^_^ $ cd .. [10:09:29] मanishearth@manishearth-glaptop ~/sand/workspace-test ^_^ $ cargo check --target thumbv7m-none-eabi (fails) [10:09:33] मanishearth@manishearth-glaptop ~/sand/workspace-test O_o $ cargo check --target thumbv7m-none-eabi -p serde (fails) ```

However, with resolver = "2", cargo check succeeds in the library folder, but not cargo check -p serde:

``` [10:45:55] मanishearth@manishearth-glaptop ~/sand/workspace-test/library ^_^ $ cargo check --target thumbv7m-none-eabi (succeeds) [10:45:58] मanishearth@manishearth-glaptop ~/sand/workspace-test/library ^_^ $ cargo check --target thumbv7m-none-eabi -p serde (fails) [10:46:02] मanishearth@manishearth-glaptop ~/sand/workspace-test/library ^_^ $ cd .. [10:46:03] मanishearth@manishearth-glaptop ~/sand/workspace-test ^_^ $ cargo check --target thumbv7m-none-eabi (fails) [10:46:05] मanishearth@manishearth-glaptop ~/sand/workspace-test O_o $ cargo check --target thumbv7m-none-eabi -p serde (fails) ```

This seems a bit counterintuitive to me: the new resolver is intended to reduce this kind of problem. It would be nice if the old behavior still worked here, and this seems like a regression to me.

Steps

  1. Check out https://github.com/Manishearth/cargo-resolver-bug
  2. Uncomment the resolver = "2" line in Cargo.toml
  3. Install some no_std target (I'm using thumbv7m-none-eabi). You can alternatively use -v in the build commands to check if serde is built with std enabled
  4. cd library && cargo check --target thumbv7m-none-eabi -p serde

Notes

Output of cargo version:

$ cargo version
cargo 1.55.0-nightly (9233aa06c 2021-06-22)
ehuss commented 3 years ago

This was an intentional change as part of making it less magical as to changing behavior based on the "current" directory (part of package-features in #5364, RFC #2957).

it's common to use cargo build -p serde to just build serde

I'm a bit surprised to hear this is "common", as I haven't really seen that done before. Is there some reason you can't just run cargo check to see how the dependencies would build? Why would you need to build a specific one?

Manishearth commented 3 years ago

I'm a bit surprised to hear this is "common", as I haven't really seen that done before. Is there some reason you can't just run cargo check to see how the dependencies would build? Why would you need to build a specific one?

It's super common in large codebases when doing a major refactor -- sometimes you wish to focus on a specific dependency, and it's not necessarily clear if a compile failure comes from:

You can get this clarity by using -v and checking which crates get built, and also by knowing the dep graph, but for large codebases this is still annoying.

For example, right now I'm moving a codebase over to no_std and it's important to be able to do this crate by crate, especially for external dependencies like serde (need to be able to make sure it's being built with the correct features, etc)

I think this is a pretty important use case tbh, it makes such work much much harder. Perhaps there could be a different flag, but I don't think this is that uncommon for large codebases.