news 2026/9/11 9:31:27

Carbon 语言与工具链版本控制方案(Versioning)完全解析:从 SemVer 规范到 Bazel 构建落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Carbon 语言与工具链版本控制方案(Versioning)完全解析:从 SemVer 规范到 Bazel 构建落地

Carbon 语言与工具链版本控制方案(Versioning)完全解析:从 SemVer 规范到 Bazel 构建落地

【免费下载链接】carbon-langCarbon Language's main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang

导读:本文以 Carbon Language 官方文档《Toolchain and language versioning》(docs/project/versioning.md)为核心骨架,系统讲解 Carbon 如何基于 Semantic Versioning(SemVer 2.0.0)为语言与整个工具链建立统一版本模型——涵盖MAJOR.MINOR.PATCH各段位的递增触发条件、破坏性变更的判定与排除规则、rc/nightly/dev三类预发布版本的语义与排序机制,并结合仓库中的 Bazel 构建实现(bazel/version/、common/version.h)展示版本字符串从 Starlark 规则计算、模板替换到编译期嵌入的全链路。读者学完后将能准确理解 Carbon 每个版本号片段的含义,掌握用--release--pre_release--rc_number--nightly_date等 Bazel 标志构建指定版本类型的方法,并领会其在 0.x 开发期、1.0 里程碑及未来 LTS/标准化演进中的定位。

概览:单一版本方案(Overview)

Carbon 在语言本身与工具链(包括标准库、编译器、链接器以及主项目发布的所有开发工具)之间采用一套统一的版本号方案,即语言和工具链共享同一个版本号,避免维护多组件间的兼容矩阵。

该方案紧密遵循 Semantic Versioning 2.0.0,其核心要点如下:

  • 正式版本号格式MAJOR.MINOR.PATCH(如0.0.0)。
  • 破坏性(不向后兼容)变更触发MAJOR递增——在达到1.0里程碑之后;在1.0之前则递增MINOR。这里特意把"可能触发构建告警(build-breaking warning)的弃用(deprecation)"也计入破坏性变更。
  • 仅含向后兼容变更的版本:预期不会发生(Carbon 明确预期大部分版本都会包含一定程度的破坏性变更)。
  • 仅含缺陷修复的版本递增PATCH
  • 预发布后缀(见下文专节):
    • MAJOR.MINOR.PATCH-rc.N:该版本的第 N 个候选发布版(release candidate)。
    • MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD:某开发日自动构建的 nightly 增量开发版本。
    • MAJOR.MINOR.PATCH-0.dev:开发者在开发过程中交互式构建的增量开发版本。

该方案的正式定义来源于提案 p004105-establish-toolchain-and-language-versioning.md,提案文档与本文档互为补充,前者还包含方案制定的动机(Abstract/Problem)、未来方向草图与备选方案对比。

主版本(MAJOR)递增规则

与 SemVer 对齐:语言或工具链任何部分的任何破坏性变更,都必须递增主版本号

从 0 到 1:基于功能完整度的里程碑

01的第一次主版本递增,预期基于"达到预期的功能完整度与质量标准"这一里程碑——即宣告语言进入稳定版本(1.0 稳定版)。在此之前,Carbon 通过0.10.2等次版本里程碑(参见 docs/project/milestones.md)逐步逼近 1.0。

1.0 之后:基于时间的发布策略

后续的主版本递增预期采用基于时间的发布策略:已就绪的功能(或破坏性变更)随当次主版本发布,其余内容等待下一次主版本。具体的发布节奏属于未来工作,应在向 1.0 冲刺及达成之后与 Carbon 用户讨论确定。

关键立场:能破坏 ≠ 应当破坏

文档特别强调:即便递增了主版本号、可以做破坏性变更,也不意味着应当做。语言层面的破坏性变更对用户而言代价极其高昂(固有的变更冲击规模)。Carbon 从 C++ 语言、编译器和标准库的更新经验中得出的结论是:真正"零破坏"的发布极其困难且约束过强。因此:

  • 预期大多数发布(尤其是语言早期阶段)都会包含一些破坏性变更;
  • 项目的工作方向是将这些变更的升级成本降到最低、范围缩到最小
  • 若未来 Carbon 足够稳定,可重新评估是否对部分发布使用次版本递增来标记向后兼容——届时将重新审视版本与发布策略,建立可预期、无意外(predictable and unsurprising)的结构。

破坏性变更的定义(Breaking changes)

除了标准库 API 或工具 API 的传统破坏性变更之外,Carbon 还涵盖语言或工具链层面的破坏性变更,其定义为:

任何导致**正确、可运行、非反射(non-reflective)**的代码变得无效、被拒绝、产生错误结果或行为被静默改变(silently change behavior)的变更。

破坏性变更的排除项(Exclusions)

Carbon 明确将两类变更排除在"破坏性变更"之外:

  1. 反射式代码(reflective code):即通过某种方式检测 Carbon 版本、或检测某功能存在与否的代码。这类代码可能因检测到"被正确设计为非破坏性"的变更而"坏掉"。项目不希望"新增功能"被算作破坏性变更,因此排除专门检测此类新增的代码。
  2. 对错误代码的破坏:除非该错误代码尽管有 bug,但仍以某种有用、且通常相当普遍的方式被接受并正常工作,否则对错误代码的破坏不视为破坏性变更。

次版本(MINOR)递增规则

当前阶段:Carbon 计划主要在主版本为0的时期使用次版本递增,以追踪通往 1.0 功能完整里程碑的进度。为此项目定义了0.10.2里程碑,并可能按需增加更多步骤。

1.0 之后:在 1.0 之后的世界里,预期大多数重要功能也会伴随一些来自弃用(deprecation)的小型、可控的破坏性变更。Carbon 当前计划不在 1.0 后做次版本发布,而是专注于让这些更新对语言用户既容易又具备可扩展性(easy and scalable)——这一立场未来可能被重新评估。

从 version_base.bzl 可以看到当前仓库正处于开发期的具体体现:version_base = "0.0.0",注释明确说明这是活跃开发版本而非已发布版本,且项目"尚未取得足以升至 0.1 里程碑的进展";同时强调"永远不会为 0.0.0 发布任何非开发性质的预发布版本,仅预期 nightly 开发预发布"。

补丁版本(PATCH)递增规则

补丁版本仅在"变更本质上是对先前已发布版本的缺陷修复"时递增,绝大多数应为严格向后兼容的缺陷修复。

发布时机:需求驱动

补丁发布预期由需求驱动(demand-driven),非必需时可以不发布。具体的日程与流程将在筹备 1.0 里程碑时确定;在 1.0 之前,项目不对补丁发布的流程或节奏做任何承诺,因为 1.0 之前的任何发布都不应被视为稳定。

特殊情形:恢复"预期公共 API"的修复

一个值得注意的细节:恢复某个版本"预期的公共 API(intended public API)"仍被视为缺陷修复。当这类修复在理论上会以通常需要递增主版本的方式破坏新代码时,只要它确实是在恢复该版本预期的行为,就可以仅以补丁版本递增来完成。

但项目对 SemVer 保证非常严肃,因为这类修复仍可能具有破坏性,因此设置了很高的门槛:

  • 必须是修复从上一版本引入的回归(regression),而非单纯地补齐缺失功能。回归甚至可以是语言或工具整体凝聚力/可靠性的下降(例如新功能中的 bug 侵蚀了整体可靠性)。关键是任何补丁修复都要以"回归修复与稳定化"的视角来论证,而非"向前修复(fixing forward)"。
  • 修复造成的破坏范围被证实很小,通常源于:包含该回归的版本持续时间很短;或可能受影响的代码结构范围很窄。
  • 回归的影响很大且难以绕过,例如:损害了大量用户的 Carbon 核心优先级;或使相当规模的用户群体采用该发布的工程成本不经济。

官方示例解析

文档给出了三类典型场景,用于判断"是否值得发布补丁修复":

场景分析结论
新功能包含导致**非健全(unsound)**的 bug,允许编译出运行时会崩溃或产生未定义行为(UB)的错误代码虽是新功能而非既有功能缺陷,但这是对语言整体可靠性及用户推理程序正确性能力的严重回归除非发现太晚(发布数月后才被发现)且唯一修复方式会对后续编写的代码产生同样糟糕的影响,否则是补丁发布的好候选;若 bug 导致安全漏洞,即便有用户冲击也可能值得修复
使用面很窄的新功能存在 bug,使本应可用的代码模式在编译期被拒绝或稳定崩溃使用场景狭窄,为此做侵入式修复得不偿失更好的候选是:在使用可能触发崩溃的方式时引入告警或错误,甚至对使用该功能本身发出告警
编译器某个默认关闭的 opt-in(通过 flag 开启)功能运行不可靠功能未默认开启,破坏范围可控好候选:禁用该 flag 或触发告警信息;不主张"向前修复"该功能
编译器某个默认开启的 opt-out(通过 flag 关闭)功能运行不可靠取决于受影响用户规模受影响用户极少:可能只需文档说明如何关闭;影响面大到成为普遍困扰和体验回归:值得发布精准修复或缓解的补丁版本

预发布版本(Pre-release versions)

SemVer 虽然为预发布版本提供了基础语法,但对语义几乎是"完全开放"的。Carbon 选择建立小而清晰、语义明确的预发布版本方案,以便准确传达这些版本"是什么、不是什么、应如何解读",同时保证这些预发布版本在 SemVer 规则下可以连贯地排序(order in a reasonably cohesive way)

预发布版本优先级从高到低依次为:

  1. MAJOR.MINOR.PATCH-rc.N(发布候选)
  2. MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD(夜间自动构建)
  3. MAJOR.MINOR.PATCH-0.dev(开发构建)

发布候选:MAJOR.MINOR.PATCH-rc.N

当项目认为某个版本已完整、可随时发布,并希望收集反馈时,会创建rc预发布版本。要求:

  • 与预期发布的版本之间不应存在有意义或重大的差距(即使是已知差距),预期通常是:只要没有相反反馈,该发布候选直接成为正式发布版本。
  • 每一类预发布版本都以顺序计数 N结尾;必须以.0作为起点(如-rc.0),这样同一版本的后续迭代才能在排序时排到第一个之后(.0确保-rc.0 < -rc.1 < ...)。

在 Bazel 构建中,RC 版本通过两个标志组合生成:--pre_release=rc--rc_number=N,对应 bazel/version/BUILD 中定义的rc_number整型标志(默认-1,非负时才合法)。其拼接逻辑在 compute_version.bzl 的compute_version()中:当rc类型且number >= 0时,追加-rc.N;若number < 0则直接fail报错。

增量开发版本:MAJOR.MINOR.PATCH-0.{nightly,dev}.N

这类版本与"实际预期发布"没有任何关联,只是开发进度的增量追踪产物。它们不受任何完整度或就绪度标准约束,实践上会出现在一次发布与下一次发布之间的每个阶段

之所以在nightly/dev加上0组件(形成-0.nightly...-0.dev),是为了保证这些版本在 SemVer 排序上严格排在所有发布候选(-rc.N)之前——因为预发布标识符按点分段的数字比较,0小于任何正整数N,从而-0.dev < -0.nightly.2024.06.17 < -rc.0 < 正式版

Nightly 预发布版本:MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD
  • 构建方式:自动化构建,每天夜间在自动化测试通过时构建。不对代码树中的内容做任何额外的质量门槛或精炼——自动化测试通过即构建。
  • 核心用途不是用于评估潜在发布的,而是为 Carbon 自身的开发者和贡献者追踪增量开发进度。这一开发导向目标决定了它们的构建方式与提供的内容。
  • 排序机制:用0前缀确保排在所有发布候选之前;再用日期派生的后缀YYYY.MM.DD提供同年份 nightly 构建的大致时间排序。
  • 源码印证compute_version()中 nightly 分支调用_validate_nightly_date()严格校验日期格式必须为YYYY.MM.DD(年 4 位数字、月日各 2 位数字,compute_version.bzl 第 10-22 行),随后拼接-0.nightly.YYYY.MM.DD
Development 预发布版本:MAJOR.MINOR.PATCH-0.dev
  • 构建方式:开发过程中对 Carbon 的交互式构建(interactive builds),是开发活动的产物,永远不会进入任何正式发布流程
  • 特性:不被期望是自动化或可复现的,可能包含**进行中的编辑(in-flight edits)**及各种其他变动。
  • 排序机制:与 nightly 相同,以0前缀保证有效排序;但不再附加任何额外信息(例如不携带构建日期)——这是为了保持开发构建机制的简单性,并最小化对构建缓存的冲击(cache impact)。构建的确切时间戳可能存在,但不参与版本号。

仓库中的落地实现:从 Starlark 规则到编译期嵌入

版本方案不仅是文档层面的约定,在仓库中已有完整实现链路。理解这条链路有助于把版本号格式与真实构建产物对应起来。

版本基线与构建标志

  • 基线版本定义在根目录 version_base.bzl:version_base = "0.0.0",注释强调这是"活跃开发版本",且 0.0.0 仅预期有 nightly 开发预发布。
  • 版本构建标志定义在 bazel/version/BUILD:
Bazel 标志类型默认值取值/说明
--releaseboolFalse启用正式发布版本;启用时必须是唯一使用的版本标志
--pre_release=KINDstringdevrc/nightly/dev三选一;不能与--release同用
--rc_number=Nint-1RC 编号,需--pre_release=rc
--nightly_date=YYYY.MM.DDstringnightly 日期,需--pre_release=nightly,格式严格为YYYY.MM.DD
  • 命令行别名:这些标志可通过根目录 .bazelrc 中定义的别名直接使用:--release--pre_release--rc_number--nightly_date(对应 Bazel 内部 label//bazel/version:release等),构建命令形如:
# 构建正式发布版本(RC 之后的正式版) bazel build --release //... # 构建第 2 号发布候选 bazel build --pre_release=rc --rc_number=2 //... # 构建 2024 年 6 月 17 日的 nightly 版本 bazel build --pre_release=nightly --nightly_date=2024.06.17 //... # 构建默认的开发版本(--pre_release=dev 为默认值) bazel build //...

版本字符串的计算逻辑

核心计算逻辑位于 bazel/version/compute_version.bzl 的compute_version(ctx)函数:

  1. version_base0.0.0)为起点;
  2. --release未开启,则按--pre_release值追加后缀:
    • rc:要求rc_number >= 0,拼接-rc.N
    • nightly:校验日期格式后拼接-0.nightly.YYYY.MM.DD
    • dev:拼接-0.dev
    • 其它值直接fail(非法标志);
  3. --release开启,则保持纯MAJOR.MINOR.PATCH形式。

该函数与expand_version_build_info规则(bazel/version/rules.bzl)配合:规则读取 Bazel 的stable-status.txt/volatile-status.txt(由--workspace_status_command=./scripts/workspace_status.py提供,见 .bazelrc 第 12 行),并受--stamp控制(默认--nostamp以降低对构建缓存的冲击)。模板中的$VERSION$GIT_COMMIT_SHA$GIT_DIRTY_SUFFIX等键会被替换;gen_tmpl.py(bazel/version/gen_tmpl.py)实现了这一 Pythonstring.Template风格的替换工具。

编译期嵌入:Version 结构体

版本信息最终嵌入工具链二进制。头文件 common/version.h 声明Carbon::Version结构体,提供MajorMinorPatch三个整型组件、String(完整版本串)与ToolchainInfo(命令行渲染用版本信息串)。模板文件 common/version.tmpl.cpp 与 common/version_stamp.tmpl.cpp 在编译期将$VERSION$GIT_COMMIT_SHA$GIT_DIRTY_SUFFIX等替换为实际值,其中:

  • Major/Minor/Patch通过constevalToInt/MajorVersion/MinorVersion/PatchVersion$VERSION字符串中解析(version.tmpl.cpp 第 14-49 行),且不依赖 stamping,避免缓存问题;
  • 带 stamp 的版本串格式为$VERSION+$GIT_COMMIT_SHA$GIT_DIRTY_SUFFIX(如0.0.0+abc1234),ToolchainInfo则渲染为Carbon Language toolchain version: $VERSION+$GIT_COMMIT_SHA$GIT_DIRTY_SUFFIX,可用--stamp显式开启后由carbon命令行的版本输出展示。

版本号的排序语义速查

把上述规则汇总,可得一份可直接用于解读任何 Carbon 版本号(并可用 SemVer 比较器排序)的速查表:

版本号示例含义排序关系
0.0.0-0.dev开发者交互式构建(默认)最低
0.0.0-0.nightly.2024.06.17某日夜间自动化构建高于 dev,按日期递增
0.1.0-rc.00.1 的第 0 个发布候选高于所有-0.*开发版本
0.1.0-rc.10.1 的第 1 个发布候选高于rc.0
0.1.00.1 正式发布最高

未来方向:提案中的长期规划

版本方案的长远演进在提案 p004105-establish-toolchain-and-language-versioning.md 的 "Directional sketch for the future" 一节中给出方向性指引(注意:这些只是方向草图,未来需要各自的正式提案):

  • 语言演化与破坏性变更:单一版本号长期看不足以支撑语言演化需求。项目计划至少将主版本映射为Rust Edition 式的源码内控制机制,让同一工具链能以不同主版本语义编译同一代码库的不同部分,实现破坏性变更的增量采纳(incremental adoption),使"破坏性变更的推出"与"工具链升级"解耦。
  • LTS 版本与标准化:SemVer 只解决"检测"问题,不解决"长期稳定"问题。方向是设立基于完整度、质量与用户需求的LTS 版本,支持窗口可能长达数十年(比 Linux 发行版 LTS 更长);LTS 频率应随窗口延长而降低,避免支撑过多版本。标准化则被视为"把某个 LTS 提升为标准"的类比过程。

结语

Carbon 的版本控制方案本质上是用最小的预发布语法集(rc0.nightly0.dev)把 SemVer 的开放语义收敛为可预期、可排序、可沟通的项目契约:在 0.x 阶段以次版本里程碑推进语言演进,以夜间与开发版本支撑高频迭代,以rc兜底发布质量;在 1.0 之后以主版本承载必要的破坏性变更并力求升级成本最小化。而 bazel/version/ 与 common/version.h 的完整实现表明,这一方案并非纸面设计,而是已可操作的构建系统能力——理解版本号的含义,即理解 Carbon 语言与工具链当前所处的演化阶段。

【免费下载链接】carbon-langCarbon Language's main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 9:29:57

如何在其他编辑器、VS Code 和终端 shell 中启用 Helix 按键模式

如何在其他编辑器、VS Code 和终端 shell 中启用 Helix 按键模式 【免费下载链接】helix A post-modern modal text editor. 项目地址: https://gitcode.com/GitHub_Trending/he/helix 如果你的日常编辑环境不全是 Helix——比如要在 VS Code、IntelliJ IDEA 或终端的 Z…

作者头像 李华
网站建设 2026/9/11 9:25:52

车载Linux系统启动问题定位与调试实战指南

1. 车载Linux系统问题定位的核心挑战 在车载电子系统日益复杂的今天&#xff0c;Linux凭借其开源、稳定和可定制的特性&#xff0c;已成为智能座舱和自动驾驶域控制器的首选操作系统。但不同于传统服务器环境&#xff0c;车载Linux面临着独特的调试挑战&#xff1a; 硬件耦合度…

作者头像 李华
网站建设 2026/9/11 9:25:36

煤矿水力割缝瓦斯卸压技术原理与应用

1. 钻孔周围水力割缝瓦斯卸压技术概述在煤矿开采过程中&#xff0c;瓦斯压力控制是关乎安全生产的核心环节。传统瓦斯抽采方法往往存在效率低、周期长等问题&#xff0c;而水力割缝技术通过高压水射流在煤层中形成定向裂缝&#xff0c;为瓦斯流动创造了高效通道。这项技术最早可…

作者头像 李华
网站建设 2026/9/11 9:25:00

AI Agent进业务系统:开放生态后的四大关键挑战与工程化落地

1. 开放生态这一步&#xff0c;到底解决了什么问题WorkBuddy 开放生态的动作&#xff0c;放在整个 AI 工具链的演进里看&#xff0c;其实是一个很有标志性的事件。它把原本封闭在 IDE 里的 AI 能力&#xff0c;从“编辑器里的结对程序员”解放成了“可以嵌入任意业务系统的智能…

作者头像 李华
网站建设 2026/9/11 9:22:52

2026年AI降AI率工具测评与技术解析

1. 2026年AI工具生态现状与降AI率需求背景 2026年的AI技术应用已经深入到各行各业的生产流程中&#xff0c;从内容创作到数据分析&#xff0c;从自动化编程到智能决策支持。但随着AI渗透率的提升&#xff0c;行业开始面临两个核心矛盾&#xff1a;一方面是AI生成内容的同质化问…

作者头像 李华