Search code examples
rustrust-cargofeature-flags

Why does Rust include dev-only features as part of a release build?


I've made a simplified example of my question in this github repo: https://github.com/JackSpagnoli/rust_features

I have a library "auth" handling api authentication, which in prod I would like to pull a value from an environment variable, but in testing and lower environments to use a constant value.

I've added compiler cfgs to handle this, using a dev flag, as below:

    #[cfg(not(feature = "dev"))]
    let api_key = std::env::var(API_KEY_HEADER).unwrap();
    #[cfg(any(feature = "dev", test))]
    let api_key = "test".to_string();

Cargo.toml for this crate has features defined as

[features]
default = []
dev=[]
some_other_feature=[]

Tests in this file can expect an api_key value of test.

This library is used in a binary crate api, which imports lib as follows

[dependencies]
lib = { path = "../lib", default-features=false, features=["some_other_feature"] }

[dev-dependencies]
lib = { path = "../lib", default-features=false, features=["dev"] }

In main.rs for api, unit tests can expect an api_key value of test, and I would presume that in main(), when running with a --release build, I can expect an api_key value set from the environment. However, when running the code is getting an api_key value of test.

This doesn't seem like intended behaviour, as dev-only features are getting compiled into release builds.


Solution

  • You are using a workspace with a virtual manifest. Add resolver = "2" to your root Cargo.toml:

    [workspace]
    resolver = "2"
    # ...
    

    Cargo's "feature unification" was improved with edition = "2021" crates to be smarter about separating [build-dependencies] and [dev-dependencies] from the build. However this is overridden by the root Cargo.toml when in a workspace and virtual manifests don't have a [package] section to define an edition field to indicate which feature-resolver to use. So it must be specified explicitly.

    See: