# Workspace dependency resolution is a footgun

**URL:** <https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885>\
**Category:** cargo\
**Created:** [November 30, 2022, 11:11pm UTC](https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885 "2022-11-30T23:11:48Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![punkeel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/punkeel/32/10221_2.png) [@punkeel](https://internals.rust-lang.org/u/punkeel)\
**Post date:** [November 30, 2022, 11:11pm UTC](https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885/1 "2022-11-30T23:11:48Z")

</div>

Cargo workspace projects are built using separate independent crates that can be tested and compiled individually, while belonging to the same project (git repository, for example). This makes it easy to isolate components, identify dependencies between sub-crates, and more.

This also comes with rough edges, as **features** are no longer resolved per-crate, and are instead shared across the workspace. This is documented in the [Cargo book](https://doc.rust-lang.org/cargo/reference/resolver.html#features):

> When building multiple packages in a workspace (such as with `--workspace` or multiple `-p` flags), the features of the dependencies of all of those packages are unified.

With a disclaimer:

> If you have a circumstance where you want to avoid that unification for different workspace members, you will need to build them via separate `cargo` invocations.

The described behavior is simple to reproduce: a [simple workspace project](https://github.com/punkeel/manycrates) with two crates (`crate-a`, `crate-b`) triggers this bug. Crate A uses `serde` and requires the `derive` feature (but doesn't use it), Crate B has a dependency (direct or not) on `serde`, _and_ its `derive` feature.

- Running `cargo check` / `cargo test` works.
- Running `cargo check -p crate-b` works.
- Running `cargo check -p crate-a` **doesn't work**.
- Removing `crate-b` **breaks** `crate-a`, yet they don't share a dependency relationship.
- Removing the unused `serde` dependency from `crate-b` **breaks** `crate-a`.

In a typical setup, CI will run tests using `cargo check/test`, and won't notice that `crate-a` is misconfigured. In my opinion, this is a foot gun, and should be highlighted on the check / test pages. This allows the creation of "bad" crates that seem to work well, but break when unrelated changes happen.

A developer cloning a repository should expect the tests to run and pass, both globally (`cargo test`), and when run individually (`cargo test -p ....` and `cargo test --lib ... --manifest-path ...`). This is, currently, not guaranteed due to the feature unification.

A library with _examples_ sub-crates (eg: [syn](https://github.com/dtolnay/syn/blob/3e915e5c98cd9df4a9b763ecd15c8e7fadc8d391/Cargo.toml#L75-L88)) could easily have misconfigured dependencies, as the features used by examples _pollute_ the other crates – unless the author is careful enough to test each crate individually. (Note: I'm not saying syn is impacted, I trust dtolnay! :))

As a developer, I expect `cargo check` and `cargo test` to throw errors when a crate or its dependencies are misconfigured, if doesn't require the right features from its dependencies. Having a way to toggle this behavior (either command flag, or `Cargo.toml` config?) would work, I believe.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [November 30, 2022, 11:57pm UTC](https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885/2 "2022-11-30T23:57:01Z")

</div>

It's not just workspaces, you can have feature leakage between your normal and dev-dependencies and between different subsets of your dependencies. The only way to really test for feature sets is to use tooling like [`cargo-hack`](https://github.com/taiki-e/cargo-hack) that isolates these different situations, `cargo hack check --workspace --feature-powerset --no-dev-deps` is what I normally use which runs 256 different builds in one of my crates to ensure no features leak from one feature to another.

---

<div class="post-metadata">

**Author:** ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)\
**Post date:** [December 1, 2022, 1:09am UTC](https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885/3 "2022-12-01T01:09:41Z")

</div>

This is only the case when not using the newer feature resolver (which is default in the 2021 edition).

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [December 1, 2022, 7:32am UTC](https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885/4 "2022-12-01T07:32:00Z")

</div>

AFAIK the newer feature resolver only affected merging of build and runtime deps features, not dev or transitive ones.

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [December 1, 2022, 7:04pm UTC](https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885/5 "2022-12-01T19:04:51Z")

</div>

The new resolver handles both build and dev dependencies, as well as dependencies for non-enabled targets. See:

- [https://github.com/rust-lang/cargo/pull/7820](https://github.com/rust-lang/cargo/pull/7820)
- [Tracking issue for -Z features=dev\_dep · Issue #7916 · rust-lang/cargo · GitHub](https://github.com/rust-lang/cargo/issues/7916)

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [December 22, 2024, 5:23pm UTC](https://internals.rust-lang.org/t/workspace-dependency-resolution-is-a-footgun/17885/6 "2024-12-22T17:23:11Z")

</div>

This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.
