Hi,
when defining features for a Cargo package I questioned how I can define valid feature combinations.
For example lets imagine you have one or more supportive (backend) features, which can be used/consumed within other features. They could provide a service.
Then it's relatively simple to declare a dependency like this:
i.e. you can express that (a OR b) => c (in the case of an optional feature, you probably do not declare it as a dependency)
but you can't declare additional conditions about the inverse direction. i.e. it should not be allowed to enable c without a or b (i.e. c alone does not provide any value without a or b). c => (a OR b)
Is there a common approach to handle this by somehow disallowing invalid or unsupported feature combinations?
Cargo's features are unified across the entire dependency tree, so they're always a union all features requested anywhere, and aren't allowed to conflict.
You may get both a and b enabled at the same time and you can't prevent that (you could fail compilation, but it may be frustrating or impossible for a user to disable a feature force-enabled by some indirect dependency).
Thanks for the reply.
I know but I don't see how that example I've shown would contradict this. The first one is already possible in Rust and requires to enable service_feature_c if you compile with consuming_feature_a or b.
The second expression says a OR b not a XOR b, i.e. it would allow to compile with:
a, c
b, c
a, b, c
EDIT: only a, only b or both without c would be also valid
I see. Yeah, that would theoretically be possible. I don't think it can be done directly currently.
The closest thing Cargo has is dep?feature syntax that enables feature of depif the dep is already selected.
c = ["a?c", "b?c"]
but you'd rely on user enabling a or b anyway.
Alternatively, you can programmatically set custom cfg() from your crate's build.rs. You can detect if c is set and set a custom cfg(a) or cfg(b) based on whatever logic you want. This is only usable for conditional compilation, and can't add or remove optional dependencies.