Blaise v0.10.0:本地后端、线程与增量编译

Hacker News Top 工具

摘要

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
  • 一种内存模型。自动引用计数统一应用于字符串、类和接口。没有 TObjectTInterfacedObject 的手动/自动区分;[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”] |=== | 特性 | 移除原因

| ShortStringAnsiStringWideStringUnicodeString | 被单一的 UTF-8 引用计数 string 类型替代

| with 语句 | 导致难以诊断的符号解析错误;破坏静态分析

| 旧式 object 类型 | 改用 record(栈/值类型)或 class(堆/引用类型)

| COM 风格的接口 GUID | 接口分发通过编译期 vtable 实现;GUID 是不必要的复杂性

| 多种语言模式 | 一种维护良好的方言胜过五种维护不善的方言

| assignresetrewriteblockread | 已被基于流的 I/O RTL 替代

| TObjectTInterfacedObject 的区分 | 在自动引用计数下采用统一的类模型;[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 编译器(gccclang
  • 用于运行时构建的 GNU make

注意:需要 FPC。Blaise 完全自托管——每个发布版本编译下一个版本。引导链从 releases/ 中的二进制文件开始。

=== 从发布版本引导

运行时构建使用 compiler/target/blaise 处的 Blaise 二进制文件编译其 Pascal 单元(blaise_str.pasblaise_arc.pasblaise_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 社区倾心打造 ❤️.

相似文章

QBE - 编译器后端:版本 1.3

Lobsters Hottest

QBE 1.3 是一个重要的编译器后端版本,新增了 7000 行代码,引入了一种新的 IL 匹配算法,针对 coremark 基准测试进行了优化(性能从 gcc -O2 的 40% 提升到超过 63%),支持 Windows ABI 和位置无关代码生成。

QBE – 编译器后端

Hacker News Top

QBE 是一个紧凑的、爱好级别的编译器后端,仅用 10% 的代码即可实现工业级优化编译器 70% 的性能,支持 amd64、arm64 和 riscv64,并采用简单的基于 SSA 的中间语言。

Zig 构建速度正在提升

Mitchell Hashimoto

Zig 0.15 相比 0.14 在编译时性能有显著提升,构建脚本编译时间从约 7 秒降至约 1.7 秒,完整构建时间从 41 秒降至 32 秒,且仍使用 LLVM。本文重点介绍了自托管后端和增量编译方面的进展。