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

Tracking Issue for weak dependency features #8832

Closed
2 of 3 tasks
ehuss opened this issue Nov 4, 2020 · 39 comments · Fixed by #10269
Closed
2 of 3 tasks

Tracking Issue for weak dependency features #8832

ehuss opened this issue Nov 4, 2020 · 39 comments · Fixed by #10269
Assignees
Labels
A-features Area: features — conditional compilation C-tracking-issue Category: A tracking issue for something unstable.

Comments

@ehuss
Copy link
Contributor

ehuss commented Nov 4, 2020

Summary

Original issue: #3494
Implementation: #8818
Documentation: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#weak-dependency-features

-Z weak-dep-features will enable "weak" dependency features, whereby dep_name?/feature_name syntax in the [features] table will not automatically enable the dep_name dependency (unlike the dep_name/feature_name syntax which always enables dep_name). This just indicates that the feature on that dependency should be enabled if something else enables that dependency on this package.

Unresolved issues

  • Bike shed the syntax. We've discussed various variants:
    • dep_name?/feat_name
    • ?dep_name/feat_name
    • dep_name?feat_name
    • Or maybe something more verbose like {dep="dep_name", feature="feat_name", enable-dep=false}
    • Or a more verbose string format, like if-dep:dep_name/feat_name (read this as "if dependency foo then enable feature bar").
    • Concerns:
      • Too verbose, and people may be less likely to use it.
      • Terse ? format means people will have to look up what it means, and searching for punctuation is difficult.
      • Interaction with org_name/pkg_name syntax, which could contribute to the punctuation soup.
  • Possibly make this the default behavior for dep_name/feat_name syntax on an edition boundary. A concern is that this is not an (easily) rustfix-able change.
  • Figure out how to deal with breakage of Cargo versions older than 1.19. Resolved in Add schema field and features2 to the index. #9161.

About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

@ehuss ehuss added A-features Area: features — conditional compilation C-tracking-issue Category: A tracking issue for something unstable. labels Nov 4, 2020
@mehcode
Copy link

mehcode commented Nov 12, 2020

Possibly make this the default behavior for dep_name/feat_name syntax on an edition boundary [...]

I think is the best option if we can make it work.

foo = [ "bar/baz" ] # just /baz if bar is activated
foo = [ "bar", "bar/baz" ] # bar and bar/baz

@est31
Copy link
Member

est31 commented Nov 12, 2020

@mehcode I think the issue is that due to the way it's built, rustfix knows nothing about Cargo.toml, thus cargo fix does neither. I guess the solution would be to extend cargo fix to also change Cargo.toml. That would work but is non-trivial. I think https://github.com/matklad/tom might be useful here.

@KamilaBorowska
Copy link

KamilaBorowska commented Nov 21, 2020

In my opinion we shouldn't have a syntax for this feature, instead a programmer could use "foo/bar" directly. There is a compatibility concern by doing so, but it could be dealt with by providing a warning when a dependency feature is used without depending on a dependency itself.

For example, in this case there would be no warning as feature b depends on lib.

a = ["lib"]
b = ["a", "lib/feature"]

However, without depending directly or indirectly on a dependency there would be a warning.

b = ["lib/feature"]

Then in a future edition of Rust the behaviour would change so that having "lib/feature" feature wouldn't enable "lib" feature.

@alexcrichton
Copy link
Member

@xfix FWIW we wanted to avoid that because it means the meaning of a/b differs depending on whose lockfile you're looking at. We thought that would be too confusing because a/b has been a feature of Cargo for so long. That's what pushed us to find a different syntax.

(although what you describe I believe is technically feasible, our hesitation was just about the confusion of having the same syntax mean two different things depending on the context)

@est31
Copy link
Member

est31 commented Nov 23, 2020

differs depending on whose lockfile you're looking at.

@alexcrichton you mean Cargo.toml? lockfiles can be shared by crates of different editions and they also don't have the a/b syntax anywhere.

@KamilaBorowska
Copy link

KamilaBorowska commented Nov 23, 2020

I think having the same syntax could be balanced by having a warning when using the syntax in older editions - so there would be only a single behavior that doesn't cause a warning. Also, I think the behaviour of a/b feature enabling a optional dependency is somewhat surprising.

Add to that we can implement a warning now, we don't have to wait for Edition 2021 or something like that - a warning could be dealt with by replacing "a/b" with "a", "a/b" - this works even in Rust 1.0.

From a list of 30 most popular dependencies (by recent downloads) on crates.io I found that the 2 crates unintentionally enable optional features.

  • rand unintentionally enables rand_chacha with std feature

    std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
  • syn unintentionally enables quote with proc-macro feature

    proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"]

On the other hand log has a feature called kv_unstable_sval which enables sval dependency by saying sval/fmt.

kv_unstable_sval = ["kv_unstable", "sval/fmt"]

However log could easily deal with a suggested warning by doing the following instead.

kv_unstable_sval = ["kv_unstable", "sval", "sval/fmt"]

In fact, rand_core is already doing something similar. It technically doesn't need to specify "getrandom", but does it anyway.

std = ["alloc", "getrandom", "getrandom/std"]

@alexcrichton
Copy link
Member

Er yes I meant the manifest, not the lock file. @xfix that's perhaps plausible to simply warn, but that's also a massive task to force the entire Rust community to relearn a feature they already know. There's a very real cost to that which isn't present if we pick a new syntax.

@est31
Copy link
Member

est31 commented Nov 24, 2020

Personally I think that warning or not, switching it without an opt-in of either an edition or special syntax is a violation of Rust's stability guarantees. I support the idea of changing the syntax on a edition boundary, but I think this feature is too useful to wait for a new edition, or be even blocked by a discussion about the syntax :). First it can be introduced with the new custom syntax, then later one can decide whether the new edition should switch to it by default. Also there is the question of interactions between the RFC to do workspace sharing of information and having heterogenous edition choices inside a workspace.

@vorot93
Copy link

vorot93 commented Dec 9, 2020

@alexcrichton From my experience, the current behavior is not really an expected one, but an unfortunate gotcha that I discovered independently. I'm strongly in favor of changing dep_name/feature syntax behavior in edition 2021.

@joshtriplett
Copy link
Member

I think we need to have a distinct syntax for this, even in a new edition. I don't think we should go directly from one meaning of abc/xyz to another.

@joshtriplett
Copy link
Member

Now that the new feature resolver has gone in, are there any blockers preventing us from stabilizing this once we're confident it works as intended?

I think we bikeshedded the syntax fairly extensively in the Cargo meetings. abc?/xyz feels like it has the right degree of orthogonality, such that / keeps the same meaning and the addition of ? means "optional".

I also think we need to give people some guidance about how soon after stabilization they can safely start using this in popular crates. For instance, I'd really like to use this in git2, but that's in the dependency trees of many crates; how long after release would it be reasonable to start using it?

@jhpratt
Copy link
Member

jhpratt commented Dec 24, 2020

With regard to how long before using, why would this be any different than any other MSRV change? I just checked the code for the time crate, and the main branch could use this (not any current release, though). I'd just hold out six months per my MSRV policy.

@Nemo157
Copy link
Member

Nemo157 commented Dec 24, 2020

Features go into the index, will this cause any issues with older cargo's loading older versions of a crate which has started using it in a new version?

@Eh2406
Copy link
Contributor

Eh2406 commented Dec 24, 2020

@Nemo157 In general the Resolver is pretty good at not picking versions that contain things it does not understand. But now that you mention it we should definitely test in this case.

@ehuss
Copy link
Contributor Author

ehuss commented Dec 24, 2020

are there any blockers preventing us from stabilizing

The path to stabilization is:

  1. Testing and feedback.
  2. Decide on the syntax.
  3. Decide if the index format change is OK.
  4. Update crates.io to accept the syntax.
  5. Stabilize and document.

The testing phase is important, because enabling this causes Cargo to use the new feature resolver in "classic" mode when resolver = "1". I've tested it a fair bit, and I am unaware of any issues, but it is a big change. Anyone can test it by setting the environment variable __CARGO_FORCE_NEW_FEATURES=compare, which will compare the results of the old and new resolver, and panic if they are not identical. I did that on a bunch of projects, but the edge cases normally arise when using unusual combinations of flags that I did not test (aside from Cargo's own test suite of about 2,000 tests).

we need to give people some guidance about how soon after stabilization

I'm not sure how feasible or useful that guidance could be. Projects have widely different MSRV policies, and it's a choice they have to make based on the level of support they want to and can feasibly provide. Whatever they choose is valid, and I'm not sure we can imply with a recommendation that their choice isn't a good one. If I only want to support the latest stable, that shouldn't be shunned. Just like if someone wants to support 2 year old releases, and they need to reject PRs because it violates that choice, I think that choice is valid and shouldn't be discouraged.

For git2, I think Alex is relatively aggressive on using newer releases than most projects (stable-1 I think).

will this cause any issues with older cargo's loading older versions of a crate which has started using it in a new version?

Those packages are mostly ignored by older cargos. There's a test for this here (although that is not directly testing older cargos, the concept is the same). I just checked, and it works starting with version 1.19 (released 2017-07-20). Prior versions fail with a parse error. We don't have an explicit timeframe in our compatibility policy (per https://doc.crates.io/contrib/design.html#forwards-compatibility). I think a minimum of 2 years isn't bad, but we haven't discussed it much.

@joshtriplett
Copy link
Member

@jhpratt wrote:

With regard to how long before using, why would this be any different than any other MSRV change?

@Nemo157 wrote:

Features go into the index, will this cause any issues with older cargo's loading older versions of a crate which has started using it in a new version?

This was the exact concern that motivated the suggestion to give people guidance. I'm not suggesting that such guidance would tell people what their MSRV (or MSCV) policy should be. Rather, I think we need guidance (supported by testing) along the lines of "There are no special compatibility considerations here, you can follow your normal MSRV policy". I want to make sure people know that if they release a new version of their crate that uses this feature, they won't break people who are using older versions of their crate.

@ehuss wrote:

Those packages are mostly ignored by older cargos. There's a test for this here (although that is not directly testing older cargos, the concept is the same). I just checked, and it works starting with version 1.19 (released 2017-07-20).

Thank you for testing that! That's exactly the kind of guidance I think people will need to be able to use this feature confidently.

Decide on the syntax.

We had a couple of fairly detailed discussions about syntax and orthogonality, which seemed to reach a consensus on the ?/ syntax. Is this still an open question?

Decide if the index format change is OK.
Update crates.io to accept the syntax.

Makes sense. Given that people can use this feature on nightly, this seems like it should happen in parallel with testing and feedback.

I've also submitted #9015 as draft documentation for the features section of the reference.

@est31
Copy link
Member

est31 commented Dec 25, 2020

I just checked, and it works starting with version 1.19 (released 2017-07-20). Prior versions fail with a parse error. We don't have an explicit timeframe in our compatibility policy (per https://doc.crates.io/contrib/design.html#forwards-compatibility). I think a minimum of 2 years isn't bad, but we haven't discussed it much.

I think that's a problem. It's one thing to have crates on crates.io break support with older cargos, it's another thing to have those older cargos be broken even if they only use an older version of the crates. Is there a way to make the feature fail in a better way for those older cargos?

@ehuss
Copy link
Contributor Author

ehuss commented Dec 26, 2020

Is this still an open question?

I think it is still open to be changed. There has been almost no feedback from users about this change, other than the 3 people who have commented here not liking the syntax.

Is there a way to make the feature fail in a better way for those older cargos?

I don't immediately have any ideas on how to make that work.

I realize that it can be painful to break old versions of software. I'm not sure if 1.19 is old enough to draw the line. Older versions could still be used with --frozen, careful vendoring, or using an older copy of the index. I do feel that 4 years might not be enough time. I don't think the index can remain compatible forever, but we haven't decided on a reasonable timeframe.

@Eh2406
Copy link
Contributor

Eh2406 commented Dec 26, 2020

How hard would it be to implement a separate "features-weak" map in the index serialization? Somehow keeping the new kind of features in a new table? Ether just the weak items, or the elements activate the weak items, or the entire thing (if there are any weak items then the hole map is call "features-weak" instead of "features").

@ehuss
Copy link
Contributor Author

ehuss commented Dec 26, 2020

There are two issues with that. One is that older cargos would ignore the field, and possibly end up resolving the features incorrectly (which may or may not work in practice). The other is that the features would still be listed in the [features] table of Cargo.toml, and the older Cargo's would fail to parse the manifest (though that won't be a problem if the project is locked to an older version).

If we want to have the rule that older Cargos will work as long as they have a Cargo.lock file, that may be a sufficient fix.

@tarcieri
Copy link

There has been almost no feedback from users about this change, other than the 3 people who have commented here not liking the syntax.

Put me down as a user who does like the abc?/xyz syntax.

@CryZe
Copy link

CryZe commented Dec 26, 2020

I'd say the ? syntax is acceptable as a short-term solution, but it should become the default behavior in some future edition or so. Everyone is surprised by the current default behavior.

@Eh2406
Copy link
Contributor

Eh2406 commented Dec 26, 2020

@ehuss Both of those are only problems if old Cargo selects a version that uses the new functionality, and I am ok with old Cargos braking if it trys to build a new crate. My (and I think @est31) concern is that and old Cargo that has a dep on and old version will stop working because Cargo can not read the index where a new unselected version uses the new sintaks. Maybe we have misunderstood your comment "Prior versions fail with a parse error."

Here is the test case I am worried about:
s = 1.0 does not use weak.
s = 2.0 uses weak.
root depends on s="1.0", can it be built with Cargo pre 1.19?

@jhpratt
Copy link
Member

jhpratt commented Aug 9, 2021

Anything holding up actually stabilizing this now that the RFC was merged?

@ehuss
Copy link
Contributor Author

ehuss commented Aug 9, 2021

There's a fair lot of work to update crates.io, and perform testing. I may work on it this week, but it may be a long while before it hits stable.

davidtwco added a commit to rust-lang/thorin that referenced this issue Dec 7, 2021
`fallible-iterator` doesn't need to be a dependency, it is pulled in by
`gimli/std` which can't be fixed without rust-lang/cargo#8832.

Signed-off-by: David Wood <david.wood@huawei.com>
davidtwco added a commit to rust-lang/thorin that referenced this issue Dec 7, 2021
`fallible-iterator` doesn't need to be a dependency, it is pulled in by
`gimli/std` which can't be fixed without rust-lang/cargo#8832.

Signed-off-by: David Wood <david.wood@huawei.com>
@jhpratt
Copy link
Member

jhpratt commented Dec 15, 2021

No rush, but @ehuss just wondering if you have made any progress on this front?

@ehuss
Copy link
Contributor Author

ehuss commented Dec 21, 2021

It is just waiting on rust-lang/crates.io#3867.

@jhpratt
Copy link
Member

jhpratt commented Dec 30, 2021

Time for FCP now that that PR was merged?

Thank you for your hard work @ehuss! It truly is appreciated.

@ehuss
Copy link
Contributor Author

ehuss commented Jan 6, 2022

Posted #10269 as a proposal to stabilized this.

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 C-tracking-issue Category: A tracking issue for something unstable.
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.