From 2fcff24100bb05596c46387c8205ee1c08f8a34e Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Sun, 14 Jul 2024 08:28:46 +0200 Subject: [PATCH] Establish toolchain and language versioning (#4105) Proposal for how Carbon version numbers work: - A single version across language, standard library, compiler, linker, etc. - Semantic Versioning (SemVer) based - Details of how SemVer criteria for major, minor, and patch should apply to Carbon - Details of how we will operate before 1.0 and how this connects to Carbon's milestones - Directional guidance for future work including post-1.0 versions, LTS versions, and standardization --------- Co-authored-by: Richard Smith --- docs/project/versioning.md | 270 ++++++++++++++++++++++++++++++++ proposals/p4105.md | 305 +++++++++++++++++++++++++++++++++++++ 2 files changed, 575 insertions(+) create mode 100644 docs/project/versioning.md create mode 100644 proposals/p4105.md diff --git a/docs/project/versioning.md b/docs/project/versioning.md new file mode 100644 index 000000000000..3558c26a89fc --- /dev/null +++ b/docs/project/versioning.md @@ -0,0 +1,270 @@ +# Toolchain and language versioning + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/4105) + + + +## Table of contents + +- [Overview](#overview) +- [Major version increments](#major-version-increments) + - [Breaking changes](#breaking-changes) + - [Exclusions to what constitutes a breaking change](#exclusions-to-what-constitutes-a-breaking-change) +- [Minor version increments](#minor-version-increments) +- [Patch version increments](#patch-version-increments) + - [Examples:](#examples) +- [Pre-release versions](#pre-release-versions) + - [Release qualification pre-releases: `MAJOR.MINOR.PATCH-rc.N`](#release-qualification-pre-releases-majorminorpatch-rcn) + - [Incremental development versions: `MAJOR.MINOR.PATCH-0.{nightly,dev}.N`](#incremental-development-versions-majorminorpatch-0nightlydevn) + - [Nightly pre-release versions](#nightly-pre-release-versions) + - [Development pre-release versions](#development-pre-release-versions) +- [Relevant proposal](#relevant-proposal) + + + +## Overview + +Carbon uses a single versioning scheme across both the language itself and +toolchain, including the standard library, compiler, linker, and all development +tools released by the main Carbon project. + +The scheme conforms to and is closely based on Semantic Versioning +(https://semver.org/ -- version 2.0.0): + +- Carbon versions: `MAJOR.MINOR.PATCH` +- Releases with backwards incompatible changes, including a deprecation that + might trigger a build-breaking warning, increment `MAJOR` after reaching the + `1.0` milestone, and increment `MINOR` before then. +- Releases with only backwards compatible changes are not expected to happen. +- Releases containing only bug fixes increment `PATCH`. +- Pre-release suffixes: + - `MAJOR.MINOR.PATCH-rc.N`: The N-th potentially viable candidate for a + release. + - `MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD`: A nightly incremental + development build on a particular day during development of that + version. + - `MAJOR.MINOR.PATCH-0.dev`: An interactive, incremental development build + on a particular day by some developer during development of that + version. + +See the sections below for the details of each aspect of these versions. + +## Major version increments + +Aligned with SemVer, the major version must increment for any _breaking change_ +to the language or any part of the toolchain. + +The first increment from 0 to 1 is expected to be based on achieving a desired +milestone of feature completeness and quality to declare the language to have +reached a stable version. + +Subsequent increments are expected to be done with a time-based release +strategy. Features (or breaking changes) ready to ship will do so, and others +will wait for the next major release. The exact cadence used is future work and +should be determined based on discussions with Carbon's users in the ramp up to +and after reaching the 1.0 milestone. + +However, just because we increment the major version for a major release and +_can_ make breaking changes doesn't mean we _will_ or _should_. Breaking +language changes are extraordinarily expensive for users due to the inherent +scale of churn they impose. It is tempting to try to make non-breaking releases +instead, but our experience with C++ language, compiler, and standard library +updates is that truly making no breaking changes is extremely difficult and +overly constraining. We expect most releases, especially in the early phases of +the language to involve _some_ amount of breaking change and will simply work to +make these as cheap to upgrade through and minimal as we can. + +At some future point, it is possible that Carbon will become so stable that it +makes sense to consider using minor version increments for some releases. If and +when this happens, we should revisit our versioning and release policies to +establish a predictable and unsurprising structure. + +### Breaking changes + +Beyond traditional breaking API changes in either standard library APIs or tool +APIs, Carbon also includes breaking changes in the language or toolchain. +Language and toolchain breaking changes are any that cause correct, functioning, +and non-reflective code to become invalid, rejected, incorrect, or silently +change behavior. + +### Exclusions to what constitutes a breaking change + +Carbon excludes "reflective code" which is in some way detecting the Carbon +version, or the presence or absence of features and as a consequence can be +"broken" by detecting changes that are correctly designed to otherwise be +non-breaking. We don't want adding features to be considered a breaking change +and so exclude code that specifically detects such additions. + +Carbon also excludes breaking changes to incorrect code unless it was accepted +and functioning in some useful, and typically widespread, way despite its bugs. + +## Minor version increments + +Currently, Carbon plans to primarily use the minor version increments with a 0 +major version to track our progress towards our 1.0 milestone of a feature +complete initial language. As a consequence we have defined 0.1 and 0.2 +milestones and may define more steps as needed. + +Beyond this and in a post-1.0 language world, we expect most significant +features to also accompany some small and manageable breaking changes from +deprecations. We may choose to revisit this in the future, but our current plan +is not to make minor version releases post-1.0 and instead focus on our +commitment to making those updates both easy and scalable for language users. + +## Patch version increments + +The patch version will increment when the change is fundamentally a bug fix to a +previously released version. We expect the vast majority of these to be strictly +backwards compatible bug fixes. + +Patch releases are expected to be driven by demand, and not necessarily present +if unnecessary. However, the exact schedule and process will be determined as +part of getting ready for the 1.0 milestone. Before that milestone we don't +commit to any particular process or cadence for patch releases as no release +before that point should be considered stable. + +Note that we still consider restoring the _intended_ "public API" of a release +to be a bug fix. When these bug fixes theoretically break new code in a way that +would typically require a major version increment, they may be made with merely +a patch version increment when they are in fact restoring our intended behavior +for that release. However, we take the SemVer guarantees very seriously as these +fixes can still be disruptive and so we work to hold a high bar for them: + +- They must be in some way fixing a _regressions_ for users from a previous + release, not merely a missing feature. + - Can even be a regression in the overall cohesion or reliability of the + language or tools, which a bug in a new feature might erode. + - Key is that we motivate any patch fix through the lens of a regression + fix and stabilization rather than fixing forward. +- The scope of disruption from the fix is demonstrably small, due to some + combination of: + - The short time duration of the release containing the regression. + - The narrow scope of code constructs potentially impacted. +- The impact of the regression is large and cannot be easily worked around, + for example: + - Undermining a core priority of the Carbon Language for a significant set + of users. + - Making the engineering cost of adopting the release uneconomical for any + significant body of users. + +### Examples: + +- We add a new feature that includes a bug which creates unsoundness and + allows incorrect code to be compiled that will crash or exhibit UB when + executed. + - While this is a new feature and not a bug in an existing feature, it + would be a _serious_ regression to the reliability of the language as a + whole and the ability of users to reason about the correctness of + programs. + - This would be a good candidate for a patch release to address unless it + is found very late (months) after the release _and_ the only ways to + address would have similarly bad effects on code written since the + initial release. + - Even that level of user disruption could potentially be overcome if for + example the bug led to security vulnerabilities. +- We add a narrowly used new feature that includes a bug where some code + patterns that _should_ work with the feature are rejected at compile time or + crash reliably. + - Unlikely this is worth a patch release to make an invasive change given + the narrow use case. + - A good candidate to introduce a warning or error on using the feature in + the way that might lead to a crash, and possibly on using the feature at + all. +- We add a compiler opt-in feature behind a flag that doesn't work reliably. + - Good candidate to have the flag disabled or trigger a warning message. + - Not a good candidate to try to fix the feature forward. +- We add a compiler opt-out feature that doesn't work reliably. + - What to do likely depends on the scope of users impacted. If _very_ few + users impacted, possibly just document how to opt-out. + - If enough are impacted to be a nuisance and a regression in experience + in general, likely worth attempting a patch release that narrowly fixes + or mitigates the issue. + +## Pre-release versions + +Beyond the major, minor, and patch versions of an actual release, SemVer +provides a foundation for pre-release version management. However, it is a very +open-ended foundation with a wide range of possibilities and no particular +semantic model provided. Some of this is to support the wide variety of +different needs across different projects. It also reflects the fundamentally +less crisp and well defined criteria needed for pre-releases. + +That said, Carbon should try to have a small and well articulated scheme of +pre-release versions to help communicate what these releases do and don't +constitute and how they should be interpreted. These are selected to provide a +framework that allows pre-release versions to order in a reasonably cohesive way +when compared using SemVer. + +In descending order, Carbon pre-releases may use: + +- `MAJOR.MINOR.PATCH-rc.N` +- `MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD` +- `MAJOR.MINOR.PATCH-0.dev` + +We expand on each of these below to provide criteria and details. + +### Release qualification pre-releases: `MAJOR.MINOR.PATCH-rc.N` + +We create release candidate or "rc" pre-releases when we believe that version to +be complete and ready to release and want to collect feedback. There should not +be interesting or significant gaps, even known ones, from the intended release. +The expectation should always be that unless some feedback arrives to the +contrary, the release candidate could simply become the release. + +For each pre-release category, we always suffix with a sequential count `N` of +the pre-releases at that version. We must start with a `.0` in order to have +subsequent iterations of the same version and category of pre-release to sort +after the first. + +### Incremental development versions: `MAJOR.MINOR.PATCH-0.{nightly,dev}.N` + +These are versions that are not in any way associated with the actual expected +release, but are periodically produced as an incremental tracking of development +progress. Because they are not expected to be part of qualifying a specific +release, they're not defined by any particular criteria of completeness or +readiness. In practice, these will occur at every stage between one release and +the next. + +#### Nightly pre-release versions + +These are automated incremental development versions built each night when the +automated testing passes. There is _no_ attempt to provide any higher quality +bar or refinement than whatever was in the tree at the time the automation runs, +and whatever automated tests are present pass. + +It is important to emphasize that the primary use case of these pre-release +versions is not to evaluate a potential release but for the developers and +contributors to Carbon itself to track incremental development progress. That +development-oriented goal drives how they are built and what they do and don't +provide. + +Mechanically, we prefix the `nightly` pre-release version component with a `0` +component to ensure these versions sort before any and all release qualification +pre-release versions. We also add a date-derived suffix to provide a rough +chronological ordering of nightly builds with otherwise identical versions. + +#### Development pre-release versions + +During development, interactive builds of Carbon need to be versioned in an +unambiguous way, and we do that with the `dev` pre-release version. Much like +nightly versions, these are only produced as artifacts of development activities +and are never part of any actual release process. These versions are further not +built expected to be automated or necessarily repeatable. They may contain +in-flight edits and all manner of other variations. + +Mechanically, we prefix the `dev` pre-release version component with `0` in the +same way as `nightly` is prefixed to ensure effective ordering. We don't add any +additional information to keep the mechanics of development builds simple -- for +example, there is no easy way to extract the date of the build. The exact +timestamp of the build may be available but doesn't participate for simplicity +and minimizing cache impact. + +## Relevant proposal + +- [Proposal p4105](/proposals/p4105.md) diff --git a/proposals/p4105.md b/proposals/p4105.md new file mode 100644 index 000000000000..3e2483fd9186 --- /dev/null +++ b/proposals/p4105.md @@ -0,0 +1,305 @@ +# Establish toolchain and language versioning + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/4105) + + + +## Table of contents + +- [Abstract](#abstract) +- [Problem](#problem) +- [Background](#background) +- [Proposal](#proposal) +- [Details](#details) +- [Directional sketch for the future](#directional-sketch-for-the-future) + - [Language evolution and breaking changes](#language-evolution-and-breaking-changes) + - [Long-Term Stable (LTS) versions and standardization](#long-term-stable-lts-versions-and-standardization) +- [Rationale](#rationale) +- [Alternatives considered](#alternatives-considered) + - [Do nothing, or just talk about a minimal nightly version.](#do-nothing-or-just-talk-about-a-minimal-nightly-version) + - [Make no breaking changes past 1.0.](#make-no-breaking-changes-past-10) + - [Version different parts of the language separately.](#version-different-parts-of-the-language-separately) + - [Use a custom versioning scheme rather than SemVer.](#use-a-custom-versioning-scheme-rather-than-semver) + - [Include more pre-release variations](#include-more-pre-release-variations) + + + +## Abstract + +Proposal for how Carbon version numbers work: + +- A single version across language, standard library, compiler, linker, etc. +- Semantic Versioning (SemVer) based +- Details of how SemVer criteria for major, minor, and patch should apply to + Carbon +- Details of how we will operate before 1.0 and how this connects to Carbon's + milestones +- Directional guidance for future work including post-1.0 versions, LTS + versions, and standardization + +## Problem + +We need a versioning scheme for Carbon both for the language and the reference +toolchain implementing that language. This is important even before we reach any +specific milestone, as we want to define the schema and implement it _before_ it +becomes useful for marking specific milestones. + +## Background + +- [Semantic Versioning](https://semver.org/) +- [Rust Editions](https://doc.rust-lang.org/edition-guide/editions/) + +## Proposal + +First, Carbon should have a single versioning scheme across both the language +itself and toolchain, including the standard library, compiler, linker, and all +development tools released by the main Carbon project. + +Second, the Carbon versioning scheme should conform to and be closely based on +Semantic Versioning (SemVer), which is the de-facto standard for versioning +schemes in software today. Beyond that, it needs to clarify how the standards +laid out in SemVer map into a programming language context as programming +languages and standard libraries have an extraordinarily broad and tightly +coupled "API" to their users -- all of the source code written in the language. +Carbon needs to provide extra clarity around what constitutes our "public API" +for SemVer purposes and the criteria for changes. + +Third, SemVer provides a schema for pre-release versions, but is largely +open-ended on their semantics. Carbon should have a specific set of well defined +pre-release versions with clearly communicated purpose, nature, and meaning to +avoid confusion. + +Fourth, language versioning is an especially important area for the long-term +evolution and so Carbon should have some directional guidance around the future +work expected in the versioning front. This should speak to specific use cases +and needs that may be left seemingly unaddressed otherwise. + +Summarizing the proposed outcome of these together: + +- Carbon versions: `MAJOR.MINOR.PATCH` +- `MAJOR` increments on backwards incompatible changes, including a + deprecation that might trigger a build-breaking warning. + - Doesn't make it free to make such changes. Each change must pay for its + adoption and churn cost. But when a change is needed and well justified, + this signifies its introduction. + - Used to establish our milestones for the language. + - Some explicit carve-outs of things designated to not be in the "public + API" of the language. +- `MINOR` increments only expected during early development with a major + version of `0`. + - If Carbon some day stabilizes sufficiently to motivate it, we may + revisit this and begin to use the minor version number to signal + backwards compatible releases. +- `PATCH` increments represent bug fixes only. + - Goal is always fully backwards compatible. + - When fixing the bug makes code written against the release with the bug + break, may be unavoidable as the intent was never the buggy behavior. + But this is rare and we hold a very high bar for such bug fixes due to + their disruptive nature. +- Pre-release suffixes: + - `MAJOR.MINOR.PATCH-rc.N`: The N-th potentially viable candidate for a + release. + - `MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD`: A nightly incremental + development build on a particular day during development of that + version. + - `MAJOR.MINOR.PATCH-0.dev`: An interactive, incremental development build + on a particular day by some developer during development of that + version. + +## Details + +See the added [versioning document](/docs/project/versioning.md). + +## Directional sketch for the future + +The mechanics outlined above provide a good basis for the initial versions of +the language (up to 1.0) and any necessary mechanics and tooling around those +versions. However, beyond 1.0 we expect the needs of the language and project to +expand and more detailed versioning and evolution tools to become critical. We +lay out directional sketches here for where Carbon should go in the future to +address these needs, but these are just directional guidance and will need their +own carefully considered proposals when the time comes. + +### Language evolution and breaking changes + +We don't expect a simple version number to be sufficient long-term for the +evolution needs of the Carbon language. We should plan to at least map these +major versions into Rust-edition-like controls within source code itself to +allow incremental adoption across a codebase of fixes for breaking changes or +adoption of new language features with a single toolchain version. That is, some +code will want to compile using previous major version semantics even with the +new compiler. + +The approach taken in Rust and proposed for C++ to address this are "editions" +that source code opts into in order to allow the compiler to support a mixture +of code in a codebase during incremental adoption. Carbon will need at least +something equivalent to this, and may want to explore a more fine-grained system +of opting into specific functionality sets similar to how pragma-based extension +usage or Circle works. + +Regardless of the specifics, a key is that breaking changes are not forcibly +coupled in their roll-out to updates to the Carbon toolchain. Each step needs to +be incrementally tackled. + +### Long-Term Stable (LTS) versions and standardization + +SemVer alone isn't sufficient to address some user needs for language stability. +It is enough to _detect_ the issues when they arise, but Carbon should also plan +for how to _address_ these issues. + +The suggested direction here is towards designated LTS versions based on a +particular level of completeness and quality and the user demand. These versions +will likely need even longer time horizons of support than Linux distro LTS +releases. The direction should be to embrace this and the potential for +multi-decade support windows to support users' needs. As the windows of LTSes +expand, their frequency should reduce to avoid supporting an unsustainable +diversity of versions. + +Exactly how a version is designated as LTS is left to the future work here, but +it should not be expected to change the schema and structure of the versioning, +just the support policy applied to the specific release version in question. + +Some users may even require standardization of a programming language to make it +usable in their environment. Carbon should again embrace this need and see the +standardization as an analogous process to promoting a normal release into an +LTS. Some relevant and effective LTS should be selected and taken through +whatever process is identified to create a standard reflecting that LTS version +of Carbon. Updates to the standard should in turn track as updates to a newer +LTS. The specifics of how to do this are left to the future work, and they may +change exactly how this works. + +Note that the goal of this future direction isn't to constrain how Carbon can +arrive effectively at either an LTS release or a standard. Instead, the goal is +to make it clear that we _should_ be open and planning to achieve these in order +to meet the needs of candidate Carbon users. + +## Rationale + +- [Language tools and ecosystem](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/goals.md#language-tools-and-ecosystem) + - Carbon needs a coherent versioning scheme across the language itself as + well as its ecosystem. Especially as the language is developing rapidly, + being able to sync across all of these with a single, simple versioning + scheme is especially important to have the tooling and ecosystem agree + about features of the language. +- [Software and language evolution](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/goals.md#software-and-language-evolution) + - Users of Carbon need a clear model for understanding the language's + evolution, tracking it, and responding to significant aspects of it. + - The versioning scheme needs to support a wide variety of versions built + in the process of evolving the language without creating confusion. + +## Alternatives considered + +### Do nothing, or just talk about a minimal nightly version. + +Advantages: + +- Carbon is at a very early stage and is a long way from needing release + candidates for stable releases or incrementing its major version numbers. +- No need to imagine distant future scenarios. + +Disadvantages: + +- We already discuss version numbers in various places in the Carbon project, + including our [milestones](/docs/project/milestones.md) and + [roadmap](/docs/project/roadmap.md). +- Establishing how the Carbon project will communicate its updates with + version number changes in advance of those updates makes that communication + more effective. +- Lets us telegraph our intentions and how we are thinking about releasing and + cadence to the community and get earlier feedback. + +A key to adopting the more detailed versioning plan is that we can change any +and all of this if and when we need to. This does not lock Carbon into using +this exact versioning scheme. We will listen to any feedback from potential +users and can adapt our approach if needed. + +### Make no breaking changes past 1.0. + +Advantages: + +- Stable languages have the lowest churn costs for users, and are easier to + learn at scale. + +Disadvantages: + +- This would be in direct opposition to our language goal of supporting + software and language evolution. + - This relieves pressure on adding things to the language by avoiding an + unreasonably high bar. The pressure is still large due to the very real + churn costs, but we avoid amplifying that further with an absolute + restriction on fixing issues. + - We expect Carbon to be a reasonably complex language in order to succeed + at its goals, ranging from C++ interop to incremental memory safety. + This complexity inherently comes with an increased risk and importance + of being able to improve and fix issues. + +### Version different parts of the language separately. + +Advantages: + +- There will be eventually be many differences between changes to the + toolchain and changes to the language itself. We might be able to capitalize + on those to have a better cadence or versioning scheme for these + independently. + +Disadvantages: + +- We would have to carefully define and maintain a compatibility matrix + between the different components. Increasingly in modern languages and + development, the compiler, language, standard library, and tooling are all + deeply interdependent. +- Experience rolling out major updates to Clang and GCC in large codebases and + software ecosystems show even compiler-only or toolchain-only changes easily + become as disruptive as smaller updates to the C++ language itself have been + over the years. As a consequence, while it is tempting to hope for a sharp + difference here we don't in practice anticipate one. + +### Use a custom versioning scheme rather than SemVer. + +Advantages: + +- We don't actually use all parts of SemVer, which results in awkward unused + component of our version number. +- SemVer doesn't actually provide an opinionated versioning scheme, merely a + relaxed schema that many versioning schemes can fit into. + +Disadvantages: + +- Fitting into SemVer ends up needing only very cosmetic changes to a scheme + that is meaningful for Carbon. And we can easily specify the open-ended + parts of the scheme. +- Allows us to easily fit into scripts and people's understanding using SemVer + as a baseline model. +- Avoids confusion when people from outside the community first encounter + Carbon versions as their most likely intuition about the meaning of various + aspects of the number will be a reasonable starting point. + +### Include more pre-release variations + +Initially there was a discussion of potentially defining `alpha` and `beta` +pre-release versions along with release candidate versions, nightly, and +development versions. The specific idea was to document versioning we could use +for longer-lived releases we want to make when not yet ready to call it a +release candidate. + +Advantages: + +- If we end up wanting longer-lived releases prior to arriving at a numbered + milestone such as `0.1`, this would provide a ready-made solution. +- Specifically, communicating the option for this early might help others + avoid being confused by what exactly the state of such a pre-release would + be. + +Disadvantages: + +- There's no real indication we would ever want to make such a release. It + seems easy to imagine the combination of nightly builds and pre-releases + completely covering all of the use cases we end up with in practice. +- Keeping the infrastructure and documentation for such improbable use cases + is drag and friction that doesn't buy us enough to be worthwhile.