0.12.0
2024/4/20,0.12.0
终于发布了,历时 8 个月,有 268 位贡献者,一共进行了 3688 次提交!
过去的发行说明都异常的长,因为试图记录所有在开发周期中所有的变化,本次更新则进行了适当地删减,便于读者和维护者阅读!
INFO
注意: 存在一部分变动并未在本次的发行说明中提及,其中包括 API 的 Break Change
。
WARNING
有关于各平台和架构的支持情况,本次更新并未进行更改,故在此处不再提及!
API 变更
可以参考:0.12.0 升级指南
Autodoc 重构
目前我们已经可以使用全新的 Autodoc
,新的实现带来了更棒的文档阅读体验!
旧的实现
文件结构为:
5987 src/Autodoc.zig
435 src/autodoc/render_source.zig
10270 lib/docs/commonmark.js
1245 lib/docs/index.html
5242 lib/docs/main.js
2146 lib/docs/ziglexer.js
25325 total
编译产物结构(演示使用的标准库文档)为:
272K commonmark.js
3.8M data-astNodes.js
360K data-calls.js
767K data-comptimeExprs.js
2.2M data-decls.js
896K data-exprs.js
13K data-files.js
45 data-guideSections.js
129 data-modules.js
15 data-rootMod.js
294 data-typeKinds.js
3.2M data-types.js
38K index.html
158K main.js
36M src/ (470 .zig.html files)
78K ziglexer.js
总输出大小为 47M,经过gzip处理后为 5.7M!
src/Autodoc.zig
用于处理 ZIR 代码(zig 编译时产生的中间代码),输出 json 以便 js 使用,这就导致很多代码无法通过某些数据(这些数据很可能是无效的),重建 AST 语法树lib/docs/commonmark.js
是一个第三方的 markdown 实现,但它的特性有点太多了,例如,我们并不希望在文档注释中使用HTML标签,因为这样会让源代码的注释无比丑陋,应当只渲染源代码和 markdown。lib/docs/ziglexer.js
是 js 中针对 zig 的语义标记实现。事实上,zig 已经在标准库中公开了由 zig 实现的语义标记。有趣的是,andrewrk 看到这个东西被添加进来的时候应该两眼一黑,具体可以见 Issue 16306 Issue 16490 。src/autodoc/render_source.zig
是一种将.zig
文件转换为带有语法高亮但不是交互式的.zig.html
文件。
新的实现
文件结构为:
942 lib/docs/main.js
403 lib/docs/index.html
933 lib/docs/wasm/markdown.zig
226 lib/docs/wasm/Decl.zig
1500 lib/docs/wasm/markdown/Parser.zig
254 lib/docs/wasm/markdown/renderer.zig
192 lib/docs/wasm/markdown/Document.zig
941 lib/docs/wasm/main.zig
1038 lib/docs/wasm/Walk.zig
6630 total
编译产物结构(演示使用的标准库文档)为:
12K index.html
32K main.js
192K main.wasm
12M sources.tar
总输出大小为: 12M,经过gzip处理后为 2.3M!
可以看到,新的实现的代码和产物都很简洁,产物刚刚好只有 4 个文件,并且文件大小直接缩减到了 1/4 。
新的实现不仅仅是表面看上去更简单,实际上它较之旧实现更加的强大,因为新的实现并不会处理 ZIR,而是直接读取解析源代码文件(sources.tar
就是打包的源代码),这意味着它拥有完整的源代码信息,不需要进行一些乱七八糟的推断。
此方案是使用 zig 编写的 WebAssembly 模块,这允许其重用编译器中的组件,例如分词器,解析器和其他用于对 zig 代码进行操作的一些程序。
通过 HTTP 请求sources.tar
文件并解压后,会将其直接送入 Wasm 模块的内存中,针对 tar 文件使用 std.tar
进行解析,源代码就地进行解析,并额外进行一些计算添加 hash 表。
针对目前的实现,优化空间可以使用多线程来加速解析,但目前来看单线程已经足够快了,似乎没有必要。
携带标准库文档
在 zig 的 0.11.0
中,zig 发行时会带有一个 docs/std/
目录,其中包含着旧autodoc 实现构建产物(足足 47M 大小)。
在本次重写中,直接删除这些构建产物,作为代替,提供了 zig std
命令,这允许使用自带的 autodoc 生成器来打开一个浏览器窗口查看文档说明,首次使用此命令时,会先执行一次针对 lib/compiler/std-docs.zig
的编译操作。
HTTP 服务器会动态创建请求的文件,包括 main.wasm 重建(如果任何源文件发生更改)和构造 sources.tar ,这意味着在查看文档时,对文档文件或 autodoc 系统本身的任何源更改都会立即反映出来。在 URL 前面加上 /debug URL 会使用 WebAssembly 模块的调试版本。
这意味着贡献者可以通过在浏览器窗口中按刷新来测试对 Zig 标准库文档以及 autodocs 功能的更改,只需要 Zig 的二进制发行版。
总之,这使的zig的安装大小从 317M 减少到了 268M (-15%)。
编译器的 ReleaseSmall 版本从 10M 缩小到 9.8M (-1%)。
构建文档时间
Autodocs 生成现在作为编译器 pipeline 的一部分完成,而不是在最后添加。它也不再依赖于 pipeline 的其他部分。
以下是构建标准库文档所需要的时间:
Benchmark 1 (3 runs): old/zig test /home/andy/dev/zig/lib/std/std.zig -fno-emit-bin -femit-docs=docs
measurement mean ± σ min … max outliers delta
wall_time 13.3s ± 405ms 12.8s … 13.6s 0 ( 0%) 0%
peak_rss 1.08GB ± 463KB 1.08GB … 1.08GB 0 ( 0%) 0%
cpu_cycles 54.8G ± 878M 54.3G … 55.8G 0 ( 0%) 0%
instructions 106G ± 313K 106G … 106G 0 ( 0%) 0%
cache_references 2.11G ± 35.4M 2.07G … 2.14G 0 ( 0%) 0%
cache_misses 41.3M ± 455K 40.8M … 41.7M 0 ( 0%) 0%
branch_misses 116M ± 67.8K 116M … 116M 0 ( 0%) 0%
Benchmark 2 (197 runs): new/zig build-obj -fno-emit-bin -femit-docs=docs ../lib/std/std.zig
measurement mean ± σ min … max outliers delta
wall_time 24.6ms ± 1.03ms 22.8ms … 28.3ms 4 ( 2%) ⚡- 99.8% ± 0.3%
peak_rss 87.3MB ± 60.6KB 87.2MB … 87.4MB 0 ( 0%) ⚡- 91.9% ± 0.0%
cpu_cycles 38.4M ± 903K 37.4M … 46.1M 13 ( 7%) ⚡- 99.9% ± 0.2%
instructions 39.7M ± 12.4K 39.7M … 39.8M 0 ( 0%) ⚡-100.0% ± 0.0%
cache_references 2.65M ± 89.1K 2.54M … 3.43M 3 ( 2%) ⚡- 99.9% ± 0.2%
cache_misses 197K ± 5.71K 186K … 209K 0 ( 0%) ⚡- 99.5% ± 0.1%
branch_misses 184K ± 1.97K 178K … 190K 6 ( 3%) ⚡- 99.8% ± 0.0%
过去需要 13 秒以上,而现在只需要 25 毫秒。
Autodoc 新特性
更加可靠的链接:由于拥有完整的源代码,故我们拥有所有元信息,并且可以编写更强大的代码来从它们出现的上下文中查找标识符。
交互式源列表:只要按下 u,你可以立刻查看当前声明或者定义的源代码(通过更改 location 哈希实现)!
更加清晰的列表
搜索支持注释
更加友好的错误集合展示(支持通过其他的声明进行跳转)
函数说明也会展示错误类型说明
正确的类型检测(旧实现可能会猜错)
浏览历史的正确记录(依赖于
popstate
事件 和历史记录 api)
INFO
更加全面的信息,可以查看 commit diff。
编译器
x86 后端
x86 后端现在通过了行为测试套件的 1765/1828(97%),与 LLVM 后端相比。由于它提供了显著更快的编译速度,所以在开发过程中有时会发现它很有用:
Benchmark 1 (8 runs): zig-0.12.0 build-exe hello.zig
measurement mean ± σ min … max outliers delta
wall_time 667ms ± 26.7ms 643ms … 729ms 1 (13%) 0%
peak_rss 175MB ± 19.3MB 168MB … 223MB 1 (13%) 0%
cpu_cycles 3.42G ± 532M 3.21G … 4.74G 1 (13%) 0%
instructions 6.20G ± 1.05G 5.83G … 8.79G 1 (13%) 0%
cache_references 241M ± 19.9M 234M … 291M 1 (13%) 0%
cache_misses 48.3M ± 1.26M 47.7M … 51.4M 1 (13%) 0%
branch_misses 35.3M ± 4.07M 33.7M … 45.4M 1 (13%) 0%
Benchmark 2 (26 runs): zig-0.12.0 build-exe hello.zig -fno-llvm -fno-lld
measurement mean ± σ min … max outliers delta
wall_time 196ms ± 5.77ms 187ms … 208ms 0 ( 0%) ⚡- 70.6% ± 1.7%
peak_rss 88.7MB ± 721KB 87.8MB … 90.4MB 2 ( 8%) ⚡- 49.3% ± 4.3%
cpu_cycles 842M ± 6.01M 836M … 866M 1 ( 4%) ⚡- 75.4% ± 6.0%
instructions 1.60G ± 9.62K 1.60G … 1.60G 0 ( 0%) ⚡- 74.1% ± 6.5%
cache_references 56.6M ± 378K 56.0M … 57.3M 0 ( 0%) ⚡- 76.6% ± 3.2%
cache_misses 8.43M ± 104K 8.30M … 8.79M 2 ( 8%) ⚡- 82.5% ± 1.0%
branch_misses 7.20M ± 30.2K 7.15M … 7.28M 2 ( 8%) ⚡- 79.6% ± 4.4%
当为 x86_64
目标编译时,可以通过传递 CLI 选项 -fno-llvm -fno-lld
,或者在 std.Build.Step.Compile
上设置构建系统标志 use_llvm
和 use_lld
为 false
来访问这个后端。这个后端现在能够编译许多Zig项目,包括编译器本身。
直到使用它作为默认后端前的任务:
- 100% 行为测试通过
- 改进调试信息
- 提高运行时性能
Windows 资源
Zig 现在支持编译(和交叉编译)Windows资源脚本(.rc
文件)和 .manifest
文件,并将结果.res
文件链接到 PE/COFF 二进制文件的资源表中。
- Add a .rc -> .res compiler to the Zig compiler
- Add zig rc subcommand, a (cross-platform) drop-in replacement for rc.exe
- Add preliminary support for Windows .manifest files
查看 Zig is now also a Windows resource compiler,了解这个功能的一些用例和使用细节。
链接器
Zig 现在支持 x86_64、aarch64 的 ELF 链接,并部分支持 riscv64。对 LLD 的依赖预计将在下一个发布周期中被删除。可以使用 -fno-lld
标志来使用当前不是默认的 Zig 链接器。
缓存系统
这个相当烦人的错误现在已经修复了:error: StreamTooLong when recompiling; duplicate source files in cache manifest。
修复方法是对缓存清单中列出的文件进行去重,这使得缓存命中速度显著提高。数据点:使用静态 musl libc 构建 hello world 缓存命中
Benchmark 1 (61 runs): master/zig build-exe hello.c -target native-native-musl -lc
measurement mean ± σ min … max outliers delta
wall_time 81.4ms ± 1.76ms 77.7ms … 87.1ms 1 ( 2%) 0%
peak_rss 64.6MB ± 77.7KB 64.4MB … 64.7MB 0 ( 0%) 0%
cpu_cycles 97.2M ± 1.04M 95.1M … 101M 1 ( 2%) 0%
instructions 153M ± 11.1K 152M … 153M 0 ( 0%) 0%
cache_references 2.21M ± 97.1K 2.05M … 2.54M 2 ( 3%) 0%
cache_misses 529K ± 24.4K 486K … 600K 4 ( 7%) 0%
branch_misses 409K ± 6.45K 397K … 437K 1 ( 2%) 0%
Benchmark 2 (189 runs): cache-dedup/zig build-exe hello.c -target native-native-musl -lc
measurement mean ± σ min … max outliers delta
wall_time 25.8ms ± 1.26ms 23.9ms … 30.7ms 11 ( 6%) ⚡- 68.4% ± 0.5%
peak_rss 65.2MB ± 61.8KB 65.1MB … 65.4MB 2 ( 1%) 💩+ 1.0% ± 0.0%
cpu_cycles 41.2M ± 608K 40.1M … 46.3M 4 ( 2%) ⚡- 57.6% ± 0.2%
instructions 64.3M ± 12.6K 64.3M … 64.4M 2 ( 1%) ⚡- 57.8% ± 0.0%
cache_references 1.28M ± 34.5K 1.21M … 1.35M 0 ( 0%) ⚡- 41.9% ± 0.7%
cache_misses 348K ± 18.6K 297K … 396K 0 ( 0%) ⚡- 34.2% ± 1.1%
branch_misses 199K ± 1.34K 197K … 206K 6 ( 3%) ⚡- 51.2% ± 0.2%
Bug 修复
Comptime 指针访问
Zig 在编译期访问指针有几个长期存在的错误。当试图以特殊的方式的方式访问指针,例如加载数组的切片或重新解引用内存时,你有时会遇到一个错误的编译错误,编译器会要求 comptime 解引用需要具有明确定义的布局的类型。
#19630 的合并解决了这个问题。在 0.12.0
中,编译器在进行与编译期内存有关的复杂操作时,不再报告错误的编译错误。这个改变也包括对编译期 @bitCast
逻辑的一些修复;特别是,包含指针的位转换聚合不再错误地强制在运行时进行操作。
当前版本包含的 Bugs
Zig 目前存在一些 已知的 bugs,甚至包含一些 编译错误!
Zig 目前仍不成熟,即使是使用 0.12.0
也可能需要参与 zig 开发才能使之顺利在某些项目开发上正常工作!
当 Zig 达到 1.0.0
时,一级支持 将获得一个额外的错误策略作为要求。
工具链
LLVM 17
当前发布的新版本已经更新至 LLVM 17.0.6!
Zig 现在直接生成 LLVM bitcode 模块文件,然后将这些文件传递给 LLVM 。这意味着一个没有 LLVM 库的 Zig 编译器仍然可以生成 .bc 文件,然后这些文件可以传递给 clang 进行编译。
musl 1.2.4
尽管musl v1.2.5 现在在上游可用,但这个版本的 Zig 仍然提供 v1.2.4 。预计 Zig 的下一个版本将使用新的的 musl。
glibc 2.38
当进行交叉编译时,现在可以使用 glibc 版本 2.35、2.36、2.37 和 2.38。
mingw-w64
根据 Martin Storsjö 的建议,Zig 现在跟踪 mingw-w64 的最新主分支提交。
路线图
0.13.0 发布周期的主要主题将是 编译速度。
在 0.13.0 发布周期中尽量实现一些里程碑特性:
- 将 x86 后端作为调试模式的默认后端。
- 链接器支持 COFF,移除对 LLD 的依赖。
- 启用增量编译以快速重建。
- 引入并发性到语义分析以进一步提高编译速度。
目前的思路是,优先考虑更快的编译将提高编译器本身的开发速度,从而在接下来的发布周期中修复更多的错误并完成更多的功能。
加快编译速度也可能会对语言本身做出一些调整。
Async/Await
特性进度
在 0.11.0
版本发布后,异步函数被冻结。由于多个尚未解决的问题,尚不知未来如何处理该特性:
- LLVM 无法优化它们。
- 第三方调试器无法调试它们。
- 取消问题。
- 异步函数指针阻止了堆栈大小的知晓。
这些问题是可以克服的,但需要时间,Zig团队目前正在关注其他优先事项。
贡献者和赞助者名单
请查看官方的 发行说明!