rust-lang / cargo

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

Problems disabling a feature #3024

Closed djc closed 1 year ago

djc commented 8 years ago

Please have a look at https://github.com/servo/servo/pull/11812. I'm trying to disable a feature there so that the dependencies will not be built. However, nor me, nor Lars were able to get it to work, though I think we also didn't find a reason that it doesn't work. This suggests to me that there might be a Cargo issue.

alexcrichton commented 8 years ago

Hm sorry but I'm not sure I quite follow what's going on there. Is there a smaller example I could take a look at?

To explain a bit how features work, though, they work by essentially unioning all the requested features for a package. That is, if A depends on C and B depends on C, then the features activated in C will be those requested by both A and B.

The default feature is then requested by default for all dependencies, so if you want to turn it off then every single dependency on the package would have to turn off the default feature.

djc commented 8 years ago

servo depends on net, which depends on devices, which depends on blurz. I'd like to build devices without Bluetooth support, because I don't need it. I made it conditional in devices, and now I'd like to add features in net and servo to make it conditional, see https://github.com/servo/servo/pull/11812/commits/1b012b06435448ac3aca3eca3f0501aab9fff8ef. However, even when building servo with --no-default-features, it still seems to want to build blurz.

The servo > net > devices chain seems to be the only thing depending on blurz according to servo's Cargo.lock, so I don't think the union thing explains what's going on.

retep998 commented 8 years ago

@djc --no-default-features will only turn off the default features of servo itself. If devices has a feature to enable blurz, then anything which directly depends on devices has to opt out of that feature when depending on devices, possibly providing a feature to opt back in. In turn anything which depends on that dependency will have to provide a feature to opt in to that feature which opts in to that devices feature. The deeper this chain gets, the deeper the feature nesting hell becomes. There is no way to disable a feature from a dependency unless every single downstream dependency provides a chain of features to bring it all the way down to where you can opt out of it.

quininer commented 4 years ago

Any plans to solve this problem? This makes it impossible to turn off some optional default-features.

epage commented 1 year ago

Looking back over this issue, it feels like a mix of

Did I miss anything?

djc commented 1 year ago

@epage I think this is the core problem:

There is no way to disable a feature from a dependency unless every single downstream dependency provides a chain of features to bring it all the way down to where you can opt out of it.

I don't think any of your linked things describe a good solution to this particular problem?

(I also think the ability to selectively disable default-enabled features is somewhat related to this.)

epage commented 1 year ago

(I also think the ability to selectively disable default-enabled features is somewhat related to this.)

3126 is for selectively disabling default features and there is interest in it from at least a couple of us on the cargo team, we just haven't been able to prioritize it to write the RFC. Note that our proposal isn't to assert that the feature can never be present and automatically change things throughout but to allow you to express "I need everything in default except foo" recognizing something else might need "foo" and enable it. This is likely different than gentoo and likely won't help this situation.

I don't think any of your linked things describe a good solution to this particular problem?

Theoretically, every package on the way is declaring that it needs that feature, directly or indirectly, and so you need to tunnel up control to the top to express this.

Sometimes, the configurability isn't related to an API for the dependents but behavior for the application (how to link -sys crates is an easy example). This why I highlighted Pre-RFC Mutually-exclusive global features. With that proposal, a package can choose to express the behavior as a Global, instead of as a Feature, and the intermediate packages have no say in what happens.

The other area where theory breaks down is that it is too easy to depend on too many features because of defaults. Defaults serve to ease on boarding but they are out-of-sight and out-of-mind and can easily be left on, pulling in too much. This is why I wonder if #3126 us enough or if we also need something like rust-lang/rfcs#3347 (which I instead from as custom base features in addition to defaults ), with one serving more for applications / getting-started, and the other serving more for core libraries to make sure they only include the minimum.

Outside of those, I'm not really seeing a practical way of resolving this because this sounds like its about allowing packages or the user to break claimed invariants (even if unintended).

djc commented 1 year ago

Right, I think this issue in itself is probably not a good thing to focus on -- let's close it.