rust-lang / cargo

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

Cargo incorrectly detects a package name conflict when a workspace package has the same name as a (transitive) dependency #12891

Open avsaase opened 10 months ago

avsaase commented 10 months ago

Problem

Take a project directory structure like this:

.
├── Cargo.lock
├── Cargo.toml
├── examples
│   └── grid
│       ├── Cargo.toml
│       └── src
│           └── main.rs
└── src
    └── lib.rs

Cargo.toml:

[package]
name = "library"
version = "0.1.0"
edition = "2021"

[dependencies]
taffy = { version = "0.3.16", features = ["grid"] }

[workspace]
members = ["examples/grid"]

examples/grid/Cargo.toml:

[package]
name = "grid"
version = "0.1.0"

[dependencies]
library = { path = "../../" }

Dependency tree:

library v0.1.0 ([omitted])
└── taffy v0.3.16
    ├── arrayvec v0.7.4
    ├── grid v0.10.0
    ├── num-traits v0.2.17
    │   [build-dependencies]
    │   └── autocfg v1.1.0
    └── slotmap v1.0.6
        [build-dependencies]
        └── version_check v0.9.4

When you try to run the grid example with cargo run --package grid you get an error:

error: There are multiple `grid` packages in your project, and the specification `grid` is ambiguous.
Please re-run this command with `-p <spec>` where `<spec>` is one of the following:
  grid@0.1.0
  grid@0.10.0

Steps

  1. Checkout https://github.com/avsaase/cargo-ambiguous-package
  2. Run cargo run --package grid
  3. Run cargo run --package grid@0.1.0

Possible Solution(s)

The problem seems to be that cargo sees the transitive grid dependency of taffy and sees that as a conflict with the package of the same name in the local workspace. This must be a bug because there is no reason to run a binary target from a (transitive) dependency with cargo run. And even if there was, the grid crate doesn't have a binary target so there's nothing to run.

The solution suggested by cargo is also not correct because running cargo run -p grid@0.1.0 gives the error that the package is not found in the workspace.

A workaround is to use globally unique package names in workspaces but this is very restrictive because adding a dependency can easily create a new conflict.

Notes

No response

Version

cargo 1.73.0 (9c4383fb5 2023-08-26)
release: 1.73.0
commit-hash: 9c4383fb55986096b414d98125421ab87b5fd642
commit-date: 2023-08-26
host: x86_64-unknown-linux-gnu
libgit2: 1.6.4 (sys:0.17.2 vendored)
libcurl: 8.2.1-DEV (sys:0.4.65+curl-8.2.1 vendored ssl:OpenSSL/1.1.1u)
ssl: OpenSSL 1.1.1u  30 May 2023
os: Linux 16 (focal) [64-bit]
epage commented 10 months ago

The challenge is you're dealing with layers of calculations. We first look up a package and then the relevant command does what it wants with it. We also don't know what bins are in package unless we parse the manifest. So for this to fully work as requested, we'd need to cross layers and then load the manifests to resolve the ambiguity. We'd need the ambiguity resolution to be unambiguous to the user since (1) they might not be aware of details and (2) they can make mistakes.

Something I've considered is

If we could prioritize workspace members with a warning saying other options are available and still error when all else is equal, I think that might be good enough.

avsaase commented 10 months ago

But why would cargo run ever run a package from a dependency? I fail to see a use case for that.

epage commented 10 months ago

I didn't say that part was ideal. I was more explaining why it is the way it is and the challenge with changing it to something else.

epage commented 10 months ago

8157 also touches on the problems with us evaluating the available packages before the available binaries.

IceTDrinker commented 10 months ago

Hello, this is of interest also in the semver trick approach https://github.com/dtolnay/semver-trick to add compatibility code (e.g. for serialization) to an old version of a crate by depending on a more recent version of the crate and adding bridge/glue code in the old crate allowing users of the old crate to use a minor release to proceed with serialization format update for example.

IceTDrinker commented 10 months ago

a workaround seems to not specify the package at all, this is an issue if you have several crates with colliding binary/example names I guess

i.e. if you have unique names for binaries/examples you can

cargo run --release --bin my_bin

as long as my_bin has a unique name in the workspace it should be run ok, adding -p my_package when my_package is also a transitive dependency brings you back to the original issue where the name is ambiguous, but running with the spec is not accepted

elagergren-spideroak commented 4 months ago

This also occurs with cargo test -p foo where your workspace has a crate called foo and you also have a dependency called foo (renamed to something else, of course).