rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.83k stars 2.42k forks source link

Allow arbitrary Horn clauses for inter-feature dependencies. #6789

Open hvenev opened 5 years ago

hvenev commented 5 years ago

Sometimes it makes sense to enable feature Z if both features Y and feature Z are enabled. Simple example: #6658

[dependencies]
krate = { optional = true, version = "1.2.3" }

[features]
bar = []
foo = [ "krate" ]
"foo+bar" = [ "krate/bar" ]

Another example pops up in native library bindings:

name = "libB-sys"

[dependencies]
libA-sys = { optional = true, version = "4.5.6" } # libA is used by libB to do featX

[features]
vendored = [] # Build the bundled copy of the library instead of using the system one
featX = []
"vendored+featX" = "libA-sys"

It may also make sense to have clauses where resolution fails:

[features]
"do-it-this-way+do-it-that-way" = false

Note that this does not permit requirements of the form "featX or featY must be enabled". The naive algorithm that only enables a feature when all prerequisites are enabled still works (https://www.doc.ic.ac.uk/~rak/papers/kowalski-van_emden.pdf, the "model intersection property")

epage commented 1 year ago

"do-it-this-way+do-it-that-way" = false

This runs afoul of feature unification. We have #2980 discussing the use cases further with https://internals.rust-lang.org/t/pre-rfc-mutually-excusive-global-features/19618 as a concrete proposal.

epage commented 1 year ago
[dependencies]
krate = { optional = true, version = "1.2.3" }

[features]
bar = []
foo = [ "krate" ]
"foo+bar" = [ "krate/bar" ]

I believe this would now be solved by

[dependencies]
krate = { optional = true, version = "1.2.3" }

[features]
bar = ["krate?/bar"]
foo = [ "krate" ]

See https://doc.rust-lang.org/cargo/reference/features.html#dependency-features for more on ? (weak features)