-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Specify Rust compatibility of nursery crates #1619
Conversation
Currently there is unfortunately not a clear guideline for what the compatibility of all rust-lang-nursery crates are. The purpose of this change is to set forth such a guideline to ensure that the nursery crates are all consistent. It may also likely be the case that many other crates in the community wish to follow such a policy as well. This change proposes that all nursery crates are compatible with the **previous two stable releases** of the compiler. For example, if 1.10 is the current release then all crates are guaranteed to compile on 1.8 and 1.9. Nursery crates may compile on older versions, but this is not a guarantee nor can it be relied on.
cc @rust-lang/libs |
Would it be helpful to clarify that the minimum Rust version can be increased via a semver compatible version bump? For example, a crate at version cc @DanielKeep |
@BurntSushi Yes, that's a good idea. Also, note that this is a proposal for an initial policy, while Rust is still very rapidly evolving. As things slow down, we've talked about possibilities like LTS (long-term support) releases, which could provide a clear point of agreement across the ecosystem in terms of old versions of Rust to maintain compat with. Likewise, we'd also like to explore tools for |
Agreed, I added some text saying that bumping the version isn't a breaking change |
Other than this means it's going to take a really long time to use associated constants in bitflags :), sounds good! |
What about full |
For future crates which are ready to ascend to the nursery, is this to be considered a prerequisite? Or will they have some time to adjust? Either approach seems ok to me, but probably good to make explicit. |
I think it's fine if a crate enters the nursery running on a "too modern" rust, but it would then have to hold back on upgrades until the right number of new releases have landed. |
I assume it's okay for a nursery crate to flag functionality that requires a new version of rust behind a feature? Do we want to guarantee that it's possible to build a nursery crate 2 versions back or that it will by default? Can a crate have a dependency with a version range that includes releases that build on only new Rust (e.g. |
@huonw I've added a note explicitly saying that we'll probably follow LTS if they ever exist, but also just noting that this policy may change. I would personally expect rust-lang to be held to the same standard, e.g. those crates must compile on at least 2 older releases for now. Note that in practice the only example of this right now is the libc crate which compiles on 1.0+, so it's not really an issue yet :) @nrc, @sfackler I'd personally consider this a gate to moving in the nursery. That is, if you don't compile on the current 2 older stable releases, you'll have to wait to get promoted or add in API changes to fix compatibility. @sfackler yeah I added some wording saying that by default the current version must compile on the current release an 2 older ones, but I personally think it's fine to have off-by-default features which break that compatibility. |
be dropped if it was before two stable releases ago (e.g. by updating the | ||
continuous integration configuration), or the change must wait to land | ||
otherwise. If the minimum vesion of Rust is increased then this is not | ||
considered a breaking change (e.g. does not require a new major release). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
femtonit: ie rather than eg
Should something be added to RFC 1291 to specify a policy for libc? |
the current stable release is 1.10, all nursery crates will compile successfully | ||
on both 1.8 and 1.9. Some nursery crates may compile on older versions, but this | ||
is not guaranteed and changes to the crate are allowed which bump the minimum | ||
rustc version requirement. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rewording suggestion:
The most recent version of a rust-lang-nursery crate is guaranteed to compile on the current release of Rust, as well as the two previous stable releases. For example, if the current stable release of Rust is 1.10, all nursery crates will compile successfully on both 1.8 and 1.9 in addition to 1.10. Nursery crates may compile on older releases of Rust, but this is not guaranteed and cannot be relied on. Changes to nursery crates that increase the minimum supported Rust release are explicitly allowed, and are considered semver compatible changes: they do not require a major version bump for the nursery crate.
Forgive the surface level suggestions, I just found the first paragraph a bit hard to follow on first read. Are we only guaranteeing that the crates compile? Or should we also specify they pass their test suite on some set of platforms, say tier 1? Changes that don't meet that are probably pathological, but for completeness' sake. |
Ah yeah it was implicit that crates run tests as well as compiling, and yes it was also somewhat implicit that this is intended for tier 1 platforms currently. |
🔔 This RFC is now entering its week-long final comment period 🔔 The libs team is leaning towards merging this as-is (compatible two versions back), but we're always open to comments! |
I'm fine with "we only promise to explicitly support the last two releases", but I just wanted to point out that there are people out there still distributing What I'm not fine with is breaking backward compatibility not requiring a semver bump. This means I can (for example) check out code that is known to compile with Rust 1.4, compile it with a Rust 1.4 compiler, and have the build fail. To me, this completely undermines the point of following semver in the first place. If the crate ecosystem had metadata about what version of the language a crate needed to compile (something I proposed prior to 1.0, but which was deemed unnecessary), this wouldn't be an issue, but it doesn't and it is. I am tired of having code just break because some transitive dependency three levels deep pushed a new minor version that causes the build to fail, and then I have to start bisecting transitive dependencies to try and figure out the exact version where everything caught fire (I don't update dependencies on a regular basis in part because of this issue), and then I have to hack the manifest to exclude the incompatible versions because I bothered to promise I'd support old versions of Rust, but oh wait, one of the dependencies in the middle has a broad version range and Cargo refuses to select the old one I want so now I have to roll that back as well and oh god it never ends please someone kill me! Hell, I can't even just make a new release with a higher version requirement, because changes in dependencies can retroactively break old releases, which to my mind is utterly unacceptable. I am terrified of To be honest, if you aren't going to try and make sure old code continues to compile, I don't see the point in saying you follow semver. Either back compat matters, or it doesn't; you can't have it "kind of matter for a little while, but after 3 months you're on your own". Apologies if this has offended anyone, but this is something I feel extremely strongly about. |
@DanielKeep it seems untenable to me to say that any semver-compatible series of a nursery crate remains compatible with one version of Rust forever. This means that if the crates ever hit 1.0 they'll never be able to take advantage of new language features until the crates hit 2.0. The idea in this RFC was to say that "two releases back" is sufficiently old enough for basically anyone at this point. If it turns out that there are major distributions lagging quite behind then we can perhaps change that number. It should also be pointed out that most nursery crates will end up supporting much older than two versions as they don't change that often. It may also be worth separating out some of the concerns you're talking about. "Random changes to the dependency graph" should never happen in Cargo with a Cargo.lock, which is highly recommended for all applications. Libraries themselves are affected by semver upgrades, but that's an entirely different story as well. |
This is not really true; As a secondary riposte: so what if you have to bump semver? They're just numbers; it's not like we're in any real danger of running out of versions.
Well, I'm not sure they are separable, but I'll try. First of all, I care about backward compatibility. If it's reasonable to support old versions of Rust, I'll do so. I want to support all reasonably "in the wild" versions at a minimum. I want someone who has (picked at random) 1.7 on their machine to look at my crates and programs, see that it's supported, and be confident that they can compile and use said crates and programs. Problems that this policy (specifically in regards to not bumping semver when breaking support with old versions of the language) may and/or will cause:
The "proper" solution to this would be to teach Cargo about language versions; in that case, this whole issue just vanishes because Cargo wouldn't select incompatible versions in the first place. But it doesn't; the only two ways these problems can be fixed is to either have crate maintainers break semver when they break compatibility, or having downstream users manually hack version ranges into their manifests, doing the legwork themselves. At the end of the day, what I want is for working code I wrote to continue working both for myself and for others without having to actively fight the package ecosystem and tooling. |
Annotating crates with their supported Rust versions seems like a good idea regardless of this RFC, but I would note that Cargo's dependency graph resolution logic is already fairly naive, and adding more constraints may worsen things there even more until someone gets around to integrating a SAT solver so we can do it right. |
#1133 effectively adds language deps as long as std evolves in lockstep with the language. |
Using compiler detection is just another way of introducing silent dependencies if you don't even have to opt-in to the "new features enabled by a new compiler". All existing libraries still may have to bend over backwards to provide a backwards-compatible interface and it may not even always be possible (e.g. language features like specialization). Also semver is not just numbers, there is a very real cost to bumping the major version. Each major version bump introduces a split in the ecosystem for who's on what version. This was very readily apparently when libc when from 0.1 to 0.2, a dependency which is shared among many crates. The more crates a type is reexported in as a public API, the harder it is to bump the major version of that type. The libc crate is an extreme case where it's in nearly every public API, but it suffices to say that bumping semver versions is not at all free. This is then compounded with the fact that nursery crates are intended to indeed be the reexported types in public APIs quite broadly. Crates like I think that there's still a lot of conflation of ideas in what you're talking about as well:
It seems fine that we'd want Cargo to learn about language versions, especially if it culls candidates from resolution based on this. That seems like a separate feature though, and one that doesn't block this RFC. It can be an independent policy that the nursery crates all provide a bare minimum of 2 versions back of compatibility, and perhaps more. If we gain the ability to write down in Cargo.toml what the minimum version is, then we can start doing so. |
@alexcrichton I don't think an automatic detection system is required, or even desired. A simple This is getting off on a bit of a tangent though. |
I share the concern about minor point releases being able to break old versions of rust. It is a semver violation in my opinion. I think if we actually find ourselves in a situation where we are going to break an old version of Rust by doing a minor version bump then we should stop and think hard about the tradeoffs. This policy shouldn't be a blanket mandate to break things, but I also think that some policy is better than the status quo. |
I do share @brson's and @DanielKeep's concerns about permitting a new required minimum version of Rust in a semver compatible version bump. I think there are a couple key trade offs and issues at play (that @alexcrichton mentioned):
The above two points seem to be in direct competition with each other. With that said, I do think it's within our discretion to define this policy. Additionally, I do feel like the current state of the community is that most folks are updating to new Rust releases, which I think suggests the policy in this RFC strikes a decent enough balance. The RFC does mention that this policy should be reconsidered in the future, particularly if more parts of the community stay on older versions of Rust. I am of course in favor of the less controversial points, which is that we have a policy saying something about the minimum Rust version supported by our official crates. @alexcrichton Could you maybe talk a bit more about the viability of specifying a minimum Rust version in the |
Personally, the way I see this policy is that it's good for now, and can be revised later. Right now, there's no guarantee; so making it two releases back is an improvement. And ideally, someday, we end up with LTS Rust releases, and the policy can be changed to coincide with that. |
@steveklabnik To be clear, I think guaranteeing two releases back is the uncontroversial part of this. :-) The specific bit that is causing trouble is requiring a new minimum Rust version for a crate wouldn't require a semver major version bump (as the RFC is currently written). |
@BurntSushi yeah sorry, I guess I wasn't as clear; it's the same thing for both. Right now, there's zero policy, I'd prefer this to getting dragged down over a relatively small point. This kind of thing has always been a tricky point; I've seen it in other ecosystems as well. Each project kind of picks whatever they want with regards to semver; I've done both options before. One of the problems with "dropping a language version is a major bump" is when you don't intend to ever release a new major version, yet the old language versions have been EOL'd. I have one project that's still on Ruby 1.8.7 for this reason... We're facing a similar problem here. That's one reason why I mentioned the LTS bit. |
I agree strongly w/ @DanielKeep and @brson. Not having a semver bump when a rustc version is deprecated will result in breaking down stream code. I personally take backwards compatibility very seriously, In Mio, I explicitly run CI using the oldest supported version of rust (https://github.com/carllerche/mio/blob/master/.travis.yml#L5-L7). It has happened in the past that my build as broken due to a downstream library silently deprecating the version of Rust that Mio supports. If silently deprecating rustc versions becomes the norm, what will happen is that libraries that take backwards compatibility seriously will start having to special case these versions in their dependencies. Aka, having to depend on "libc <= 0.2.13". This seems like a far worse outcome. Making a semver bump should be cheap. I also respectfully disagree w/ @steveklabnik's opinion that something is better than nothing. The greater rust community looks to the rust team for leadership, and policies like these have a far greater impact than just how the rust nursery is managed. Once a policy is set, it will become spread out into the community as a model and gain momentum. It will be significantly harder to amend the RFC than set it initially. |
Apparently @othiym23 has some strong feelings about how this works in node: https://twitter.com/othiym23/status/762679697914245121 |
Ok wrote #1709 with motivation from this thread. |
The libs team discussed this RFC during triage yesterday and the decision was to close. The crux of this RFC is that updating the minimum required version of Rust is not a semver-breaking change, which seems to be the most contentious point. This in turn is tied closely enough to other features like LTS releases or Cargo understanding the minimum language version for crates. As a result the policy would likely change here as soon as those are implemented, so our thinking is we can just wait to reformulate this policy once one of those is implemented. |
Currently there is unfortunately not a clear guideline for what the
compatibility of all rust-lang-nursery crates are. The purpose of this change is
to set forth such a guideline to ensure that the nursery crates are all
consistent. It may also likely be the case that many other crates in the
community wish to follow such a policy as well.
This change proposes that all nursery crates are compatible with the previous
two stable releases of the compiler. For example, if 1.10 is the current
release then all crates are guaranteed to compile on 1.8 and 1.9. Nursery crates
may compile on older versions, but this is not a guarantee nor can it be relied
on.