Skip to content

Support different versions of the same dependency within a workspace #13594

Open
@alshdavid

Description

@alshdavid

Problem

My Cargo workspace has multiple entry points that compile to executable/bin or dylib targets. Currently, when placed within a workspace, Cargo will attempt to combine their dependencies where they share the same "compatible" versions of a dependency.

The problem is that these project consume third party dependencies that have conflicting versions - either because library maintainers don't adhere to semver correctly or because library maintainers choose to specify exact versions of a dependency (e.g. =0.0.40).

My projects can be compiled on their own without issue however, if they share a workspace, cargo build will fail because Cargo tries/fails to resolve these conflicting dependencies.

Example Case

I have a workspace that has three packages

/crates-main
  /project-bin
    Cargo.toml
  /project-types
    Cargo.toml
/crates-plugins
  /plugin-dynamic-lib
    Cargo.toml
Cargo.toml

crates-main/project-bin
This is the main entrypoint for my application which compiles to an executable. This program is able to consume dynamic libraries using the libloading crate.

crates-main/project-types
This is a shared library compiled as a lib that has no external dependencies, only exporting types to be used by both the "plugins" and the main executable (a.k.a. the "contract").

crates-plugins/plugin-dynamic-lib
This is a library that is compiled to a dylib. It depends on project-typesfor the types required to initialize a plugin and will be consumed by the executable produced byproject-bin`

Note that this package could also be an executable, I am using a dylib in my example because that's my current use case

In summary we have 2 packages that compile to binaries (./project-bin and ./plugin-dynamic-lib.so) and one shared library that is statically linked within those two crates.

Problem

As an example, assume project-bin consumes log = "=0.4.20" and plugin-dynamic-lib consumes log = 0.4.21 (indirectly via a third party dependency external to the workspace).

In a combined workspace, cargo build will error saying that it cannot resolve a compatible version between the two specified.

In reality, these packages will compile to separate binaries so version conflicts of dependencies would not result in a material conflict at runtime.

Current Solution

To get around this today, I simply avoid using a Cargo workspace and compile the projects independently of each other from a build script where shared dependencies are referenced via my_pkg = { path = "../path/to/pkg" }.

The issue with this approach is that rust-analyzer is unable to provide suggestions for the packages when the top level folder is open in the editor - resulting in a less than ideal development experience

Proposed Solution

A few possible solutions to this:

Option 1

Allow for multiple incompatible dependencies to coexist within a workspace if their versions cannot be combined and their consumers are of crate-type bin or dylib

e.g. a package in crates.io with the latest version of 0.4.21

Consumer A

[bin]

[dependencies]
dependency = `^0.4.0`

Consumer B

[bin]

[dependencies]
dependency = `=0.4.20`

Consumer A would get 0.4.21
Consumer B would get 0.4.20

Option 2
Devise a way for rust-analyzer to work with multiple nested projects within a parent directory

Option 3
Perhaps some kind of support for workspaces, isolating dependencies between the workspaces

Notes

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-dependency-resolutionArea: dependency resolution and the resolverC-feature-requestCategory: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`S-triageStatus: This issue is waiting on initial triage.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions