Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying dependencies per feature #5954

Closed
sdroege opened this issue Aug 31, 2018 · 10 comments
Closed

Allow specifying dependencies per feature #5954

sdroege opened this issue Aug 31, 2018 · 10 comments
Labels
A-features Area: features — conditional compilation A-optional-dependencies Area: dependencies with optional=true

Comments

@sdroege
Copy link
Contributor

sdroege commented Aug 31, 2018

Most feature-dependency correspondences can currently be modeled by making the dependency optional but having the feature depend on this.

This is not possible (from what I see) if "feature-a" and "feature-b" depend on the same crate but in different versions, as each crate can only be specified once.

A syntax like the following would seem consistent for that case (and could also provide another way of specifying feature-dependant dependencies in general).

[target.'cfg(feature = "feature-a")'.dependencies]
foobar = "0.1"

[target.'cfg(feature = "feature-b")'.dependencies]
foobar = "0.2"
@alexcrichton
Copy link
Member

I think that this may also largely be supported by #5653? May make it a bit easier to specify as well!

@updogliu
Copy link

updogliu commented May 8, 2019

@alexcrichton There might be dependencies that are relevant only for a certain feature. Is there a way to express that?

Edit:
There is already an example in the doc:
https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section

@mmstick
Copy link

mmstick commented Aug 5, 2019

Encountered a similar issue where a workspace is split into multiple sub-crates, and each rely on specifying shared features of the main crate dependency. Something like this doesn't seem to work at all:

[features]
default = [ "fwupd", "system76" ]
fwupd = []
system76 = []

[target.'cfg(all(not(feature = "fwupd"), feature = "system76"))'.dependencies]
firmware-manager = { path = "../", default-features = false, features = [ "system76" ] }

[target.'cfg(all(feature = "fwupd", not(feature = "system76")))'.dependencies]
firmware-manager = { path = "../", default-features = false, features = [ "fwupd" ] }

[target.'cfg(all(feature = "fwupd", feature = "system76"))'.dependencies]
firmware-manager = { path = "../", default-features = false, features = [ "fwupd", "system76" ] }
cargo build --manifest-path gtk/Cargo.toml --no-default-features --features system76

@sergiimk
Copy link

Hopefully this will save someone an hour of googling.

If you have a library a that depends on b, and you want to support two or more major versions of b that are slightly incompatible:

In a's Cargo.toml:

[dependencies]
b-5 = { package = "b", version = "^5", optional = true }
b-6 = { package = "b", version = "^6", optional = true }

[features]
default = ["use-b-6"]
use-b-5 = ["b-5"] 
use-b-6 = ["b-6"]

Create a b_shim.rs in a:

#[cfg(feature = "use-b-5")]
pub use b_5::*;
#[cfg(feature = "use-b-6")]
pub use b_6::*;

Instead of use b::foo import via crate::b_shim::foo.

Application that uses a can now chose to use it with older b by:

[dependencies]
b = "^5"
a = { version = "*", default-features = false, features = ["use-b-5"] }

This is more work than it should be....

@epage
Copy link
Contributor

epage commented Oct 24, 2023

With package renaming, we've satisfied the main request and there is a great example just above of that.

As for this case

[features]
default = [ "fwupd", "system76" ]
fwupd = []
system76 = []

[target.'cfg(all(not(feature = "fwupd"), feature = "system76"))'.dependencies]
firmware-manager = { path = "../", default-features = false, features = [ "system76" ] }

[target.'cfg(all(feature = "fwupd", not(feature = "system76")))'.dependencies]
firmware-manager = { path = "../", default-features = false, features = [ "fwupd" ] }

[target.'cfg(all(feature = "fwupd", feature = "system76"))'.dependencies]
firmware-manager = { path = "../", default-features = false, features = [ "fwupd", "system76" ] }

that can be done as

[features]
default = [ "fwupd", "system76" ]
fwupd = ["dep:firmware-manager", "firmware-manager/fwupd"]
system76 = ["dep:firmware-manager", "firmware-manager/system76"]

[dependencies]
firmware-manager = { path = "../", default-features = false, optional = true }

As this seems resolved, I'm closing it. If there is a reason to re-open this, let us know!

@epage epage closed this as not planned Won't fix, can't repro, duplicate, stale Oct 24, 2023
@nathanielsimard
Copy link

I need to use something like that but for a different use case. I need to activate a feature flag on a dependency when that dependency is activated and the other feature flag is activated as well:

[features]
flag1 = ["crate1"]
flag2 = ["crate2"]
someflag = []

[target.'cfg(all(feature = "flag1",  feature = "someflag"))'.dependencies]
crate1 = { ..., features = ["someflag"] }

[target.'cfg(all(feature = "flag1",  not(feature = "someflag")))'.dependencies]
crate1 = { ..., features = [] }

[target.'cfg(all(feature = "flag2",  feature = "someflag"))'.dependencies]
crate2 = { ..., features = ["someflag"] }

[target.'cfg(all(feature = "flag2",  not(feature = "someflag")))'.dependencies]
crate2 = { ..., features = ["someflag"] }

If I do something like this:

[features]
flag1 = ["crate1"]
flag2 = ["crate2"]
someflag = ["crate1/someflag", "crate2/someflag"]

Then both crates are going to be activated when only the flag someflag is activated.

@epage
Copy link
Contributor

epage commented Nov 9, 2023

Is weak features what you need?

someflag = ["crate1?/someflag", "crate2?/someflag"]

@nathanielsimard
Copy link

@epage Yes exactly! I didn't know it even existed, thanks a lot 🙏

@Sytten
Copy link

Sytten commented Jul 11, 2024

There is still a use case that is not covered with the weak feature. @epage

[features]
default = ["myfeature"]
myfeature = []
simd = []

[target.'cfg(all(feature = "simd",  feature = "myfeature"))'.dependencies]
base64-simd = "0.8.0"

[target.'cfg(all(not(feature = "simd"),  feature = "myfeature"))'.dependencies]
base64 = "0.22.0"

I know you can do myfeature and myfeature-simd, but it really is not that nice especially if you have multiple features that can have a simd variant.

@epage
Copy link
Contributor

epage commented Jul 11, 2024

@Sytten Sytten mentioned this issue Jul 12, 2024
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-features Area: features — conditional compilation A-optional-dependencies Area: dependencies with optional=true
Projects
None yet
Development

No branches or pull requests

9 participants