Closed djc closed 1 year 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.
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.
@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.
Any plans to solve this problem? This makes it impossible to turn off some optional default-features
.
Looking back over this issue, it feels like a mix of
Did I miss anything?
@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.)
(I also think the ability to selectively disable default-enabled features is somewhat related to this.)
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).
Right, I think this issue in itself is probably not a good thing to focus on -- let's close it.
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.