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

Rust Roadmap: libc v1.0 release #547

Open
coder543 opened this issue Mar 3, 2017 · 53 comments
Open

Rust Roadmap: libc v1.0 release #547

coder543 opened this issue Mar 3, 2017 · 53 comments
Milestone

Comments

@coder543
Copy link

coder543 commented Mar 3, 2017

Therefore, it follows logically that libc must have a v1.0 release according to the Rust roadmap.

I am opening this issue so that a plan can be formulated and then executed upon.

  • What would it take to get libc to v1.0?
    • I see some issues marked as 1.0-breakage, so those would need to be done, but it looks like people are holding off on doing them until closer to the currently-nebulous release date for v1.0.
  • When should a v1.0 release happen?
    • We could wait until the end of the year, or we could go ahead and make good on this portion of the roadmap, starting with libc.
@lambda
Copy link
Contributor

lambda commented Mar 3, 2017

Aside from the issues tagged 1.0-breakage, which seem simple enough to deal with, I think that the big outstanding question is #180, that libc's c_void is not the same type as std's c_void (also filed as rust-lang/rust#31536). There's been some substantial discussion of this on internals, and there is an active RFC with considerably more discussion.

@SimonSapin
Copy link
Contributor

I’m very opposed to making a 1.0 release just because. Upgrading from 0.1 to 0.2 was a huge pain. In Servo we had to coordinate upgrades of 52 dependencies: servo/servo#8608. Upgrading only some dependency but not others would cause build errors because they typically use some libc type (like c_void) in their public API.

And wasn’t just Servo. crates.io lists 1210 reverse dependencies for libc now.

I think that a much better justification than just getting a nicer-looking version number should be needed to force the ecosystem to go through that again.

@coder543
Copy link
Author

coder543 commented Mar 3, 2017

I'm very opposed to making a 1.0 release just because.

It's on the official Rust Roadmap. It's very hard to argue that libc isn't essential. The reasoning is detailed on the issue here. That alone should be reasoning enough to do the upgrade.

However, @lambda has pointed out that issue #180 needs to be resolved. If #180 were resolved, that would be a significant change, and that should warrant a big upgrade, should it not? So, one way or another, this needs to happen in 2017, and maybe we can make a significant fix to the c_void type at the same time, which would be nice to have.

It makes a lot of people nervous to depend on libraries that declare themselves unstable, yet libc has definitely reached maturity and should be considered stable. Updating the version number is an important symbolic step, and is not a trifling thing done "just because". However, I would agree that it should only be done when major issues like #180 are resolved. I think we need a roadmap for fixing that issue.

@SimonSapin
Copy link
Contributor

If people feel strongly enough about the nicer-looking version number, one way that I think would be acceptable is:

  • Make 1.0 compatible with 0.2. This means not fixing any of the issues labeled 1.0-breakage.
  • Somehow teach Cargo that they’re compatible, so that it could select 1.0.0 when a crate declares a dependency as libc = "0.2.18", for example.

@coder543 the issue you point to says “1.0-level” in the title. That’s a subjective judgment of quality, not a version number. 1.0.0 as a version number can be a signal that maintainers believe a project has this level of quality. Is this signal worth making hundreds of crates coordinate to upgrade?

@SimonSapin
Copy link
Contributor

The only way I can think of that fixing #180 is a breaking change is if a crate implements the same trait separately for std::os::raw::c_void and libc::c_void. I don’t know if such breakage is major or minor.

@coder543
Copy link
Author

coder543 commented Mar 3, 2017

What you suggest would require breaking semver in Cargo, so I don't think that's going to happen.

Would you prefer that libc never have another breaking release? It will happen eventually. When it does, I believe that we should also update the version number to 1.0.0. The idea of having a 1.0-level release is to have releases that are subjectively of good quality, and part of the subjectivity there is in the version number, not just the code contained within. People who don't live and breathe Rust can't be expected to understand that version 0.2.x is considered stable, and their management is especially not going to be understanding of that.

I want Rust to have as few obstacles to being used in production as possible, and when management sees dependency on libraries that are below v1.0, that's going to be an obstacle.

@tomaka
Copy link

tomaka commented Mar 3, 2017

According to the roadmap, Rust should have 1.0-level crates for essential tasks.

Is interfacing with the libc an essential task? I don't think so, as most of what it provides is already provided by the stdlib.

Most people that depend on libc do just because it provides the c_* types, but they should probably use the types in std::os::raw instead of using libc.

@SimonSapin
Copy link
Contributor

Would you prefer that libc never have another breaking release?

Yes. And url (which I maintain), and serde, and some others.

When a library gains in popularity, especially among other libraries that expose it in their respective public APIs, any breaking release becomes increasingly more painful. This is the "other side of the coin" of enforcing SemVer in Cargo.

@lambda
Copy link
Contributor

lambda commented Mar 3, 2017

1.0.0 as a version number can be a signal that maintainers believe a project has this level of quality.

I think more important than "level of quality" is "level of stability". In a production project, I don't want to use some crate, have the project work and be deployed for a while, then suddenly need to add some new feature that depends on updating some dependent crate, and discover that due to having many recursive dependencies that were not at a stable point, having to do a whole bunch of work to clean that mess up.

Essentially, the signal that 0.2.x sends me is that at some unpredictable point in the near future, I'll have to deal with the very problem you describe, of having to do a whole bunch of work to fix up a whole ecosystem of dependencies. A 1.0.0 release signals to me "we think that this is ready to support stably for a long period of time, so there won't be gratuitous ecosystem-wide semver incompatible bump in the near future".

Now, is it worth actually breaking the existing ecosystem in order to help prevent this worry? I'm not sure. Simply documenting that for libc, 0.2.x is considered to be stable and supported for the long term may be sufficient, there are plenty of other widespread open source libraries that have always or for many years been under 1.0 but still considered stable. But it is worth thinking about the version number as a stability signal, rather than a quality signal.

@coder543
Copy link
Author

coder543 commented Mar 3, 2017

Yes. And url (which I maintain), and serde, and some others.

That's not being realistic.

Breaking changes have to happen eventually or things will stagnate forever.

@SimonSapin
Copy link
Contributor

That's not being realistic.

Of course. “Not ever” is an exaggeration of “not unless the benefits outweighs the costs that we know (and learned the hard way) to be very high”.

@lambda
Copy link
Contributor

lambda commented Mar 3, 2017

Yes. And url (which I maintain), and serde, and some others.

When a library gains in popularity, especially among other libraries that expose it in their respective public APIs, any breaking release becomes increasingly more painful. This is the "other side of the coin" of enforcing SemVer in Cargo.

Indeed, at some point you want to commit to long-term stability, and accept the warts in the interface and work around them in backwards compatible ways.

Serde in particular is the one that has bitten me the most here. But I would actually like serde to get to 1.0 so that I know when I'll stop having to be on the upgrade treadmill to keep up with the ecosystem. Right now, due to my previous experience with the API changing, I'm wary of relying on it heavily until that happens. Likewise, the 0.2 version number of libc, and previous libcpocalypse, makes me a little wary of relying on it as well.

I think that while the release to bump to 1.0.0 will be painful for many of these crates, ripping off that bandaid and sending the signal that that's the last time that will happen in quite a while is the big benefit of the push to 1.0.0-level crates. There is a bit of a sense of "Rust is stable now, but the ecosystem is not" that holds people back from depending on it.

@steveklabnik
Copy link
Member

Simply documenting that for libc, 0.2.x is considered to be stable and supported for the long term may be sufficient, there are plenty of other widespread open source libraries that have always or for many years been under 1.0 but still considered stable.

IMHO, the Rust team should lead here, and get it to 1.0.

I agree with @SimonSapin that this shouldn't be taken lightly, as it will be painful. But it should be done.

@metajack
Copy link

metajack commented Mar 3, 2017

I think the argument here is not don't do it, but don't do it unless there are meaningful breaking changes to justify it. Republishing what we have now as 1.0 just creates a ton of work to achieve a more appealing version number.

The last libc breaking upgrade was a huge time sink, which we often refer to as the libc-pocalypse. I may be wrong, but I think we probably discussed calling the current version 1.0 back then for this very reason.

When it does happen, I suggest not just publishing the crate and moving on. Actually do the work to get the whole ecosystem upgraded as quickly as possible; know that this is going to cause amazing grief and be prepared to help.

@tbu-
Copy link
Contributor

tbu- commented Mar 3, 2017

It would be easier to upgrade once Cargo understands the difference between public and private dependencies, I guess – the problem last time was (AIUI) that Cargo decided to use mutually (semver-)incompatible versions of libc together where it was a public dependency, i.e. one whose types were reexported/used in public interfaces.

Once Cargo understands public/private dependencies, there incompatible versions of libc won't appear in one project where they're used together, so there should be no upgrade churn.

Cargo issue: rust-lang/cargo#2064.

@nox
Copy link

nox commented Mar 3, 2017

@tbu- There will be upgrade churn even with this, given this will be a breaking bump in all projects where libc is a public dependency.

@tbu-
Copy link
Contributor

tbu- commented Mar 3, 2017

AIUI, no. People can declare their project compatible with 1.0 whenever they like, and also stay compatible with 0.2 (libc should make it easy to stay compatible with both; use the version constraint >=0.2.0,<2.0 in crates). Then the ecosystem can gradually move to 1.0.

@nox
Copy link

nox commented Mar 3, 2017

What do you mean "stay compatible"? How?

@nox
Copy link

nox commented Mar 3, 2017

If a crate in your project has a public dependency on libc, any other crate with that same public dependency must have the same version constraint as the first one, AFAIU how public dependencies are supposed to work.

But regardless of that, if your crate exposes a libc type in its API, then it must do a breaking bump to update it to 1.0, because its API changed in a breaking way. And then every other crate that exposes types from the libc-depending one will also require a breaking bump for the same reason, ad nauseam.

@tbu-
Copy link
Contributor

tbu- commented Mar 3, 2017

Not if Cargo understood public dependencies. Then it would know that it can't upgrade your libc dependency unless it also updates the libc dependency of the parent crate.

I link to two crates A and B, both have a public dependency on libc, 0.2.0. The next day, A decides that it will also support libc 1.0.0, constraint libc = ">=0.2.0,<2.0". Since Cargo understands public dependencies, it knows that it cannot upgrade libc in crate A unless both the parent crate and crate B also allow version 1.0.0 of libc. Nothing breaks.

@nox
Copy link

nox commented Mar 3, 2017

That doesn't work.

When A updates libc as a public dependency with >=0.2.0,<2.0, B will not have yet told Cargo that libc is a public dependency for itself too, and thus Cargo will happily build a 0.2 version for B and a 1.0 version for A.

@tbu-
Copy link
Contributor

tbu- commented Mar 3, 2017

Yes, it needs public dependencies first, and it needs the acknowledgement of public dependencies first.

@brson
Copy link
Contributor

brson commented Mar 3, 2017

I'm really glad you've opened this issue. It's going to take a lot of such efforts for us to achieve the libs goals this year.

FWIW, the libs team is starting to work on what it means to be 1.0 and evaluating crates with this in mind, and we'll start a public process soon to help move these crates forward (here is a very preliminary sketch of the guidelines the libs team tries to follow when evaluating apis, with a checklist at the top covering basic fit-and-finish issues).

libc though is fairly special, with some unique considerations since it is entirely bindings, and may not fit into the typical crate evaluation process.

Regarding the version number of this crate, I'd suggest that the notion that we are trying to get crates to 1.0, while being evocative and easy to understand, is an oversimplification. What is most important is that we get a core of critical crates up to consistent quality levels, not that they literally have a version "1.0" (e.g. some key crates are already > 1.0 but still have work to do, so they also don't fulfill the criteria of being "1.0" crates).

@coder543
Copy link
Author

coder543 commented Mar 3, 2017

I'd suggest that the notion that we are trying to get crates to 1.0, while being evocative and easy to understand, is an oversimplification. What is most important is that we get a core of critical crates up to consistent quality levels, not that they literally have a version "1.0".

I agree with this. We're not just trying to bump version numbers. But, in the process of uplifting the quality of these crates, it becomes highly logical to signal to users that they are actually and literally 1.0 levels of quality by setting the version number appropriately. Failing to do so would arguably be negligent, since it does not follow the semver guidelines, which state that 0.x.y is purely for "initial development". If a crate is at 1.0 levels of maturity, then for semver compliance alone, it should be numbered as such, since it is not in the initial development stage. I would hate for Rust crates to get into the habit of misusing the semver system out of some reluctance to release 1.0. There can always be a 2.0 or X.0 release later. 1.0 is not the end of the line.

For production use, it also makes it much easier to present to coworkers and managers who are less familiar with internal Rust politics when the version numbers are appropriately set as well. The morale boost in the community from having these pervasive core crates reach v1.0 would also be tangible.

There are many reasons to want to have a literal v1.0, but I don't think we should promote crates to v1.0 unless they are mature and stable in terms of both API and internal logic. Remember that "perfect is the enemy of good," so we also cannot hold the process up forever waiting on the ideal crate before releasing v1.0.

libc may be a special case, but I chose to create this issue here because it is the most downloaded crate of all time, the most essential by one self-evident definition. If it is special because it is entirely bindings, then arguably that makes it easier to judge its maturity level than something like a serialization library, where there are so many corner cases that it takes a lot of bikeshedding to decide what 1.0 even means.

@SimonSapin
Copy link
Contributor

@tbu-

It would be easier to upgrade once Cargo understands the difference between public and private dependencies, I guess

Yes this would help, but it wouldn’t solve the problem. When there is a conflict (crate A uses both B and C, which both have a public libc dependency) all that Cargo can do is tell you about the conflict earlier and in clearer terms than rustc would. You’ll still need to wrangle pull requests and crates.io publication in many repositories to solve the conflicts.

@tbu-
Copy link
Contributor

tbu- commented Mar 3, 2017

@SimonSapin Perhaps the crate authors could be persuaded to support both libc versions at the same time – then the conflicts could be resolved by choosing one common version for all crates that have a public libc dependency.

@nox
Copy link

nox commented Mar 3, 2017

With a feature? Features are supposed to be additive.

@tbu-
Copy link
Contributor

tbu- commented Mar 4, 2017

@nox With libc = ">=0.2,<2.0".

@nox
Copy link

nox commented Mar 4, 2017

Oh. That still means coordination across all crates, and that means no improvements such as new bindings can land in libc ever, even non-breaking changes, because then the constraint would need to change to 1.y.z, i.e. the version where the improvements were introduced.

That's another problem with range constraints, they just postpone the breaking bump.

@retep998
Copy link
Member

retep998 commented Mar 4, 2017

Has anyone considered whether types in libc could benefit from as of yet unstable or unimplemented features such as untagged unions or specifying alignment? If it could, then there's no point in even trying to go to 1.0 until such features are stable.

@bstrie
Copy link

bstrie commented Nov 17, 2017

@dtolnay , I love the idea, even if it is "just crazy enough to work". :P But does crates.io even allow one to upload a version that is "lesser" than the most recently-published version?

It would also still require the entire ecosystem to bump deps simultaneously, which might be a bit of a snarl...

@dtolnay
Copy link
Member

dtolnay commented Nov 17, 2017

But does crates.io even allow one to upload a version that is "lesser" than the most recently-published version?

Yes, for example serde 1.0.0 was published April 20, 2017 followed by serde 0.9.16 published on April 23, 2017.

It would also still require the entire ecosystem to bump deps simultaneously, which might be a bit of a snarl...

Unless I misunderstand what you mean, the whole point is to avoid the entire ecosystem having to bump deps simultaneously. Every crate that depends on libc can bump that dep independently without making their own breaking change. The approach is documented in semver-trick.

@bstrie
Copy link

bstrie commented Nov 17, 2017

You're not misunderstanding, I was just slightly mistaken in a variety of silly ways. :P Ship it!

@gnzlbg
Copy link
Contributor

gnzlbg commented Feb 3, 2018

I don't think doing a 1.0 release just for the sake of saying this crate is 1.0 is personally worth it.

However, the are a number of outstanding API-breaking issues that we might want to do at some point (finding a solution for the ctypes mess, removing removed functionality, updating c_void, etc.). That is going to require a breaking change anyways, and we might just use the occasion to bump directly up to 1.0 release.

Right now, the ctypes situation has no clear path forward, fixing c_void doesn't seem to have a clear path forward either, and the version number saying 0.2 instead of 1.0 is IMO not a big deal either because there are outstanding API issues that we want to fix at some point and that are very likely going to be API-breaking changes so... 0.2 actually reflects the state of things pretty well.

@faern
Copy link
Contributor

faern commented Jul 15, 2018

Personally I feel it's very strange to keep oddities and hacks in the implementation and public API over doing a one time painful effort to upgrade code. No matter how painful it is. Because it's a one time thing vs getting a better API forever.

I think we should aim for as many breaking changes as possible for 1.0. So that the reward for doing the job of upgrading everything pays off as much as possible.

I would feel it would be very strange to release 1.0 without proper untagged unions or specifying alignment and removing the __align hack in addition to coming up with, and implementing a long term solution for c_void as well as the other debated warts in this crate.

@jorickert
Copy link

The problem with platforms that make breaking API/ABI changes (BSD) #570 should in my opinion also resolved before/with 1.0 because this issue will likely cause problems in the future and is probably not fixable without breaking changes

@gnzlbg
Copy link
Contributor

gnzlbg commented Aug 7, 2018

@snsmac we just would need to add newer target for ABI incompatible OS versions (e.g. x86_64-unknown-linux-gnu2, x86_64-unknown-linux-gnu3, ...) and use conditional compilation inside of libc (and everywhere else...) to handle the different ABI incompatibilities.

But that's a backwards compatible change and therefore orthogonal to any libc versioning issues. We could do this today and would just need to bump the minor libc version.

@gnzlbg
Copy link
Contributor

gnzlbg commented Nov 24, 2018

So this is my attempt at an abstracted summary of the discussion so far.

First, there is a strong consensus that new libc releases should be backwards compatible with libc 0.2.. Second, I think that these two groups of issues characterize most arguments given in favour of doing a new release:

  • Using new features: a new version of libc should properly use new Rust features - union, repr(align), repr(packed), repr(packed(N)), flexible-array members / custom DSTs, core::ffi::c_void.

  • Platform APIs aren't timeless. @dtolnay 's summary mentions many of the open PRs and issues and almost all of them are breaking changes because a platform had a breaking change on its API.


I have some opinions on these.

Identifying underlying issues

We have been able to use new Rust features in libc (e.g. align, packed, core::ffi::c_void) without breaking the world. While the c_void change is a "technical breaking change" (using rust-semverver terminology), it's probably a soft breaking one per the API guidelines, and AFAICT only one user noticed this (#1136) because it was still stuck on a nightly from the 1.30 cycle prior to the nightly containing core::ffi::c_void. Nobody has noticed the other breaking changes and technically, C FFI was broken without them (e.g. incorrect struct size / alignment).

Looking at some of the API-breakage issues, some of them are "this type layout changed". However, for some of them this happened because the C types are actually DSTs (e.g. using flexible-array members). So maybe using new Rust language features helps fixing these without fully breaking backwards compatibility.

This leads me to the second group of issues. Platform APIs aren't timeless. Most platforms change the values of consts (e.g. from C enum variants) very often, sometimes from release to release. This already makes libc very platform specific. libc's design currently assumes that platforms are timeless, and though most platforms do not change function symbol names, some platforms do remove some symbols, change struct layout, value of statics, etc. In some cases, users would get linker errors, but in most cases, using libc with the wrong platform version is just undefined behavior and there is not much we can do about this right now.

Remembering the 0.1 to 0.2 migration, the two most painful things for me were libc = "*" which hopefully nobody is using anymore, and that some libraries were using libc ctypes on their APIs, which broke interoperability between libraries using different libc versions.

Backwards-compatibility preserving solutions

I think there are a couple of actionable items that do not necessarily require a breaking version:

  • cty: Platforms don't break their ctypes like c_int often, and doing so would probably require a new target triple. The cty crate already exposes C types. One way to allow crates to interoperate across incompatible libc versions would be for the libc crate to expose its ctypes from here.

  • libc_core: There are core APIs and types that platforms (almost) never break (e.g. malloc). If we would extract the "core" of libc that is actually required for libstd to work, we could minimize its risk of breaking more easily, e.g., by being more picky about which APIs are allowed there or more conservative with new language features. This could reduce the chance of "incompatibilities" between the core APIs in crates.io and the ones re-exported by libstd, and ideally, would result in a libstd that works across a wider range of platform versions. Some people have expressed interest on platform-version aware libc. This change might allow experimenting from that on crates.io without affecting libstd.

  • Support crater runs for libc crates.io version: to make decisions about breaking changes we need to know what do they break.

  • Clarify which breaking changes are allowed for libc. Which version of the platforms should libc track until we have platform-versioning? Is it ok to update consts ? (Policy of supported platform version for constant values #1142) Is it ok to update a function API ? Could we do crater runs for libc changes? Is it ok to fix undefined behavior (e.g. wrong struct / size alignment) ? Is it ok to fix "highly incompatible" types (e.g. use union, use FAMs, ...), etc.

These actionable things could allow us to implement most of the "API breaking" changes that are pending without actually breaking anybody while keeping libc at version 0.2.

This doesn't mean that we will never do a libc 1.0 release, but rather that we don't need consensus about when and how to do a 1.0 release to keep making progress on some of the open issues.

@tbu-
Copy link
Contributor

tbu- commented Nov 24, 2018

As I understand it, we'd only have to do one final libcpocalypse (the second one), because with rust-lang/rfcs#1977, Cargo would understand public dependencies and thus version conflicts between two crates using different versions of libc cannot happen, because Cargo would always resolve the two crates' libc version to the same one.

Is my understanding correct?

@SimonSapin
Copy link
Contributor

A lot of FFI crates use libc types in their public API, so libc is a public dependency. So Cargo being aware that some (other) dependencies are private is not gonna help a lot there.

However a lot of the type mismatches between libc 0.1 and 0.2 were about c_void. Now that we have c_void in the standard library and libc re-exporting it, that’s one fewer source of incompatibility between 0.2 and a future semver-incompatible version.

@gnzlbg
Copy link
Contributor

gnzlbg commented Nov 27, 2018

Now that we have c_void in the standard library and libc re-exporting it, that’s one fewer source of incompatibility between 0.2 and a future semver-incompatible version.

Yes, IMO this change has solved the largest headache. The point about moving the ctypes out of libc is to more easily allow interoperating between different versions of libc, at least for the majority of cases (e.g. the C standard library types like c_int and friends).

If we never release a new libc version, then this change does not buy us anything AFAICT.

@bstrie
Copy link

bstrie commented Jul 30, 2019

I do like the idea of having one crate for fundamental things which platforms don't have the nerve to break, and another for platform-specific things which may break at a platform's whim. If the former crate proved to be stable, small, and well-defined enough--effectively "things defined by the C standard that everything in the world relies on and it would be catastrophic for any platform to attempt to break them"--it might even be a candidate for inclusion in std someday (although I acknowledge that not everyone is on board with the idea of us standardizing even more things from the C standard, but it's hard to argue that there's any external crate that's more de-facto standardized than this crate already is).

@Razican
Copy link
Contributor

Razican commented Jan 19, 2020

Hi, has there been any further discussion on this? It would be nice to have a 1.0 libc, that could be forward compatible.

@gnzlbg
Copy link
Contributor

gnzlbg commented Jan 20, 2020

Chances are libc 0.3 will be released at some point with major backward incompatible changes, like proper usage of unions, #[repr(align / packed)], etc.

I'm not sure whether libc 1.0 is something that makes even sense anymore, since many platforms supported by libc do perform backward incompatible changes to their APIs on a regular basis, and libc currently needs to adapt to that, which necessarily results on backward incompatible changes on our end.

A step towards that would be to start by removing all kernel APIs and non-stable APIs from the libc crate, and moving them to other crates that can follow a versioning scheme closer to the OS.

@retep998
Copy link
Member

A step towards that would be to start by removing all kernel APIs and non-stable APIs from the libc crate, and moving them to other crates that can follow a versioning scheme closer to the OS.

Technically the CRT on Windows is a non-stable API as it releases new major versions once in a while that can have breaking changes.

@gnzlbg
Copy link
Contributor

gnzlbg commented Jan 20, 2020

If somebody wants to start working on this, I can mentor. A good step would be to create a new crate in this repo for a particular platform, add that as a dependency of libc (for backwards compatibility, at least for the moment), and start moving APIs towards that crate.

danielverkamp pushed a commit to danielverkamp/libc that referenced this issue Apr 28, 2020
* test table lookup intrinsics with negative indices

* provide table lookup intrinsics only on little endian targets
@dekellum
Copy link

dekellum commented Jan 23, 2021

The libc crate is as core as any crate could possible be! 0.2.0 should have been released as 1.0.0, per your own stated policies! Hind site is of course 20/20, but its more than just cosmetic. Leaving this as is, e.g. 0.2.3921 will mean either continued risky/harmful release practices and/or fear and loathing at using new rustc features as they become available (even with the build.rs version check approach).

Proposed route to a more gracefully establishing of 1.0.0, without a schism:

  1. Add a virtual/logical "links" attribute to this libc crate, Cargo.toml properties. Release that as soon as possible, e.g. 0.2.83. Wait for that to be the dominant release in use (1 month?)
  2. Release libc as a forthcoming 0.2.z, and duplicated, with no other changes, as 1.0.z, e.g. 1.0.84
  3. The 1.0.z release will be a sleeper, non-issue, because of normal dep rules, except that people will start noticing that they are behind on the libc dep. Suggest to these people in the release notes to change their dependency to libc = ">= 0.2.83, < 2.0", test and report any issues.
  4. New features should continue to get released to 0.2.z and 1.y.0 in parallel for at least 3 months (longer if motivated to solve any real problems in the wild).
  5. After the waiting period of (3), new features, including any MSRV increases should only get released as 1.y.0. There may be multiple minor (y) series maintained in parallel for significant MSRV increases and new features. The 0.2.z now only gets critical fixes (maybe just security fixes). Downstream libraries can start narrowing/upgrading to libc = ">= 1.y.z, <1.(y+1)" (e.g "~1.y.z") or ">= 1.y.z, <2" (e.g. "^1.y.z") as they see fit.

Please go ahead and poke holes in the above plan. I'm sure it could be improved further, but if you think it is somehow fundamentally flawed, then please propose an alternative better plan, that doesn't read "don't bother with 1.y.z", which is just a sad state, and poor resting place due to fatigue.

Also: I'm not entirely insensitive to the point expressed about the platforms making Semver hard/impossible for libc. I suggest that the libc README be amended to include explanation of a "Semver best effort" release policy and how end users will be encouraged to submit PRs to backport fixes to earlier minor series, etc.


The biggest distinction between this proposal and the Semver Trick previously proposed above (comment) is that this proposal doesn't risk breakage to older/infrequently published crate series that currently depend on libc (e.g. libc="0.2"). The application of (0) means we won't allow a duplicate libc 1.0 in the dependency graph, at least not in any general cargo update case, and such older crates will not see changes in libc 1.y.0 (step 4) for obvious reasons. In general terms, the above proposed approach is more conservative and cautious than the Semver Trick.

At the very least, if there is any good motivation for an 0.3 release, it really seems like it would be a waisted opportunity not to release that as 1.0.0 and get, the semver bump over with in one go. If it helps, I offer my time to make the changes/releases I propose, and writeup the rather important release notes explaining the novel approach.

@bstrie
Copy link

bstrie commented Feb 28, 2022

If somebody wants to start working on this, I can mentor. A good step would be to create a new crate in this repo for a particular platform, add that as a dependency of libc (for backwards compatibility, at least for the moment), and start moving APIs towards that crate.

@gnzlbg Still willing to mentor this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests