Conditional compilation with features

I am working through Herbert Wolverson's excellent (currently in Beta) book "Advanced Hands-on Rust".
In Chapter 3, "Optimize and Benchmark Your Library", he uses features to be able to select which random number algorithm is used for random number generation.

The library Cargo.toml looks like this:

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

[dependencies]
rand = "0.8"
rand_pcg = { version = "0.3", optional = true }
rand_xorshift = { version = "0.3", optional = true }

[features]
default = [ "pcg" ]
pcg = [ "rand_pcg" ]
xorshift = [ "rand_xorshift" ]

...and the module with the code is:

#[cfg(feature = "pcg")]
type RngCore = rand_pcg::Pcg64Mcg;

#[cfg(feature = "xorshift")]
type RngCore = rand_xorshift::XorShiftRng;

#[cfg(all(not(feature = "pcg"), not(feature = "xorshift")))]
type RngCore = rand::prelude::StdRng;

This all seems reasonable, and it compiles correctly. Tests and benchmarks for the library run as expected. I can select the different algorithms from the command line with
cargo bench --no-default-features --features xorshift

Earlier in the book, an example game is built using this library. According to the book, if I want to set a default, I should use the following syntax in the application Cargo.toml line when pulling in the library:
my_library = { path = "../my_library", features=["xorshift"] }
This works if the selected feature in this line matches the default feature in the library Cargo.toml. If I select a different feature, I get an error when compiling:

 ❯ cargo check
    Checking my_library v0.1.0 (/home/paul/projects/rust/projects/more_hands/my_library)
error[E0428]: the name `RngCore` is defined multiple times
  --> my_library/src/random.rs:10:1
   |
7  | type RngCore = rand_pcg::Pcg64Mcg;
   | ---------------------------------- previous definition of the type `RngCore` here
...
10 | type RngCore = rand_xorshift::XorShiftRng;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RngCore` redefined here
   |
   = note: `RngCore` must be defined only once in the type namespace of this module

Am I missing something in terms of how the features are setup, or how I am setting the features I want in my application Cargo.toml? It seems my feature request in the application Cargo.toml is not over-riding the default in the library Cargo.toml, but adding to the list of active features (hence the redefinition build error).
I have had a look through the documentation for Cargo, and have not been able to find the answer to my questions there. If you can point me at official documentation, that would also be great!

Correct assessment. Features are additive. You can disable the default features for my_library by setting default-features to false:

- my_library = { path = "../my_library", features=["xorshift"] }
+ my_library = { path = "../my_library", features=["xorshift"], default-features = false }

Thanks @jofas - I will drop Herbert a suggestion about this - he may wish to point it out in the final version of the book.

1 Like

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.