"conditional compilation" in rust doesn't meet my requirements

Hi, there:

There is my requirements:

  • compile a specified version of a function based on command line arguments

The ideal code should be like this:

#[cfg(algorithm = "a")]
fn foo() {...}

#[cfg(algorithm = "b")]
fn foo() {...}

Than I can test them via:

cargo test --cfg algorithm = "a" ...
cargo test --cfg algorithm = "b" ...

But according to my study, it seems impossible:

The problem with "features" is:

  • I cannot set key-value inside it

The background of my issue is, my database project implemented various latch strategies, and I want to test them one by one.

Features don't have key-value semantics, because cargo unifies them acress your dependency graph. I'd do a feature per algorithm, so that the user can choose which of them are compiled in. You can then provide a wrapper function that calls one of the algorithms using some logic to decide between them.

#[cfg(algorithm_a)]
fn foo_a() {
    todo!()
}

#[cfg(algorithm_b)]
fn foo_b() {
    todo!()
}

#[cfg(any(algorithm_a, algorithm_b))]
fn foo() {
    if cfg!(algorithm_a) {
        foo_a()
    } else {
        foo_b()
    }
}

An alternative design could include a trait that defines the functionality you need, with different implementations behind cfg-flags. You can then use generics to write most of your code abstracted over a specific implementation.

1 Like

Features are indeed unified and not supposed to be exclusive. There is however some work ongoing with adding exclusive features. As far as I know this pre-RFC is as far as it has gotten: Pre-RFC: Mutually-excusive, global features - cargo - Rust Internals

1 Like

If this is a binary project and not a library, this can still be a reasonable choice. It will not be nice to compilation (since it's a globally transitive setting), but setting the environment variable RUSTFLAGS to --cfg=algorithm=a will make cfg(algorithm = "a") pass in every crate in the entire compilation graph.

However, note that both cfg(algorithm = "a") and cfg(algorithm = "b") can still be set together; cfg keys can be multivalued. If you're using RUSTFLAGS it's on you to not do anything silly like set cfg(unix) on a non-Unix target.

The "most correct" solution is to make the choice of algorithm a trait implementation provided by simple dependency injection by function argument, as then enabling the features is addictive.

5 Likes