从 0 到 1:Carbon 编程语言实战指南——搭建 C++ 后继工具链并跑通第一个程序
【免费下载链接】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 是一个由 Google 主导的 C++ 后继语言实验项目,目标是给庞大 C++ 代码库提供现代化、可逐步迁移的出路,其仓库里既有语言设计文档,也有一套能真正编译.carbon源码到原生可执行文件的实验性工具链。这篇文章会带你从源码构建编译器、跑通第一个程序,再读懂仓库里的真实示例代码。
为什么要有 Carbon:C++ 解不了的题
C++ 至今仍是高性能软件的主力语言,但 docs/project/difficulties_improving_cpp.md 里写得很直白:几十年技术债让"渐进改良"难到几乎不可能。所以 Carbon 没有选择修补 C++,也没有 fork 它,而是走"后继语言"路线——C++ → Carbon,类比 JavaScript → TypeScript。
官方给后继语言定了四条硬标准,缺一不可:
- 性能对标 C++(基于 LLVM,能碰到底层位与地址);
- 与 C++ 双向零开销互操作,任何一层 C++ 库都可以单独先迁到 Carbon;
- 对 C++ 开发者学习曲线平缓;
- 支持按文件、按库的可规模化迁移。
先泼一盆冷水:README 开头就声明 Carbon 是实验项目,官方 FAQ 里明确写着"not ready for use"。现在的正确姿势不是急着上生产,而是参与设计讨论、贡献工具链,或者提前理解它的设计思路。
值不值得投入:先对号入座
官方 docs/project/faq.md 有一句很坦诚的话:如果你的项目技术上、经济上都适合用 Rust、Go、Kotlin,那就去用。Carbon 瞄准的是另一群人:
- 背着百万行级 C++ 代码、动不了架构的存量项目;
- 依赖大量第三方 C++ 库、无法接受 RPC 或 FFI 边界的团队;
- 对编译器、泛型设计、语言治理过程本身感兴趣的人。
三步跑起来:从源码构建编译器
Carbon 目前没有稳定的通用安装包,最直接的路径是从源码构建工具链(以 Ubuntu/Debian/WSL 为例)。
第 1 步,装齐四个构建依赖:
sudo apt update sudo apt install clang libc++-dev libc++abi-dev lld git第 2 步,克隆仓库:
git clone https://gitcode.com/GitHub_Trending/ca/carbon-lang cd carbon-lang第 3 步,一条命令构建并运行工具链的 help:
./scripts/run_bazelisk.py run //toolchain -- help这里不用手动装 Bazel——scripts/run_bazelisk.py会自动拉取 Bazelisk 并完成构建。首次构建时间较长,属于正常现象。
第一个程序:只有 5 行的 hello world
仓库里最小的可运行程序在 examples/hello_world.carbon:
import Core library "io"; fn Run() { Core.PrintStr("Hello world!\n"); }两个要点:import Core library "io"引入核心库的 io 模块(当前只实现了Print、PrintStr、ReadChar等少数函数,见 core/io.carbon);Run()是程序入口。
构建产物里已经带好了编译器,手动走一遍"编译 → 链接 → 运行"全流程:
./bazel-bin/toolchain/carbon compile --output=hello.o examples/hello_world.carbon ./bazel-bin/toolchain/carbon link --output=hello hello.o ./hello也可以跳过手动步骤,直接交给 Bazel:./scripts/run_bazelisk.py run //examples:hello_world(目标定义在 examples/BUILD)。
看个真东西:埃氏筛里的 Carbon 类语法
hello world 太浅,来看 examples/sieve.carbon——它用筛法计算 1000 以下的质数。摘出核心骨架:
class Sieve { impl as Core.UnformedInit {} // 声明该类型支持"先未初始化、后填充" var is_prime: array(bool, 1000); fn Make() -> Sieve { /* 初始化全部为 true,其余逻辑省略 */ } fn MarkMultiplesNotPrime(ref self, p: i32) { /* 划去倍数,省略 */ } }第一次读会有几个陌生点,其实都有讲究:
class声明类,var is_prime: array(bool, 1000)是定长数组,类型必须显式写出——这不是啰嗦,而是为了支持模式匹配语义(官方解释见 docs/project/faq.md 的"为什么变量声明必须带类型"一节);impl as ...是 Carbon 泛型系统的实现声明,相当于"给某个接口/能力提供一份实现";ref self表示方法以引用访问对象,避免拷贝;- 循环长这样:
for (n: i32 in Core.Range(1000)),类型写在迭代变量后面。
跑一下验证:./scripts/run_bazelisk.py run //examples:sieve,它会打印出全部 168 个质数。
设计赌注:Carbon 押在哪三件事上
泛型:checked 泛型 + 模板双轨
C++ 模板只能"实例化时才检查",报错又晚又难懂。Carbon 的 checked 泛型在定义处就完成完整类型检查,错误直接指出"没满足哪个要求";同时保留template语法用于 C++ 互操作。设计细节在 docs/design/generics/。
C++ 互操作:让 Clang 直接读你的头文件
工具链通过 Clang 加载 C++ 头文件的 AST,把公开 API 转成 Carbon 名字——std::vector在 Carbon 里就是Cpp.std.vector,双向调用零开销。目标文档在 docs/design/interoperability/。
内存安全:不推翻重来,而是分两步走
第一步:自动化迁移到面向 C++ 互操作的 Carbon 方言;第二步:增量重构出内存安全子集。近期就做几件低垂的果实:强化初始化状态追踪、支持动态边界检查的 API、用可见的unsafe语法标记残余未定义行为。规划见 docs/design/safety/。
工具链现状:诚实版
架构上工具链走的是经典分段流水线:Lex → Parse → Check(SemIR)→ Lower → LLVM → CodeGen,文档见 toolchain/docs/README.md。但要清醒:这是很早期的编译器,核心库函数很少,大量语法尚未实现完整,构建可能因依赖版本出问题。官方路线是先把 Carbon ↔ C/C++ 互操作做通,再交付 0.1 里程碑的 MVP,全图见 docs/project/roadmap.md。
继续深入的正确入口
- 示例代码:examples/ 下有 2024 Advent of Code 的 15 天解题代码,比 hello world 更能反映当前语言面貌;
- 设计决策:proposals/ 是 100 多份提案的档案馆,每个设计都附"考虑过的替代方案";
- 参与贡献:CONTRIBUTING.md 说明了设计讨论与工具链开发两条贡献路径。
下一步建议:先执行./scripts/run_bazelisk.py run //examples:sieve把质数打印出来,再对照 examples/sieve.carbon 逐行读一遍——这是目前理解 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),仅供参考