Blaise v0.10.0:本地后端、线程与增量编译
摘要
Blaise v0.10.0 通过 QBE 增加了本地后端支持、线程功能和增量编译,推动这款现代 Object Pascal 编译器向自托管和更广泛的平台支持迈进。
查看缓存全文
缓存时间: 2026/06/10 00:23
graemeg/blaise
来源:https://github.com/graemeg/blaise
= Blaise Pascal 编译器 :icons: font :source-highlighter: rouge
你钟爱的 Pascal,为现代而重塑。
Blaise 是一款从零构建的下一代 Object Pascal 编译器,旨在消除数十年的遗留包袱。它优先考虑开发者生产力、内存安全和高性能执行。
== ✨ 愿景
Object Pascal 生态系统目前有两个选择:Embarcadero Delphi(专有,以 Windows 为先)和 Free Pascal(开源,但背负着 30 年累积的复杂度——五种语言模式、五种字符串类型、数千个包含文件)。
这款编译器采用了不同的路线:
- 一种语言模式。没有
{$mode}开关;不支持遗留方言。 - 一种字符串类型。UTF-8 引用计数字符串,基于 0 的索引。二进制数据使用
RawBytes。 - 一种内存模型。自动引用计数统一应用于字符串、类和接口。没有
TObject和TInterfacedObject的手动/自动区分;[Weak]用于打破循环引用。Free保留为立即释放的同义词。 - 干净的接口。没有 COM GUID;通过编译期 vtable 映射进行接口分发。
- 具体化泛型。编译期单态化——无类型擦除。
- 现代构建系统。使用
project.xml的 PasBuild;无需 makefile。 - 一流的调试器。OPDF 是默认调试格式;不需要 DWARF。
参见链接:docs/design.adoc[文档/设计.adoc] 了解完整架构和实现计划。
结果——一款现代的、跨平台的 Object Pascal 编译器,通过 https://c9x.me/compile/[QBE](最终是 LLVM)生成本机代码。单一语言模式、单一字符串类型、零 GUID 接口、具体化泛型,以及一流的 https://github.com/graemeg/opdebugger[OPDF] 调试格式支持。
== 🚀 项目状态
- 自托管:是。Blaise 引导并重新编译自身,达到字节级不动点。不再需要 FPC——整个工具链仅靠 Blaise 运行。
- 测试:2627 个测试且持续增长(从一开始就采用测试驱动开发)。测试套件本身在 Blaise 下编译。
- 后端:当前使用 QBE 后端,LLVM 后端正在积极开发中。
[cols=“1,3,1”, options=“header”] |=== | 阶段 | 目标 | 状态
| 1 | 引导管道——在 Linux x86_64 上通过 PasBuild 输出 Hello World | 完成 ✅
| 2 | 类型系统——类、记录、ARC、异常 | 完成 ✅
| 3 | 泛型 + 零 GUID 接口 | 完成 ✅
| 4 | OPDF 调试信息输出 | 完成 ✅
| 5 | 自托管 | 完成 ✅
| 6 | 语言改进 + 扩展 RTL 和 StdLib + 错误修复 | 进行中
| 7 | LLVM + Windows + macOS ARM64 | 计划中
| 8 | LSP + VS Code 扩展 | 计划中
| 9 | FPC/Delphi 代码库迁移分析器 | 计划中 |===
== 经典 Pascal 中移除的内容
[cols=“1,3”, options=“header”] |=== | 特性 | 移除原因
| ShortString、AnsiString、WideString、UnicodeString
| 被单一的 UTF-8 引用计数 string 类型替代
| with 语句
| 导致难以诊断的符号解析错误;破坏静态分析
| 旧式 object 类型
| 改用 record(栈/值类型)或 class(堆/引用类型)
| COM 风格的接口 GUID | 接口分发通过编译期 vtable 实现;GUID 是不必要的复杂性
| 多种语言模式 | 一种维护良好的方言胜过五种维护不善的方言
| assign、reset、rewrite、blockread
| 已被基于流的 I/O RTL 替代
| TObject 和 TInterfacedObject 的区分
| 在自动引用计数下采用统一的类模型;[Weak] 用于打破循环
|===
== 📢 社区
核心架构仍在最终确定中,因此该项目目前不接受代码贡献。非常欢迎对语言设计、语法选择以及 Blaise 未来方向的反馈——请使用 GitHub 上的 https://github.com/graemeg/blaise/discussions[讨论] 标签。
== 仓库布局
本项目采用 PasBuild 的多模块布局。每个包含 project.xml 的子目录都是一个独立模块;根目录的 project.xml 是聚合器。
…. project.xml 根聚合器 (packaging=pom) │ ├── compiler/ 编译器二进制文件 (packaging=application) │ ├── project.xml │ └── src/ │ ├── main/pascal/ uLexer、uParser、uAST、uCodeGenQBE, … │ └── test/pascal/ 测试套件 (blaise.testing, 由 Blaise 编译) │ ├── runtime/ 始终链接的运行时 (packaging=library) │ ├── project.xml │ ├── Makefile │ └── src/ │ ├── main/c/ C 垫片 (blaise_exc.c、blaise_io.c, …) │ ├── main/pascal/ system.pas、blaise_str.pas、blaise_arc.pas, … │ └── test/pascal/ 运行时测试 (punit, 由 Blaise 编译) │ ├── stdlib/ 标准库 —— 通过 uses 子句选择性加入 │ ├── project.xml │ └── src/ │ └── main/pascal/ sysutils.pas、classes.pas、math.pas, … │ ├── tools/ │ └── migration-analyser/ FPC/Delphi 迁移报告工具 (packaging=application) │ ├── project.xml 依赖于 compiler 模块 │ └── src/ │ ├── main/pascal/ │ └── test/pascal/ │ ├── vendor/qbe/ 供应商 QBE 后端源码 (锁定版本,从源码构建) └── docs/ 设计文档和规范 ….
PasBuild 将每个模块编译到各自的 target/ 子目录。构建输出永远不会提交到仓库。
== 构建
=== 先决条件
- 先前发布的 Blaise 二进制文件(参见
releases/) - https://github.com/graemeg/pasbuild[PasBuild]
- 用于构建供应商 QBE 后端和链接的 C 编译器(
gcc或clang) - 用于运行时构建的 GNU
make
注意:不需要 FPC。Blaise 完全自托管——每个发布版本编译下一个版本。引导链从 releases/ 中的二进制文件开始。
=== 从发布版本引导
运行时构建使用 compiler/target/blaise 处的 Blaise 二进制文件编译其 Pascal 单元(blaise_str.pas、blaise_arc.pas、blaise_sys.pas)。在干净的检出上,该二进制文件尚不存在,因此必须通过 BLAISE make 变量显式传递发布版本二进制文件。
[source,shell]
0. 构建供应商 QBE 后端(一次性——除非更新 vendor/qbe/,否则无需重复)
cd vendor/qbe && make && cd ../..
1. 使用发布版本二进制文件构建运行时(BLAISE= 避免鸡生蛋问题)
cd runtime && make BLAISE=../releases/v0.7.0/blaise && make install && cd ..
2. 使用最新发布版本二进制文件编译编译器
releases/v0.7.0/blaise
–source compiler/src/main/pascal/Blaise.pas
–unit-path compiler/src/main/pascal
–unit-path runtime/src/main/pascal
–unit-path stdlib/src/main/pascal
–emit-ir > /tmp/blaise.ssa
3. 汇编并链接
vendor/qbe/qbe -o /tmp/blaise.s /tmp/blaise.ssa gcc -o compiler/target/blaise /tmp/blaise.s compiler/target/blaise_rtl.a
一旦 compiler/target/blaise 存在,后续的 RTL 重建(make && make install)无需覆盖即可工作。步骤 0 中的 QBE 构建是一次性的,在重新构建编译器时无需重复。
=== 引导开发分支
上述方法在最新发布版本二进制文件足够新以编译当前源码时有效。在发布版本之间,情况将不再成立:一旦某个提交教会解析器一个新特性,而后来的提交在运行时/编译器中使用该特性,则发布版本二进制文件无法直接构建 master。
scripts/rolling-bootstrap.sh 从最后一个发布版本二进制文件开始,逐提交重建链条,直到检出的修订版本,生成一个可用的 -pre 引导二进制文件。参见 link:scripts/BOOTSTRAP.adoc[scripts/BOOTSTRAP.adoc] 了解先决条件(将发布版本二进制文件放在 releases/ 下)和用法。
=== 通过 PasBuild 构建
PasBuild 可以使用 Blaise 二进制文件驱动完整的编译和测试流程:
[source,shell]
pasbuild compile -m blaise-compiler –compiler compiler/target/blaise pasbuild test -m blaise-compiler –compiler compiler/target/blaise
=== 运行测试
[source,shell]
pasbuild test -m blaise-compiler –compiler compiler/target/blaise
=== 验证自托管不动点
在对编译器进行任何更改后,验证编译器能否重现自身:
[source,shell]
./scripts/fixpoint.sh
这将生成阶段二和阶段三的 IR,并确认它们是否相同。
=== 运行编译器
构建完成后,编译器二进制文件位于 compiler/target/blaise。
[source,shell]
编译单文件程序
compiler/target/blaise –source Hello.pas –emit-ir > Hello.ssa vendor/qbe/qbe -o Hello.s Hello.ssa gcc -o Hello Hello.s compiler/target/blaise_rtl.a
带单元搜索路径编译
compiler/target/blaise –source MyApp.pas
–unit-path src/units
–emit-ir > MyApp.ssa
仅输出 QBE IR(用于调试编译器本身)
compiler/target/blaise –source Hello.pas –emit-ir
== 许可证
Apache License v2.0 附带运行时库异常。参见 link:LICENSE[LICENSE]。
由 Graeme 为 Pascal 社区倾心打造 ❤️.
相似文章
Blaise – 一款面向 QBE 的现代、自举、无历史包袱的 Object Pascal 编译器
Blaise 是一款现代且自举的 Object Pascal 编译器,旨在通过提供单一语言模式、统一的内存模型以及基于 QBE 的原生代码生成,来消除遗留系统的负担。
QBE - 编译器后端:版本 1.3
QBE 1.3 是一个重要的编译器后端版本,新增了 7000 行代码,引入了一种新的 IL 匹配算法,针对 coremark 基准测试进行了优化(性能从 gcc -O2 的 40% 提升到超过 63%),支持 Windows ABI 和位置无关代码生成。
QBE – 编译器后端
QBE 是一个紧凑的、爱好级别的编译器后端,仅用 10% 的代码即可实现工业级优化编译器 70% 的性能,支持 amd64、arm64 和 riscv64,并采用简单的基于 SSA 的中间语言。
Zig 构建速度正在提升
Zig 0.15 相比 0.14 在编译时性能有显著提升,构建脚本编译时间从约 7 秒降至约 1.7 秒,完整构建时间从 41 秒降至 32 秒,且仍使用 LLVM。本文重点介绍了自托管后端和增量编译方面的进展。
Phel v0.36.0 – 运行于 PHP 之上的 Lisp,现支持数值塔(Numeric Tower)与一等公民 Var
Phel v0.36.0 已发布,为这款受 Lisp 启发的、编译为 PHP 的函数式编程语言引入了数值塔和一等公民 Var。