How do I "ignore" a member in a Cargo workspace?

I have a workspace with 2 members:

  • foo which must build on 1.75 and uses Edition 2021
  • foo_tests which is a separate crate for tests. foo_test uses nightly and importantly uses Edition 2024

In my CI, I want to guarantee that foo can be built using:

cargo +1.75 build --package foo

The above command raises this error:

error: failed to load manifest for workspace member `foo_tests`

Caused by:
  failed to parse manifest at `foo_tests/Cargo.toml`

Caused by:
  feature `edition2024` is required

  The package requires the Cargo feature called `edition2024`, but
  that feature is not stabilized in this version of Cargo
  (1.75.0 (1d8b05cdd 2023-11-20)).

Because foo_tests uses Edition 2024 (which wasn't stabilized until 1.85) i cannot compile foo using Rust 1.75. However, I'd like to essentially completely ignore the foo_tests member.

What should I do if I want to continue using nightly and Edition 2024 for foo_tests, but also be able to compile foo with Rust 1.75 and Edition 2021?

I want to use Edition 2024 in foo_tests to be able to use let chains

Workspace

  • Cargo.toml:

    [workspace]
    members = [
      "foo",
      "foo_tests"
    ]
    
  • foo/Cargo.toml:

    [package]
    name = "foo"
    version = "0.1.0"
    edition = "2021"
    rust-version = "1.75.0"
    
  • foo_tests/Cargo.toml:

    [package]
    name = "foo_tests"
    version = "0.1.0"
    edition = "2024"
    

Things I have tried

  • Using the --exclude flag. Error: it can only be used with --workspace
  • Using --workspace --exclude foo_tests, but the same error is raised as in the original post

you can try

  1. remove workspace
    2.load the 1.75 version as a dependency with path to 2024 versions
    3.and build 2024 version

I suppose just removing "tests" from the workspace_members array manually will work. If nothing else, writing a small bash script and running it in the CI could work. I was hoping there is a way to do this without changing the filesystem though, I appreciate your answer

1 Like

Include foo in the workspace and explicitly exclude foo_tests from the workspace.

.
โ”œโ”€โ”€ Cargo.lock
โ”œโ”€โ”€ Cargo.toml
โ”œโ”€โ”€ foo
โ”‚   โ”œโ”€โ”€ Cargo.toml
โ”‚   โ””โ”€โ”€ src
โ”‚       โ””โ”€โ”€ lib.rs
โ””โ”€โ”€ foo_tests
    โ”œโ”€โ”€ Cargo.lock
    โ”œโ”€โ”€ Cargo.toml
    โ””โ”€โ”€ src
        โ””โ”€โ”€ main.rs

Cargo.toml

[workspace]
members = ["foo"]
exclude = ["foo_tests"]
resolver = "2"

foo/Cargo.toml

[package]
name = "foo"
version = "0.1.0"
edition = "2021"
rust-version = "1.75.0"

[dependencies]

foo_tests/Cargo.toml

[package]
name = "foo_tests"
version = "0.1.0"
edition = "2024"

[dependencies]
foo = { path = "../foo" }
3 Likes

I just tried this, it seems to have the same effect as not including "foo_tests" at all. For example, rust-analyzer stops working inside of "foo_tests" when I do this. (and I would like it to continue working)

And If I have some lints I want to inherit from the workspace Cargo.toml:

[workspace]
members = ["foo"]
exclude = ["foo_tests"]

[workspace.lints.clippy]
absolute_paths = "deny"

foo_tests/Cargo.toml:

[package]
name = "foo_tests"
version = "0.1.0"
edition = "2024"

[lints]
workspace = true

Running cargo clippy inside of foo_tests says it failed to find a workspace root:

error: failed to parse manifest at `/home/e/random/proj/foo_tests/Cargo.toml`

Caused by:
  error inheriting `lints` from workspace root manifest's `workspace.lints`

Caused by:
  failed to find a workspace root

exclude seems mostly useful when globs are involved

Essentially, the idea is that it continues to act like it is in a workspace under normal operations. But running with cargo +1.75 should act as if it is excluded

I think ideal behaviour would be if the --exclude flag allowed me to exclude a package before Cargo verifies that the package's Cargo.toml is valid. Essentially the same behaviour as if it was present in the workspace.exclude field

Such an --exclude flag would require the contents of the workspace Cargo.lock lockfile to change depending on if you pass the flag or not, which is a bad idea.

1 Like

Another idea that popped into my mind is to set RUSTFLAGS="--edition 2024". However, this doesn't help because Cargo also implicitly passes --edition 2021 as it is specified in the manifest

error: Option 'edition' given more than once

Removing the edition field from the manifest defaults it to 2015 anyway. If there was a way to override the edition that Cargo passes to rustc it would work - So Cargo.toml says Edition 2021 but we pass RUSTFLAGS=--edition 2024

The edition of foo_tests would be 2021 by default. But when compiling with cargo test --package tests we would override it to 2024.

For now, I'm just not going to use Edition 2024 but for the long-term it would be nice if this could be done

I opened an issue in Cargo about this: It is impossible to compile any individual Edition 2021 package in a workspace using Cargo 2021 if there is even one Edition 2024 package ยท Issue #15894 ยท rust-lang/cargo ยท GitHub

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.