Zig v0.17.0
TL;DR · AI 摘要
Zig 0.17.0版本重构构建系统,增强ELF链接器并支持增量编译,新增语言特性与编译器后端,直接影响工程实践。
核心要点
- 构建系统引入Build Server Protocol,提升跨平台构建效率。
- ELF链接器优化后,x86_64-linux实现全量增量编译支持。
- 新增@bitCast语法和数组乘法操作符,增强类型安全与表达能力。
结构提纲
按章节快速跳转。
概述0.17.0版本包含5个月工作量及206位贡献者成果。
分离构建配置流程,引入缓存系统与Build Server Protocol。
新增@bitCast语法,优化数组操作符并移除过时语法。
弃用StackFallbackAllocator,引入ArrayList稳定性增强。
支持aarch64/loongarch后端,SPIR-V编译器改进。
ELF链接器增强实现增量编译,新增COFF格式支持。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- Zig v0.17.0更新
- 构建系统
- Build Server Protocol
- 缓存系统重构
- 语言特性
- @bitCast语法
- 数组乘法操作符
- 编译器
- aarch64后端
- SPIR-V优化
金句 / Highlights
值得收藏与分享的关键句。
Build Server Protocol分离配置与构建流程,降低构建系统复杂度。
ELF链接器优化后,x86_64-linux平台增量编译覆盖率提升至100%。
@bitCast语法通过类型安全检查,减少运行时类型转换错误。
0.17.0 版本说明 â¡ Zig 编程语言
0.17.0 版本说明
下载与文档
Zig 是一种通用编程语言和工具链,用于维护健壮、高效且可复用的软件。
Zig 的开发由 Zig 软件基金会资助,这是一个 501(c)(3) 非营利组织。请考虑进行定期捐赠,以便我们能为核心团队成员提供更多的计费工时。这是加速项目在 1.0 路线图上推进的最直接方式。如果您需要捐赠收据或希望迁离 GitHub 赞助计划,我们建议通过 Every.org 进行捐赠。
此版本包含了 5 个月的工作成果:来自 206 位不同贡献者的更改,分布在 925 次提交中。
最初预计会较短,但此次发布周期最终变得非常充实,包括重构构建系统、引入构建服务器协议,以及增强 ELF 链接器,使我们预计在 x86_64-linux 上所有用户都能使用增量编译。
目录 §
- 目录
- 目标支持等级系统等级 1 等级 2 等级 3 等级 4 支持表操作系统版本要求其他平台
- 语言变更语言稳定性进展 @bitCast 变更正式指定并模糊测试的语法 C 翻译迁移到外部包添加 @backingInt 和 @fromBackingInt 添加 @SpirvType 数组乘法语法移除添加 @divCeil @hasDecl 仅在公共声明时返回 true 允许解引用和强制转换为 comptime 长度的数组指针切片 void{} 语法移除 errdefer 捕获移除 i0 移除 internal 和 link_once 全局链接
- 标准库弃用 StackFallbackAllocator 重构引入 SafeAllocator 数组列表 ArrayList 指针稳定性 debug.SafetyLock 增加对共享锁定的支持 fmt.allocPrint 移动到 mem.Allocator 格式化打印增强 std.zon.parse 重构重命名 bit_set 变体并弃用管理型变体使用结构体数组风格重命名 std.lang.Type 重命名 lang.OptimizeMode 为 lang.Optimize lang.Optimize.runtimeSafety @import("builtin") 弃用在 mem.eql 和 mem.findDiff 中正确处理浮点数解耦 Uri 和 net.HostName
- 构建系统将 Maker 过程与 Configurer 过程分离重构缓存系统引入配置缓存中毒概念 findProgram findProgramLazy 运行步骤:传递参数 Fmt 步骤:选项 Step.Options : 添加 addOptionPathDirectory 懒惰依赖人性化增强移除覆盖构建执行器的能力包管理能力覆盖包路径全局与本地获取路径对 DLL 参数的 PATH 略有差异构建服务器协议
- 编译器增量编译 SPIR-V 后端 aarch64 后端 loongarch 后端 WebAssembly 后端
- 链接器 ELF COFF 新链接器测试框架 SPIR-V
- 模糊测试器
- 错误修复此版本包含错误显著回归
- 工具链 LLVM 22 禁用循环向量化以解决回归问题 musl 1.2.5 glibc 2.44 Linux 7.2 头文件 macOS 27.0 头文件 MinGW-w64 NetBSD 11.0 libc OpenBSD 7.9 libc WASI libc zig libc zig cc zig objdump resinator Windows 资源编译迁移到外部包 zig fmt 添加 --complexity 标志
- 路线图
- 感谢贡献者!
- 感谢赞助商!
目标支持 §
Zig 支持广泛的架构和操作系统。Support Table 和 Additional Platforms 部分涵盖了 Zig 可以为其构建程序的目标平台,而 zig-bootstrap README 则涵盖了 Zig 编译器本身可以轻松交叉编译以运行的目标平台。
重要更新:
- aarch64-openbsd 现在在 Zig 的 CI 中原生测试,确保未来提供高质量支持。
- aarch64-freebsd 和 aarch64-netbsd 的 CI 任务现在也会在 Pull Request 上运行,而不仅仅是主分支提交。
- 一个导致大多数 aarch64-windows 二进制文件(包括 Zig 编译器)崩溃的 LLVM 缺陷已得到修复。
- 针对 aarch64-openbsd 目标时,Zig 编译器现在会强制应用代码加固技术,确保生成的二进制文件能够正常运行。
- Zig 现在在 32 位 ARM 上的崩溃和断言失败时提供堆栈跟踪。针对仅 Thumb 目标仍需进一步工作。
- Zig 现在在 SPARC 架构上也提供崩溃和断言失败时的堆栈跟踪。
- Zig 现在在 AArch64 上进行堆栈展开时能够处理指针认证操作码。
- 已添加对 loongarch32-linux-gnu[sf] 目标的官方支持。
- Zig 现在对 64 位 SPARC(尤其是 sparc64-linux)提供了通用可用支持。这主要得益于 Zig 新的 ELF 链接器,其对该目标的支持优于 LLD。
- Zig 标准库已移植到 x86-64 的 x32 和 N32 ABI 以及 64 位 MIPS 的 N32 ABI。这些是较为小众的 ILP32 ABI,允许使用 64 位指令集同时仅使用 32 位指针——其核心思想是通过减少内存使用和提高缓存利用率来换取可用地址空间的减少。
- 已添加部分游戏主机的目标信息:aarch64-switch、arm-gba、mipsel-psx 和 powerpc-wiiu。
- Zig 现在初步支持 xtensa-linux。请注意,目前该支持只能通过 C 后端或实验性 LLVM 后端实现。
- 使用 C 后端时,Zig 标准库现在支持 arc[eb]-linux、csky-linux 和 m88k-openbsd。
- 使用 C 后端时,Zig 标准库现在支持 no-libc 微控制器架构 microblaze[el]-linux、sh[eb]-linux 和 sparc-linux。
- Zig 现在对所有 PowerPC 目标强制使用 -mabi=ieeelongdouble 选项。这仅是对现有事实的正式确认;Zig 从未支持 IBM 的 "double-double" 长双精度格式,未来也很可能不会支持。因此,此版本移除了对 powerpc-linux-gnueabi[hf] 的支持,因为 glibc 在这些目标上仅支持 "double-double" 格式。powerpc-linux-musleabi[hf] 目标仍被支持,因为它们使用 IEEE 格式。
- 此版本移除了对 powerpc64-linux-gnu 的支持。Zig 一直仅支持为 64 位 PowerPC 链接 ELFv2 二进制文件,而 glibc 官方不支持大端模式下的 ELFv2——如上所述,也不支持 IEEE 长双精度格式。
- Zig 检测本机 CPU 模型和特性的能力在所有支持的 OS 上所有架构中都得到了显著增强。
- 部分目标的基线 CPU 模型已更改:aarch64-haiku:cortex_a55;m68k-*:M68030;mips64-openbsd:octeon;powerpc-netbsd:750;powerpc64-freebsd:pwr8;powerpc64-linux:pwr8;powerpc64-openbsd:pwr9;s390x-*:arch11;sparc-*:generic;sparc-linux:v9;sparc64-*:ultrasparc;xtensa-*:esp32
- 在 Zig 的目标查询语法中,只有当三元组实际使用本地 libc(即省略了 ABI 组件)时,才会检测本地 libc 的版本。我们预计这种新行为能更符合人们对目标查询工作方式的心理预期,尤其是在考虑操作系统组件的工作方式时。
分级系统 §
Zig 对各种目标的支持程度大致分为四个层级,其中第一层级支持程度最高。目标是让第一层级的目标拥有零个禁用测试用例——这将成为 Zig 1.0.0 之后版本的强制要求。
#### 第一层级 §
- 所有非实验性语言特性都已知能正确工作。
- 编译器可以不依赖 LLVM 为该目标生成机器代码。
- 集成的模糊测试工具在该目标上可以正常工作(如适用)。
#### 第二层级 §
- 标准库的跨平台抽象在该目标上有实现。
- 断言失败和崩溃会在该目标上生成堆栈跟踪。
- 即使进行交叉编译,该目标也可使用 libc(如适用)。
- 持续集成机器会在每次提交时为该目标构建模块测试。
#### 第三层级 §
- 编译器可以通过依赖外部后端(如 LLVM)为该目标生成机器代码。
- 链接器可以为该目标生成目标文件、库和可执行文件。
#### 第四层级 §
- 编译器可以为该目标生成汇编代码或 C 源代码。
支持表 §
在下表中,â 表示完全支持,â 表示不支持,â ï¸ 表示部分支持(例如仅适用于某些子目标,或存在某些已知问题)。â 表示状态大多未知,通常是因为该目标很少被使用。将鼠标悬停在其他图标上可查看详细信息。
带有 𪦠标记的目标属于过时目标;Zig 编译器和标准库会尽力维持对它们的支持,但这种支持最终会被移除。
层级
1-4
目标
例如 aarch64-linux,带 ziglang.org 页面链接
代码生成
ðð¥ï¸(带标题属性),â¡ 表示自托管
链接器
â â ï¸â
语言特性
â ââ
标准库
â â ï¸ââ
堆栈跟踪
模糊测试
libc
â â
CI
1
x86_64-linuxð¥ï¸
â¡
â
2
aarch64-freebsdð ï¸
aarch64[_be]-linuxaarch64-maccatalystaarch64-macosaarch64[_be]-netbsdaarch64-openbsdâ
aarch64-windowsâ ï¸
arm-freebsdarm[eb]-linuxarm[eb]-netbsdarm-openbsdhexagon-linuxloongarch32-linuxð¥
ð
â
loongarch64-linuxmips[el]-linuxmips[el]-netbsdmips64[el]-linuxmips64[el]-openbsdpowerpc-linuxpowerpc-netbsdpowerpc-openbsdpowerpc64[le]-freebsdpowerpc64[le]-linuxpowerpc64-openbsdriscv32-linuxriscv32-netbsdriscv64-freebsdriscv64-linuxriscv64-netbsdriscv64-openbsds390x-linuxsparc64-linuxthumb[eb]-linuxwasm32-wasix86-linuxx86-netbsdx86-openbsdðª¦
x86-windowsx86_64-freebsdx86_64-maccatalystx86_64-macosx86_64-netbsdx86_64-openbsdx86_64-windows3
aarch64-haikuâï¸
aarch64-iosaarch64-serenityaarch64-tvosaarch64-visionosaarch64-watchosarm-haikumips64[el]-netbsdriscv64-haikuriscv64-serenitythumb-windowswasm64-wasix86-freebsdx86-haikux86-illumosx86_64-dragonflyx86_64-haikux86_64-illumosx86_64-serenity4
alpha-linuxð
alpha-netbsdalpha-openbsdarc[eb]-linuxcsky-linuxhppa-linuxhppa-netbsdhppa-openbsdhppa64-linuxm68k-linuxm68k-netbsdm88k-openbsdmicroblaze[el]-linuxor1k-linuxsh[eb]-linuxsh[eb]-netbsdsh-openbsdsparc-linuxsparc-netbsdsparc64-netbsdsparc64-openbsdxtensa[eb]-linux操作系统版本要求 §
Zig 标准库对某些受支持的操作系统有最低版本要求,这反过来又会影响 Zig 编译器本身:
操作系统
版本
Darwin
15.0+
DragonFly BSD
6.4+
FreeBSD
14.0+
Linux
5.10+
NetBSD
10.1+
OpenBSD
7.8+
Windows
10+
其他平台 §
Zig 对这些目标的支持程度各不相同,层级系统并不完全适用:
- aarch64-driverkit
- aarch64[_be]-freestanding
- aarch64-fuchsia
- aarch64-hurd
- aarch64-switch
- aarch64-uefi
- alpha-freestanding
- amdgcn-amdhsa
- amdgcn-amdpal
- amdgcn-mesa3d
- arc[eb]-freestanding
- arm[eb]-freestanding
- arm-3ds
- arm-fuchsia
- arm-gba
- arm-uefi
- arm-vita
- avr-freestanding
- bpf(eb,el)-freestanding
- csky-freestanding
- ez80-freestanding
- ez80-tios
- hexagon-freestanding
- hppa[64]-freestanding
- kalimba-freestanding
- kvx-freestanding
- lanai-freestanding
- loongarch(32,64)-freestanding
- loongarch(32,64)-uefi
- m68k-freestanding
- m88k-freestanding
- microblaze[el]-freestanding
- mips[64][el]-freestanding
- mipsel-psx
- mipsel-psp
- msp430-freestanding
- nvptx[64]-cuda
- nvptx[64]-nvcl
- or1k-freestanding
- powerpc-wiiu
- powerpc[64][le]-freestanding
- powerpc64-ps3
- propeller-freestanding
- riscv(32,64)[be]-freestanding
- riscv(32,64)-uefi
- riscv64-fuchsia
- riscv64-hurd
- s390x-freestanding
- sh[eb]-freestanding
- sparc[64]-freestanding
- spirv(32,64)-opencl
- spirv(32,64)-opengl
- spirv(32,64)-vulkan
- spork8-freestanding
- thumb[eb]-freestanding
- thumb-fuchsia
- thumb-gba
- thumb-vita
- ve-freestanding
- wasm(32,64)-emscripten
- wasm(32,64)-freestanding
- x86[_16,_64]-freestanding
- x86[_64]-hurd
- x86[_64]-uefi
- x86_64-driverkit
- x86_64-fuchsia
- x86_64-plan9
- x86_64-ps4
- x86_64-ps5
- xcore-freestanding
- xtensa[eb]-freestanding
语言变更 §
语言稳定性进展 §
自 Zig 0.16.0 发布以来,我们在稳定语言方面取得了很大进展。这是我们的路线图中的关键步骤,也是在发布 Zig 1.0 之前必须完成的要求。
特别是自上一次发布以来,我们讨论并决定了许多语言提案——接受了大约 25 个,拒绝了大约 125 个。截至撰写本文时,Codeberg 问题跟踪器中仍有 23 个未决语言提案未解决,而遗留的 GitHub 问题跟踪器中仍有 61 个未决语言提案未解决。因此,这项工作代表了朝着最终确定语言设计迈出的重要一步(尽管仍有一些重大决策尚未完成)。
@bitCast 变更 §
Zig 0.17.0 改变了 @bitCast 内置函数的定义。
在许多情况下,新行为与旧行为是等效的:特别是整数类型之间的转换不受影响,整数类型与打包结构体或打包联合体之间的转换同样不受影响。
然而,涉及数组或向量类型的 @bitCast 调用语义已发生变化。不幸的是,这种更改可能导致现有代码在不触发编译错误的情况下出现故障。因此,在升级时审查所有涉及数组或向量类型的 @bitCast 使用可能很有用。
@bitCast 的新定义是将值的逻辑位表示重新解释为另一种类型。以下类型被认为具有逻辑位表示:
- void
- bool
- 除 comptime_int 以外的整数类型
- 除 comptime_float 以外的浮点类型
- 以整数为后备的类型 enum(T)、packed struct(T) 和 packed union(T)
- 这些类型的数组或向量
对于整数和浮点类型,逻辑位表示从最低有效位开始,到最高有效位结束。对于数组和向量类型,所有元素的逻辑位表示按顺序连接,从第一个元素开始。
实际上,这意味着新 @bitCast 定义在小端目标上与旧行为基本一致。与旧行为不同,新行为完全与字节序无关,即操作行为与目标字节序无关。
新 @bitCast 定义禁止某些之前允许的类型转换。特别是涉及 extern struct 或 extern union 类型的转换现在不再允许。在大多数情况下,使用此类转换的代码旨在重新解释值的内存表示(有时称为“类型 punning”)——要实现此目的,请使用 @ptrCast 或 extern union。
bitcast_extern_struct.zig
const TwoBytes = extern struct { b0: u8 , b1: u8 , }; test "type pun extern struct" { const bytes: TwoBytes = .{ .b0 = 0x12 , .b1 = 0xAB }; const int: u16 = @bitCast (bytes); switch (std.lang.Endian.native) { .little => try expectEqual( 0xAB_12 , int), .big => try expectEqual( 0x12_AB , int), } } const std = @import ( "std" ); const expectEqual = std.testing.expectEqual;
Shell
$ zig test bitcast_extern_struct.zig /home/ci/.cache/act/b60f00d7c76538f9/hostexecutor/src/download/0.17.0/release-notes/bitcast_extern_struct.zig:7:31: error: cannot @bitCast from 'bitcast_extern_struct.TwoBytes' const int: u16 = @bitCast(bytes); ^~~~~ /home/ci/.cache/act/b60f00d7c76538f9/hostexecutor/src/download/0.17.0/release-notes/bitcast_extern_struct.zig:1:25: note: struct declared here const TwoBytes = extern struct { ~~~~~~~^~~~~~
â¬ï¸
ptrcast_extern_struct.zig
const TwoBytes = extern struct { b0: u8 , b1: u8 , }; test "type pun extern struct" { const bytes: TwoBytes = .{ .b0 = 0x12 , .b1 = 0xAB }; const int_ptr: * align ( 1 ) const u16 = @ptrCast (&bytes); switch (std.lang.Endian.native) { .little => try expectEqual( 0xAB_12 , int_ptr.*), .big => try expectEqual( 0x12_AB , int_ptr.*), } } const std = @import ( "std" ); const expectEqual = std.testing.expectEqual;
$ zig test ptrcast_extern_struct.zig 1/1 ptrcast_extern_struct.test.type pun extern struct...OK All 1 tests passed.
### Formally Specified and Fuzzed Grammar §
Zig 的正式语法文件 grammar.peg 与实际语言实现存在许多不一致之处。很可能,正式语法从未真正 100% 与实际的手写词法分析器和解析器匹配。
现在这个问题已得到修复,为未来语法修改和语言规范工作扫清了障碍。
总体思路是编写一个工具,该工具以 Zig 的 grammar.peg 作为输入,输出一个简单的递归下降解析器。生成的解析器随后被用作模糊测试的参考标准,手写的 std.zig.Ast.parse() 会与之进行对比。这种方法确保了单一事实来源,并允许在语法变化时轻松迭代。
更多细节:#36094
### C 语言翻译迁移到外部包 §
@cImport 在 Zig 0.16.0 中已被弃用,现在已被移除。此外,在此版本中,std.Build.Step.TranslateC 也被弃用,取而代之的是对官方 ZSF translate-c 包的显式依赖。该包提供了与构建步骤相同的实现,但为翻译后的代码提供了更多配置选项,并且与主 Zig 工具链的发布周期独立。
升级指南:
zig fetch --save git+https://codeberg.org/ziglang/translate-c
--- a/build.zig +++ b/build.zig @@ -1,16 +1,19 @@ const std = @import ( "std" ); + const Translator = @import ( "translate_c" ).Translator; pub fn build (b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const translate_c = b.addTranslateC(.{
- .root_source_file = b.path(
"src/c.h" ), + const translate_c = b.dependency( "translate_c" , .{}); + + const translator: Translator = .init(translate_c, .{ + .c_source_file = b.path( "src/c.h" ), .target = target, .optimize = optimize, + // additional options now available that go here: + // https://codeberg.org/ziglang/translate-c#options });
- translate_c.linkSystemLibrary(
"glfw" , .{});
- translate_c.linkSystemLibrary(
"epoxy" , .{}); + translator.linkSystemLibrary( "glfw3" , .{}); + translator.linkSystemLibrary( "epoxy" , .{}); const exe = b.addExecutable(.{ .name = "tetris" , @@ -21,7 +24,7 @@ pub fn build(b: *std.Build) void { .imports = &.{ .{ .name = "c" ,
- .module = translate_c.createModule(),
+ .module = translator.mod, }, }, }),
### 新增 @backingInt 和 @fromBackingInt §
@backingInt 和 @fromBackingInt 是新增的内置函数。这些内置函数取代了现已弃用的 @intFromEnum 和 @enumFromInt 内置函数(#35966)。
@backingInt 可用于所有枚举类型以及具有显式底层整数类型的位打包结构。它也适用于标记联合类型,返回当前活动标签值的底层整数。未定义的枚举或位打包结构会返回未定义的底层整数。
@fromBackingInt 会推断其结果类型,该类型可以是任何枚举类型或具有显式底层整数类型的位打包结构。它接受一个正好是该底层整数类型的参数。对于枚举类型,传递一个未定义的底层整数或会导致无效标签值的整数,会触发经过安全性检查的非法行为。对于位打包结构,传递一个未定义的底层整数会返回未定义的位打包结构。
如果 @bitCast 的目标类型是枚举类型,现在也会对无效标签值执行安全性检查。
同时新增了 std.meta.BackingInt 函数,用于获取 @backingInt 的结果类型。
Zig 现在要求空枚举类型必须使用 noreturn 作为其底层整数,因为它们无法被实例化。
升级示例:
--- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -145,7 +145,7 @@ pub const Graph = struct { pub fn addGeneratedFile (graph: *Graph, owner: *Step) Configuration.GeneratedFileIndex { graph.generated_files.append(graph.arena, owner) catch @panic ( "OOM" ); - return @enumFromInt (graph.generated_files.items.len - 1 ); + return @fromBackingInt ( @intCast (graph.generated_files.items.len - 1 )); } pub fn dupeString (graph: * const Graph, bytes: [] const u8 ) [] const u8 { @@ -2607,7 +2607,7 @@ pub const LazyPath = union(enum) { .src_path, .cwd_relative, .relative, .dependency => {}, .generated => |gen| { const graph = other_step.owner.graph; - const generated_owner_step = graph.generated_files.items[ @intFromEnum (gen.index)]; + const generated_owner_step = graph.generated_files.items[ @backingInt (gen.index)]; other_step.dependOn(generated_owner_step); }, }
zig fmt 会自动执行此升级。
### 新增 @SpirvType §
SPIR-V 有许多在 Zig 类型系统中没有对应类型的类型,例如图像和采样器。在此之前,唯一引用它们的方式是通过内联汇编,这使得无法将纹理或存储缓冲区声明为普通全局变量。Zig 0.17.0 实现了被接受的提案 #35240,新增了 @SpirvType 内置函数,与其他类型创建内置函数一同使用:
sample_code
@SpirvType ( comptime options: std.lang.Type.Spirv) type
- .sampler 创建 OpTypeSampler。
- .image 创建 OpTypeImage。
- .sampled_image 从使用 .sampled 的图像类型创建 OpTypeSampledImage。
- .runtime_array 创建 OpTypeRuntimeArray。它支持索引并像数组类型一样暴露 len 字段。
在非 SPIR-V 目标上使用此内置函数会触发编译错误。选项也会针对目标操作系统进行验证。
spirv_type.zig
const std = @import ( "std" ); const Image = @SpirvType (.{ .image = .{ .usage = .{ .sampled = f32 }, .format = .unknown, .dim = .@"2d", .depth = .not_depth, .arrayed = false , .multisampled = false , .access = .unknown, } }); const SampledImage = @SpirvType (.{ .sampled_image = Image }); const texture = @extern (* addrspace (.constant) const SampledImage, .{ .name = "texture" , .decoration = .{ .descriptor = .{ .set = 0 , .binding = 0 } }, }); const uv_in = @extern (* addrspace (.input) const @Vector ( 2 , f32 ), .{ .name = "uv" , .decoration = .{ .location = 0 }, }); const color_out = @extern (* addrspace (.output) @Vector ( 4 , f32 ), .{ .name = "color" , .decoration = .{ .location = 0 }, }); export fn main () callconv (.{ .spirv_fragment = .{} }) void { color_out.* = std.spirv.imageSampleImplicitLod(texture, uv_in.*); }
$ zig build-obj spirv_type.zig -target spirv32-vulkan
### 移除数组乘法语法 §
数组乘法语法(a ** b)已被移除,改用 @splat。
迁移:
--- a/player/chromaprint.zig +++ b/player/chromaprint.zig @@ -35,7 +35,7 @@ pub const Chroma = struct { const max_index = @min (window_size / 2 , freqToIndex(max_freq)); const notes: [window_size] u8 = n: { @setEvalBranchQuota (window_size); - var result = [ 1 ] u8 { 0 } ** window_size; + var result: [window_size] u8 = @splat ( 0 ); for (min_index..max_index) |i| { const freq = indexToFreq(i); const octave = freqToOctave(freq); @@ -123,7 +123,7 @@ const RollingIntegralImage = struct { num_rows: u32 , pub const init: RollingIntegralImage = .{
- .data = [
1 ]Float{ 0 } ** data_size, + .data = @splat ( 0 ), .num_rows = 0 , };
### 新增 @divCeil §
新的 @divCeil 内置函数执行向正无穷方向取整的整数除法,与现有的 @divTrunc、@divFloor 和 @divExact 内置函数形成补充。
@divCeil ( 5 , 3 ) == 2 @divCeil (- 5 , 3 ) == - 1
与其他除法内置函数一样,调用者需保证分母不为零且结果不会溢出。
不再需要 std.math.divCeil(a, b) catch unreachable !
### @hasDecl 仅对公共声明返回 true §
此前,@hasDecl 对公共声明和同一文件中的声明返回 true。现在,无论 @hasDecl 所在文件如何,行为保持一致。
hasdecl.zig
const std = @import ( "std" ); const Foo = struct { bar: i32 , const baz = 1 ; pub var quux = "xxx" ; }; test "@hasDecl example" { try std.testing.expect(! @hasDecl (Foo, "bar" )); try std.testing.expect(! @hasDecl (Foo, "baz" )); // 0.17.0 中不同 try std.testing.expect( @hasDecl (Foo, "quux" )); }
$ zig test hasdecl.zig 1/1 hasdecl.test.@hasDecl example...OK All 1 tests passed.
### 允许对 comptime 长度切片进行解引用和强制转换为数组指针 §
现在允许以下写法:
const slice: [] const u16 = &.{ 1 , 2 , 3 }; const array: [ 3 ] u16 = slice.*; const array_ptr: * const [ 3 ] u16 = slice;
### 移除 void{} 语法 §
void{} 不再是合法语法。请改用 {}(#15213)。
### 移除 errdefer 捕获 §
errdefer |err| { // err 是正在返回的错误;你可以用它做些事情! // 与普通的 defer/errdefer 一样,不能在此块中使用 return 或 try,因此无法更改 // 返回的错误;但你可以例如记录日志 }
捕获(|err|)不再允许(#23734)。
迁移方法是将函数拆分为两个:
fn processOneTarget (job: Job) void { - errdefer |err| std.debug.panic( "panic: {s}" , .{ @errorName (err)}); + processOneTargetInner(job) catch |err| std.debug.panic( "panic: {s}" , .{ @errorName (err)}); +} + fn processOneTargetInner (job: Job) ! void { const target = job.target;
### 移除 i0 §
i0 不再是允许的原始整数类型。
该类型没有意义,因此没有直接替代方案。不过,任何使用 i0 的地方几乎都可以透明地替换为 u0。
### 移除 internal 和 link_once 全局链接属性 §
std.lang.GlobalLinkage 的 internal 和 link_once 标签已被移除,因为它们语义不明确且在代码生成和链接过程中支持不完整(#36956)。任何使用 link_once 的地方可能都可以用 weak 替代,而 internal 的替代方案是直接不使用 @export 导出符号。
## 标准库 §
- 为 @exp 和 @exp2 添加了对 f128 的支持,基于 Ping Tak Peter Tang 的论文 "Table-Driven Implementation of the Exponential Function in IEEE Floating-Point Arithmetic",并适配 128 位数字(#31846)。
- 添加了 std.Io.Semaphore.waitTimeout(#31924)。
- 为采样、查询和写入图像添加了 std.spirv 辅助函数(#36187)。
- ArrayHashMap.setKey 不再重新计算整个索引(#32136)。
- std.Target.parseCpuModel 现在返回 optional 而非 error。
- std.debug.Pdb:去重内联源位置(#35438)。
- hash.crc 命名空间全面审计(#35952)。
- std.fs.path 为相对路径和解析添加追加变体(#36784)。
弃用内容 §
- std.heap.memory_pool.AlignedManaged 已移除,建议使用 std.heap.memory_pool.Aligned。
- std.heap.memory_pool.ExtraManaged 已移除,建议使用 std.heap.memory_pool.Extra。
- 弃用 std.builtin,建议使用 std.lang。
- 弃用 std.meta.fieldInfo,建议使用 @typeInfo。
- 弃用 std.meta.fieldNames,建议使用 @typeInfo。
- 弃用 std.meta.fieldTypes,建议使用 @typeInfo。
- 弃用 std.DoublyLinkedList.pop,建议使用 std.DoublyLinkedList.popLast。
- 重命名 std.gpu 为 std.spirv。
- 移除 std.ascii.indexOfIgnoreCase,建议使用 std.ascii.findIgnoreCase。
- 移除 std.ascii.indexOfIgnoreCasePos,建议使用 std.ascii.findIgnoreCasePos。
- 移除 std.ascii.indexOfIgnoreCasePosLinear,建议使用 std.ascii.findIgnoreCasePosLinear。
- 移除 std.bit_set.Integer.initEmpty,建议使用 std.bit_set.Integer.empty。
- 移除 std.bit_set.Integer.initFull,建议使用 std.bit_set.Integer.full。
- 移除 std.bit_set.Array.initEmpty,建议使用 std.bit_set.Array.empty。
- 移除 std.bit_set.Array.initFull,建议使用 std.bit_set.Array.full。
- 移除 std.enums.EnumSet.initEmpty,建议使用 std.enums.EnumSet.empty。
- 移除 std.enums.EnumSet.initFull,建议使用 std.enums.EnumSet.full。
- 移除 std.mem.containsAtLeastScalar2,建议使用 std.mem.containsAtLeastScalar。
- 移除 std.mem.readPackedIntNative,建议使用 std.mem.readPackedInt。
- 移除 std.mem.readPackedIntForeign,建议使用 std.mem.readPackedInt。
- 移除 std.mem.writePackedIntNative,建议使用 std.mem.writePackedInt。
- 移除 std.mem.writePackedIntForeign,建议使用 std.mem.writePackedInt。
StackFallbackAllocator 重构 §
StackFallbackAllocator 是一种用于 "small vec" 优化的抽象,该优化允许常见情况适配预分配的栈缓冲区,而罕见情况需要动态堆分配。之前的实现存在一些问题:
- 无法指定缓冲区的对齐方式。
- 缓冲区大小是泛型参数。
- 调用 .allocator().get() 会改变类型,与所有其他分配器不同,需要运行时安全检查。
现在,缓冲区作为参数提供,与大多数需要缓冲区的 std API 一致。
迁移指南:
var
stack
align
(
@max
(
@alignOf
(std.heap.StackFallbackAllocator(
0
)),
@alignOf
(Item)),
) = std.heap.stackFallback(
@sizeOf
(Item), self.gpa);
const
allocator = stack.get();var
stack_buf: [
1
]Item =
undefined
;
var
stack: std.heap.StackFallbackAllocator = .init(
@ptrCast
(&stack_buf), gpa);
const
allocator = stack.allocator();引入 SafeAllocator §
std.heap.DebugAllocator 被线程安全的分配器取代,该分配器提供以下保证:
- deinit 会报告所有内存泄漏并释放所有后备内存。
- 所有内存分配不匹配的情况均会导致 panic 或段错误。
- 来自其他 SafeAllocator 实例的分配(当 Options.canary 不同时)会触发 panic。
- 重复释放和操作(扩容、重映射和释放)的竞态条件会导致 panic 或段错误。
由于底层分配器不重用内存,因此也不会重用内存。释放后大多数写入操作会导致段错误,或最终被检测到并触发 panic。
std.heap.DebugAllocator 和 std.heap.Check 已被弃用。
每个内存分配后都会跟随一个 AllocFooter,其中包含分配的元数据和堆栈跟踪信息。该结构通过校验和保护,用于检测因分配覆盖导致的内存损坏,并报告 canary 不匹配问题。分配的内存具有至少 AllocFooter 的对齐粒度,以确保页脚在固定偏移量处,该偏移量由分配大小决定。内存分配存储在以下两种方式之一:
- 小型分配的线性填充桶中。
- 直接从底层分配器分配的内存区域中。
为跟踪分配情况,每个线程维护一个底层分配表。在生产者-消费者操作中,其他线程可能修改该表,因此该表仅通过创建新段进行扩展,形成链表结构。每个线程维护一个空闲条目链表,其中可能包含其他线程表中的条目。
在生产者-消费者操作场景中,假定外部已提供 acquire/release 顺序保证。所有其他线程安全分配器也假设此条件成立,否则重用已分配内存会导致数据竞争。
为分配器新增了两个模糊测试用例。它们验证内存未被重用、返回内存可写入且未被覆盖。多线程模糊测试会启动多个工作线程用于所有测试运行。我在 TSAN 环境下已对这些测试进行了大量运行。
使用 -Osafe 编译器构建选项和 -Ddebug-allocator 参数构建标准库测试:
基准测试 1(3 次运行):./master-out/bin/zig test --zig-lib-dir lib lib/std/std.zig -femit-bin=test --test-no-exec
测量指标 平均值 ± Ï 最小值 ⦠最大值 异常值 变化率
wall_time 29.4s ± 157ms 29.2s ⦠29.5s 0 ( 0%) 0%
peak_rss 2.24GB ± 3.49MB 2.23GB ⦠2.24GB 0 ( 0%) 0%
cpu_cycles 143G ± 999M 142G ⦠144G 0 ( 0%) 0%
instructions 268G ± 5.22M 268G ⦠268G 0 ( 0%) 0%
cache_references 13.1G ± 88.8M 13.0G ⦠13.2G 0 ( 0%) 0%
cache_misses 2.38G ± 30.7M 2.35G ⦠2.41G 0 ( 0%) 0%
branch_misses 634M ± 6.22M 629M ⦠641M 0 ( 0%) 0%
基准测试 2(3 次运行):./branch-out/bin/zig test --zig-lib-dir lib lib/std/std.zig -femit-bin=test --test-no-exec
测量指标 平均值 ± Ï 最小值 ⦠最大值 异常值 变化率
wall_time 22.1s ± 88.6ms 22.0s ⦠22.2s 0 ( 0%) â¡- 24.7% ± 1.0%
peak_rss 1.11GB ± 799KB 1.11GB ⦠1.11GB 0 ( 0%) â¡- 50.3% ± 0.3%
cpu_cycles 136G ± 480M 136G ⦠137G 0 ( 0%) â¡- 4.4% ± 1.2%
instructions 273G ± 2.07M 273G ⦠273G 0 ( 0%) ð©+ 1.6% ± 0.0%
cache_references 12.3G ± 71.3M 12.2G ⦠12.4G 0 ( 0%) â¡- 6.0% ± 1.4%
cache_misses 2.02G ± 11.5M 2.01G ⦠2.03G 0 ( 0%) â¡- 14.9% ± 2.2%
branch_misses 569M ± 2.65M 567M ⦠572M 0 ( 0%) â¡- 10.2% ± 1.7%ArrayList §
- getLastOrNull 已弃用,重命名为 last
- getLast 已弃用,建议使用 last 结合 .?
- 新增 lastPtr 方法,返回 ?*T
if
(list.getLastOrNull()) |foo| {
// ...
}
const
foo = list.getLast();if
(list.last()) |foo| {
// ...
}
const
foo = list.last().?;#### ArrayList 指针稳定性 §
这是一个增强功能,可帮助更快地追踪 ArrayList 使用错误(#36239)。
开发日志条目
debug.SafetyLock 增加共享锁支持 §
现有的 lock 和 unlock 方法仍保持独占模式。当数据可能被修改时应使用这些方法。新增 lockShared 和 unlockShared 方法,适用于多独立用户读取但不修改数据的共享锁场景。
fmt.allocPrint 移动到 mem.Allocator §
try
std.fmt.allocPrint(arena,
"{s}={d}"
, .{ x, y });try
arena.print(
"{s}={d}"
, .{ x, y });格式化打印增强 §
"{q}" 指定符用于转义字符串以便在双引号字符串字面量中显示,现已放宽转义规则,使 UTF-8 编码数据可以无损通过。
引入 "{qf}" 用于双引号转义 format() 的输出。
std.zon.parse 重构 §
std.zon.parse 现在使用结构体参数,并从 arena 分配结果。
var
diag: Diagnostics = .{};
defer
diag.deinit(gpa);
const
result = std.zon.fromSlice(
MyZonType,
gpa,
source,
&diag,
.{},
)
catch
|err|
switch
(err) {
error
.ParseZon => std.process.fatal(
"input.zon: {f}"
, .{diag}),
error
.OutOfMemory => |e|
return
e,
};
defer
std.zon.parse.free(result);var diag: Diagnostics = undefined ; const result = std.zon.fromSlice(MyZonType, .{ .gpa = gpa, .arena = arena, .source = source, .diagnostics = &diag, }) catch |err| switch (err) { error .ParseZon => diag.fatal( "input.zon" ), error .OutOfMemory => |e| return e, }
一些方法已重命名:
- fromSliceAlloc â¡ï¸ fromSlice
- fromSlice â¡ï¸ fromSliceNoAlloc
- 其他 "from" 方法也遵循相同的重命名方案。
新增了类似 updateFromSlice 的 "updateFrom" 变体方法。这些方法用于更新内存中的值,将 ZON 源中指定的字段覆盖到现有值的字段上。这在使用 ZON 加载具有不同优先级的配置文件时非常有用,例如一个拥有全局配置文件和每个项目配置文件的文本编辑器。
### 重命名 bit_set 变体并弃用托管版本 §
为保持一致性重命名类型,弃用之前的名称和托管版本。
- std.bit_set.IntegerBitSet â¡ï¸ std.bit_set.Integer
- std.bit_set.ArrayBitSet â¡ï¸ std.bit_set.Array
- std.StaticBitset , std.bit_set.StaticBitSet â¡ï¸ std.bit_set.Static
- std.DynamicBitSetUnmanaged , std.bit_set.DynamicBitSetUnmanaged â¡ï¸ std.bit_set.Dynamic
- std.DynamicBitSet , std.bit_set.DynamicBitSet â¡ï¸ std.bit_set.DynamicManaged (弃用)
### std.lang.Type 的结构体数组风格 §
进行类型反射时,结构体和联合体将以结构体数组风格返回信息 (#35234) 。
--- a/lib/compiler/Maker/ScannedConfig.zig +++ b/lib/compiler/Maker/ScannedConfig.zig @@ -49,9 +49,10 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void { } fn printStruct (sc: * const ScannedConfig, s: *Serializer.Struct, comptime S: type , v: S) ! void { - inline for ( @typeInfo (S).@"struct".fields) |field| { - try s.fieldPrefix(field.name); - try printValue(sc, s.container.serializer, field. type , @field (v, field.name)); + const info = @typeInfo (S).@"struct"; + inline for (info.field_names, info.field_types) |field_name, field_type| { + try s.fieldPrefix(field_name); + try printValue(sc, s.container.serializer, field_type, @field (v, field_name)); } }
### 将 lang.OptimizeMode 重命名为 lang.Optimize §
并从枚举标签名称中移除 "release"。
虽然此更改添加了向后兼容的声明,但表达式中使用 == 或 != 操作符时将无法使用弃用名称,因此此更改是破坏性的。
- std.lang : OptimizeMode â¡ï¸ Optimize Debug â¡ï¸- debug ReleaseSafe â¡ï¸- safe ReleaseFast â¡ï¸- fast ReleaseSmall â¡ï¸- small
### lang.Optimize.runtimeSafety §
推荐使用 std.lang.Optimize.runtimeSafety 代替 std.debug.runtime_safety,因为它能为调用站点提供关于其自身模块的信息,而不是标准库模块的信息。
### @import("builtin") 的弃用项 §
@import("builtin") 中的冗余常量 cpu、os、abi 和 object_format 已被弃用,将在 0.18.0 版本中移除。请使用 target 常量上的对应字段替换所有用法:
- @import("builtin").cpu â¡ï¸ @import("builtin").target.cpu
- @import("builtin").os â¡ï¸ @import("builtin").target.os
- @import("builtin").abi â¡ï¸ @import("builtin").target.abi
- @import("builtin").object_format â¡ï¸ @import("builtin").target.ofmt
### 正确处理 mem.eql 和 mem.findDiff 中的浮点数 §
当 std.mem.eql 和 std.mem.findDiff 的两个输入是同一内存区域的切片时,这些函数会进行短路优化。这种短路优化只有在给定类型的 == 运算符具有自反性时才是正确的。对于浮点数来说并非如此,例如 std.math.nan(f64) != std.math.nan(f64)。此 PR 的更改会在处理浮点数切片时禁用该优化。
先前失败、现在通过的测试用例:
const
x: [
3
]
f64
= .{
42.0
, std.math.nan(
f64
),
3.1415
};
try
std.testing.expect(!std.mem.eql(
f64
, &x, &x));
try
std.testing.expectEqual(
1
, std.mem.findDiff(
f64
, &x, &x));解耦 Uri 和 net.HostName §
Uri 有时在 resolveInPlace 中使用 HostName.validate 验证主机名,有时在 parseAfterScheme 中不使用。这本身存在问题,但更严重的是 RFC3986(Uri)对有效主机名的定义与 RFC1123(HostName)存在显著差异。因此,让 Uri 一致使用 HostName.validate 反而会降低 Uri 的实用性。
取而代之的是,Uri 中所有与 HostName 相关的代码已被移除。Uri.getHost 已迁移至 HostName.fromUri(由于语义差异较大,未提供优雅的弃用过渡),而 Uri.getHostAlloc 已被完全移除。
var
host_buf: [HostName.max_len]
u8
=
undefined
;
const
host =
try
uri.getHost(&host_buf);var
host_buf: [HostName.max_len]
u8
=
undefined
;
// 注意:由于 fromUri 会执行验证,错误集已发生变化
const
host =
try
HostName.fromUri(uri, &host_buf);#36036
构建系统 §
- b.build_root (Directory) â¡ï¸ b.root (Path)
- ConfigHeader.Options : include_guard_override â¡ï¸ include_guard
- LazyPath : getDisplayName â¡ï¸ format ( "{f}" )
- LazyPath.basename : 已移除,因为该值直到构建阶段才能确定
- b.findProgram 拆分为 findProgram 和 findProgramLazy,并对 API 进行了未来兼容性改进
- ConfigHeader 已修复,现在所有样式都会报告未使用的值
- addArtifactArg , addPrefixedArtifactArg â¡ï¸ addArtifactArg2
- addOutputFileArg , addPrefixedOutputFileArg â¡ï¸ addOutputFileArg2
- addFileContentArg , addPrefixedFileContentArg â¡ï¸ addFileContentArg2
- addOutputDirectoryArg , addPrefixedOutputDirectoryArg â¡ï¸ addOutputDirectoryArg2
- addDirectoryArg , addPrefixedDirectoryArg , addDecoratedDirectoryArg â¡ï¸ addDirectoryArg2
- addDepFileOutputArg , addPrefixedDepFileOutputArg â¡ï¸ addDepFileOutputArg2
- addFileArg , addPrefixedFileArg â¡ï¸ addFileArg2
将构建过程与配置过程分离 §
zig build 现在在独立的可执行文件中运行项目的 build.zig 代码,该可执行文件与执行包管理和构建图的进程不同。这使 zig build 在以下原因中变得更加快速(#35428):
- 当修改 build.zig 脚本时,构建器可执行文件保持不变,因此在安装 Zig 后只需构建一次("首次设置")。
- 构建器可执行文件以优化模式构建,这在我们引入了 --watch 和 --fuzz 参数后变得越来越有价值。
- 根据与 zig build 一起使用的 CLI 参数,有时可以跳过 build.zig 的逻辑。
此外,配置信息现在以紧凑的二进制格式序列化,该格式可以被第三方工具使用,并作为新构建服务器协议的一部分。此前通过 fork 构建运行器来满足此需求的方式已不再支持。
要将配置渲染为 .zon 格式并输出到 stdout,请使用 --print-configuration 参数。
缓存系统重构 §
新功能:
- 目录支持。目录中添加、删除或重命名条目可能导致缓存未命中。
- 元数据模式。通常,只有内容变更会导致缓存未命中。在元数据模式下,当大小、inode 或 mtime 发生变化时,无论内容是否变更,都会导致缓存未命中。
四种组合均可能实现(is_directory=true/false,metadata_mode=true/false)。这些功能作为新 API 暴露在构建系统中。
由于 Zig 工具链高度依赖缓存系统,此版本还切换为二进制格式,文件大小减少约 25%,这在减轻文件系统缓存压力的同时,也简化了计算机的工作——直接从磁盘复制字节,而无需解析文本文件。新推出的 zig cache-cat 子命令可用于排查 zig-cache 目录内文件的问题或进行调试。
缓存系统现在还具备解释“未命中”原因的能力。std.Build.Cache 的公共 API 存在许多破坏性变更,但除编译器工具外,该 API 使用频率较低,所有变更都使误用变得更加困难。
观察到此变更使缓存命中速度提高了 5-10%(#36822)。
引入配置缓存中毒概念 §
如果缓存被“中毒”意味着配置逻辑产生了副作用,或执行了缓存系统无法追踪的操作。
这与单个步骤在评估时是否可能产生副作用无关,而是与 build.zig 内部的逻辑有关。例如,一个在构建时打印“hello world”的 Run 步骤会产生副作用,因此不值得设置此标志;而配置时检查 scdoc 是否存在以确定配置选项默认值的操作则属于缓存中毒。
保持缓存纯净会使 zig build 更快,在生成相同配置时跳过配置器流程。
当缓存被中毒时,构建器进程在摄入配置文件后会将其删除,因为无法重复使用。
导致缓存中毒的方式包括调用 findProgram,或更直接地使用 std.Build.Graph.poisonCache。比缓存中毒更好的替代方案是使用这些新函数显式声明配置依赖项:
- std.Build.dependOnFileContents - 表示 build.zig 逻辑依赖特定文件的内容。
- std.Build.dependOnFileMetadata - 表示 build.zig 逻辑依赖特定文件的大小、inode、mtime 和内容。
- std.Build.dependOnDirectoryContents - 表示 build.zig 逻辑依赖特定目录的条目。
- std.Build.dependOnDirectoryMetadata - 表示 build.zig 逻辑依赖特定目录的最后修改时间。
高级用户可以通过新 CLI 选项覆盖缓存中毒行为:
--cache-poison[=mode] 覆盖配置缓存行为
pure (默认)避免误判缓存命中
poisoned 不缓存配置
disallowed 当缓存被中毒时触发 panic
ignored 适度中毒对任何人都无害findProgram §
立即(在配置阶段),会在主机上搜索具有多个可能名称的可执行文件。
名称的搜索顺序遵循以下规则:首先观察搜索前缀,然后是 PATH 环境变量。
调用此函数会污染配置缓存,因此只有在需要通过配置逻辑观察程序存在性或其输出时才适用。这也是为什么现在有了 findProgramLazy。
findProgramLazy §
创建一个匿名 Step,用于在主机上搜索具有多个可能名称的可执行文件。
与 findProgram 不同,此函数不会污染配置缓存,但结果无法在配置阶段使用,因此返回类型为 LazyPath。
返回找到的可执行文件的 LazyPath。只有当 LazyPath 被依赖的 Step 使用时,搜索才会实际执行。
此 API 在以下情况下非常有用:
- 二进制文件在不同系统上的名称不一致(例如 "python" 与 "python3")。
- 二进制文件可能通过从源代码构建生成,而非全局安装,因此可能在搜索前缀路径之一中找到。
Run Step: Passthru Args §
在 Run 步骤中,passthru 参数现在统一处理,不再在配置阶段可观察运行参数是否提供。
--- build.zig
+++ build.zig
@
-
if
(b.args) |args| {
- run_cmd.addArgs(args);
-}
+run_cmd.addPassthruArgs();这移除了构建脚本的一项能力,因为它们无法再观察到这些参数。作为交换,这意味着当修改这些参数时,构建脚本不再需要重新编译。
Fmt Step: Options §
paths 和 exclude_paths 现在是 LazyPath 列表。提供了一个便捷方法用于创建它们:b.pathList。
--- build.zig
+++ build.zig
@
-
const
fmt_include_paths = &.{
"lib"
,
"src"
,
"test"
,
"tools"
,
"build.zig"
,
"build.zig.zon"
};
-
const
fmt_exclude_paths = &.{
"test/cases"
,
"test/behavior/zon"
};
+
const
fmt_include_paths = b.pathList(&.{
"lib"
,
"src"
,
"test"
,
"tools"
,
"build.zig"
,
"build.zig.zon"
});
+
const
fmt_exclude_paths = b.pathList(&.{
"test/cases"
,
"test/behavior/zon"
});Step.Options : add addOptionPathDirectory §
现在,当添加一个文件路径类型的选项时,必须显式选择以下三种方式之一(#36876):
- addOptionPath(必须是一个文件)
- addOptionPathDirectory(必须是一个目录)
- addOptionPathUntracked(放弃依赖跟踪)
Lazy Dependency Ergonomic Enhancements §
- 当获取懒加载依赖项时记录日志。
- std.Build.dependency:支持懒加载依赖项。
- 引入 std.Build.dependencyLazy,可能返回 error.LazyDependencyNeeded 而非 null,以便使用 try。
- 当用户构建函数返回 error.LazyDependencyNeeded 时,构建系统会继续获取依赖项,而不是失败。
Removed Ability to Override Build Runner §
不再有“构建运行器”的概念;它已被拆分为:configurer 和 maker。
此用例现在由构建服务器协议处理。
Package Management §
所有包管理功能已从编译器中移除,并移至构建系统。这包括以下子命令:
- zig build
- zig fetch
- zig init
- zig libc
- zig cache-cat
这意味着编译器可执行文件中曾包含的大量功能现在以源代码形式提供,包括:
- 包获取逻辑
- HTTP 客户端和网络功能
- TLS(传输层安全协议)及相关加密技术
- Git 协议
- xz、gzip、zstd、flate、zip 压缩格式
- 解析、验证及处理 build.zig.zon 文件
所有这些功能现在均以 -Osafe 优化模式进行编译,而非以前的 -Ofast 模式,因为这些功能属于编译器本身。在对构建系统本身进行调试时,可以使用环境变量 ZIG_DEBUG_CMD=1 将构建系统编译为调试模式。
其他修改:
- 修复错误:拒绝允许路径依赖超出父包根目录的请求。
#### 覆盖包路径的功能 §
--pkg-path 命令行参数和 ZIG_LOCAL_PKG_DIR 环境变量现在在 fetch 和 build 命令中都会被识别。
#### 全局与本地获取 §
现在 zig fetch 仅将内容获取到全局缓存中,与之前的行为一致。但是,如果使用了 --save(或任何变体),它也会将内容获取到本地包路径中。在全局获取时,不需要 build.zig 文件存在。zig build 始终在本地获取(同时也会在全局获取)。
值得注意的是,这修复了之前退化的用例 zig fetch 。
通过路径获取时,哈希值始终会被计算,重新压缩的 tarball 始终会被创建,并且始终会覆盖全局缓存中的现有条目。
DLL 参数的 PATH 略有差异 §
以前,当目标为 Windows 或 Wine 时,Run 步骤中添加的工件参数会根据包含递归 DLL 依赖项的目录集修改 PATH。现在,这一操作仅针对 argv[0] 执行。对于其他命令行参数也执行此操作的动机尚不明确,因为这些 DLL 不需要加载即可执行 argv[0]。
构建服务器协议 §
现在,当传递 --listen=- 参数时,构建系统会提供一种协议,允许连接的客户端监控和控制构建图的执行过程。该协议旨在被第三方工具(如 IDE)使用。
目前可以执行的操作包括:
- 获取整个构建图的静态信息(配置后),包括可用的构建步骤、设置的选项、依赖关系等。还有一些内容尚未包含,例如暴露的模块名称集合。
- 在构建步骤开始和完成时收到通知,包括错误信息和生成的文件信息。
- 请求构建特定的步骤。
特别是,maker 进程和 configurer 进程的分离是一项破坏性变更,导致 ZLS 项目无法与 0.17.0 版本兼容。尽管在此发布周期中已取得一些进展以恢复功能,但 Zig 团队和 ZLS 团队仍在合作进一步增强构建服务器协议,使 ZLS 不仅能恢复功能,还能超越之前的强大功能和能力。
未来,Zig 自身的许多第一方构建系统工具将作为构建服务器协议的客户端,通过实际使用该协议来确保第三方工具享有同等能力(#36497)。
还计划让构建服务器复用编译器服务器协议进行编译步骤,提供类型系统信息、重构和其他高级编辑功能(#615)。
编译器 §
增量编译 §
Zig 0.17.0 版本对增量编译功能进行了重大改进。该功能允许在修改代码后几乎即时地重新构建项目。许多 bug 已被修复,上一版本引入的新 ELF 链接器也已对该功能提供了良好支持。
得益于这些改进,现在大多数针对 x86_64-linux 的项目都可以使用增量编译功能。要使用该功能,请在 zig build 命令中添加参数 -fincremental --watch(例如:zig build -fincremental --watch)——这将使 Zig 构建系统监听源文件的更改,并通过执行增量重建进行响应。
如需了解如何在自己的项目中使用增量编译功能,或想深入了解该功能的内部实现机制,可以阅读 Zig 核心团队成员撰写的这篇博客文章。
未来版本将继续专注于改进该功能,包括引入新的 Mach-O 链接器和自带 aarch64 后端(对增量编译有良好支持);添加无需 --watch 参数即可使用增量编译的支持;以及修复所有剩余的 bug。
SPIR-V 后端 §
现在,自托管的 SPIR-V 后端已与其他后端一样支持多线程。
诸如 LocalSize 和 OriginUpperLeft 等执行模式现在是从函数的调用约定中推导出来的,而不是通过内联汇编设置。新的 spirv_task 和 spirv_mesh 调用约定为任务着色器和网格着色器提供了支持(#35676)。
通过 OpCapability 和 OpExtension 在内联汇编中声明能力与扩展已不再允许。它们现在通过目标 CPU 特性启用,即 -mcpu 参数。
在此发布周期中,SPIR-V 后端修复了 22 个 bug。
aarch64 后端 §
该功能的进展受到链接器增强功能的阻碍,其中许多功能已在本次发布周期中完成。
loongarch 后端 §
已提交了 loongarch64 自托管后端的初步实现(#36418)。该实现仍处于实验阶段,目前尚不可用。为该后端做贡献有两种方式:直接参与开发,以及为 AIR 法规化特性做贡献,这有助于所有未完成的后端更快地完成开发。
WebAssembly 后端 §
与 LLVM 后端相比,Zig 的 WebAssembly 后端现在通过了 2060/2054(100%)行为测试。但由于缺乏调试信息支持(#37032),在调试优化模式下编译时它还不是默认选项。
链接器 §
ELF §
本次发布在用上一版本引入的新实现替换 Zig 旧版自托管 ELF 链接器方面取得了重大进展。具体改进包括:
- 完整的 x86_64 支持
- 完整的 SPARC64 支持
- 部分 Loongarch 支持
- 静态库生成
- 共享库生成
- 可执行文件中未定义符号的错误提示
- GOT 生成
- 复制重定位
- GNU 符号版本控制
- DWARF 调试信息
- 符号哈希表生成
- 基本可复现的二进制文件
- 任意节对齐
- 支持小型主机文件系统块大小
虽然此链接器尚未完全达到与我们旧版自托管ELF链接器的功能 parity(仍默认禁用),但实践中它已经能够构建绝大多数针对x86_64-linux的Zig项目。这使得这些项目可以使用增量编译功能——就像在Zig 0.16.0中,这种新链接器在此情况下默认启用。
在Zig的下一个版本中,我们希望完全淘汰旧版ELF链接器,改用此实现。
COFF §
链接器的COFF支持新增了以下功能(#35674):
- 输出对象文件(.obj)和归档文件(.lib)
- 与镜像文件一同输出implibs
- 输出镜像文件的TLS和导出数据目录
- 支持将对象文件、归档文件和导入库作为输入
- 仅链接归档文件中需要的对象(即包含满足引用所需的符号时)
- COMDAT规则(已支持链接compiler_rt和libc,部分COMDAT类型尚未支持)
- 支持链接-gnu和-msvc libc
- TLS支持
- __dllimport支持:通过IAT直接进行间接调用/加载
- 根据导出符号自动检测应选择的入口点
- -gnu:构造函数/析构函数支持(即合并.ctor和.dtor,设置__CTOR_LIST__、__DTOR_LIST__符号)
- 支持多个.drectve参数(这些参数用于正确链接msvc libc):/INCLUDE:强制引用符号 /ALTERNATENAME:添加符号别名 /MERGE:节合并。此功能还用于将特定节定向到正确位置(如将.ctor/.dtor定向到.rdata) /DEFAULTLIB:添加新输入
新链接器测试框架 §
Zig正在转向基于快照的链接器测试。
测试结合了比较objdump快照输出、实际运行生成的二进制文件以及检查链接器错误三种方式。
zig build -Dlink-snapshot-update 会使测试以输出快照而非检查快照的模式运行。
添加新测试的典型工作流程:
- 添加测试
- zig-debug build test-link -Dtest-filter=my-test -Dlink-snapshot-update 会为所有verifyObjdump调用中定义的快照组合输出.dmp文件。快照文件夹中故意让多个目标共享同一个快照名称以减少噪声,因此某个快照名称的首次测试会决定更新快照。如果不同目标确实存在差异,将在第4步揭示。
- 检查快照输出的正确性
- zig-debug build test-link -Dtest-filter=my-test 现在会将所有目标与新添加的快照进行比对
- 如果出现快照失败,意味着不同目标产生了不同的快照输出。需要检查输出以确认这些差异是否确实有效。如果是有效差异,应使用scope参数使-Dlink-snapshot-update将快照输出到不同文件名,按差异进行区分
- 重新运行-Dlink-snapshot-update更新新的快照集合
SPIR-V §
SPIR-V链接器已重写(#36828)。现在支持增量编译,可链接外部.spv对象文件。
Fuzzer §
尽管此版本的构建系统变更与Zig集成的模糊测试器及其与构建系统的交互有松散关联,但模糊测试器本身未进行任何修改。
我们预计在未来的版本周期中将重点改进模糊测试工具。
错误修复 §
本版本周期中关闭的329个错误报告完整列表:
- 在GitHub上跟踪
- 在Codeberg上跟踪
许多错误在本次版本周期中既被引入又被修复。出于简洁性的考虑,大部分错误修复未包含在本次发布说明中。
本版本包含错误 §
Zig已知存在错误、编译错误和回归问题。
即使使用Zig 0.17.x,开发非简单项目可能仍需要参与开发流程。
当Zig达到1.0.0版本时,一级支持将增加错误处理政策作为额外要求。
#### 显著回归问题 §
我们已知0.17.0版本存在以下显著回归问题:
- #37006:在x86架构上,compiler-rt无法为soft float编译
- #36986:std.debug.simple_panic无法编译
- #36986:弱符号Zig libc无法可靠覆盖
- #36444:maker进程与configurer进程分离导致std.Build.Step.Run的响应文件用例失效
- #37050:SPIR-V后端回归问题
工具链 §
LLVM 22 §
本次Zig版本升级至LLVM 22.1.8。此升级涵盖Clang(zig cc)、libc++、libc++abi、libunwind和libtsan等组件。
#### 禁用循环向量化以解决回归问题 §
在上一个Zig版本中,我们被迫禁用LLVM关键优化流程——循环向量化——以解决影响Zig编译器的编译错误。
自引入该变通方案以来,LLVM主分支已合并修复方案。但该修复方案尚未包含在Zig 0.17.0使用的LLVM 22版本中。因此,目前该变通方案仍保持启用状态。
Zig 0.18.0将升级至LLVM 23,届时可重新启用该优化流程。
musl 1.2.5 §
Zig 0.17.0分发musl 1.2.5版本及回溯的安全部署和兼容性修复。同时上游已发布1.2.6版本。Zig 0.18.0将升级至musl 1.2.6。
当静态目标musl时,许多函数现在由zig libc提供而非复制自musl源文件。因此,如遇Zig提供的musl libc相关错误,请通过Zig的Issue Tracker提交而非直接提交至musl项目。
glibc 2.44 §
交叉编译时现在可使用glibc 2.44版本。
Linux 7.2 头文件 §
本版本包含Linux内核7.2版本头文件。
macOS 27.0 头文件 §
本版本包含macOS系统27.0版本头文件。
MinGW-w64 §
Zig 0.17.0分发MinGW-w64提交版本31bd54ab7d5fe03c67ed2bb1a57e531b9c7f8cc4。
然而,许多函数现在由zig libc提供而非复制自MinGW-w64源文件。因此,如遇Zig提供的MinGW-w64 libc相关错误,请通过Zig的Issue Tracker提交而非直接提交至MinGW-w64项目。
NetBSD 11.0 libc §
交叉编译时现在可使用NetBSD libc 11.0版本。
OpenBSD 7.9 libc §
交叉编译时现在可使用OpenBSD libc 7.9版本。
WASI libc §
Zig 0.17.0继续分发WASI libc提交版本c89896107d7b57aef69dcadede47409ee4f702ee。
然而,许多函数现在由zig libc提供而非复制自WASI libc源文件。
此外,从Zig 0.18.0开始,Zig将不再分发第三方WASI libc代码,而是通过zig libc为WASI目标提供libc支持。更多信息请参见:
- 定义独立的Zig libc ABI
- 移除wasi-libc支持
zig libc §
在 libc.txt 文件中,gcc_dir 字段已更名为 cc_dir,以反映其并非专属于 GCC 的事实。旧名称目前仍会被接受,但建议用户将 libc.txt 迁移到新名称(#36951)。
此外,在 Linux 目标平台上,cc_dir 现在是必填项。需要注意的是,由于 Android 和 OpenHarmony 将相关目标文件存储在非典型位置,这些目标平台的用户可能需要将 cc_dir 设置为与 crt_dir 相同的路径。
zig cc §
zig cc 和 zig c++ 现在基于 Clang 22.1.8。
zig objdump §
这是快照测试的必要条件,同时也对开发 COFF 链接器有所帮助。
支持的功能:
用法: zig objdump [选项] 文件
选项:
-h, --help 打印帮助信息并退出
--all-headers 等效于 --file-headers --linker-member=2 --member-headers --section-headers --relocs --symbols
--exports[=sort] 显示导出符号。
对于 COFF 导入库,显示符号列表和导入头。
指定 =sort 可按符号名称对导入头进行排序。
--file-headers 显示文件格式特定的头信息
--imports 显示导入符号
--linker-member[=1|2|longnames] (Coff) 显示指定归档链接成员的内容(默认值为 2)
--member-headers 显示归档成员头信息
--elements=[e1],[e2],-[e3],... 选择要显示的格式元素。专为快照测试设计。
file-type 文件类型摘要
header-name 标题块前的名称
member-path 显示完整成员路径。若移除,则仅使用基名。
newlines 输出部分之间使用换行符
table-header 带列名的表格标题
all (默认)以上所有
--only-member=[name] 仅考虑包含 [name] 的归档成员名称。可多次指定。
--only-section=[name] 仅考虑包含 [name] 的节名称。可多次指定。
--only-symbol=[name] 仅考虑包含 [name] 的符号名称。可多次指定。
--redact=[kind] 擦除指定字段类型。专为快照测试设计。
rva 相对虚拟地址
va 虚拟地址和文件偏移
ord 符号序号 / 提示
size 大小和长度
all 以上所有
--relocs 显示重定位信息
-s, --snapshot 等效于 --redact=all --elements=-all
--section-headers 显示节头信息
--strings 显示字符串表
--symbols 显示符号表
--tls 显示 TLS 信息部分示例输出:
⯠zig objdump mathtest-dync-exe-no-llvm.dll --all-headers
mathtest-dync-exe-no-llvm.dll: PE/COFF 图像
/think
COFF头:
8664 机器类型(AMD64)
7 节区数量
6a08670a 时间戳
0 符号表指针
0 符号数量
f0 可选头大小
2022 标志
| 可执行镜像
| 大地址感知
| DLL
COFF可选头:
20b 魔数(PE32+)
14.00 链接器版本
14a400 代码大小
84e00 已初始化数据大小
0 未初始化数据大小
1000 入口点地址( 180001000)
1000 代码基地址( 180001000)
180000000 映像基地址
1000 节区对齐方式
200 文件对齐方式
6.00 操作系统版本
1.00 映像版本
6.00 子系统版本
0 Win32版本值
1d6000 映像大小
400 头大小
0 校验和
2 子系统(WINDOWS_GUI)
160 DLL标志
| 高熵VA
| 动态基址
| NX兼容
100000 栈保留大小
1000 栈提交大小
100000 堆保留大小
1000 堆提交大小
0 加载器标志
10 RVA和大小数量
数据目录:
1b48d0 54 导出
1b4924 8c 导入
0 0 资源
1cc000 633c 异常
0 0 安全
1d4000 1280 基址重定位
1bc000 1c 调试
0 0 架构
0 0 全局指针
1aebc8 28 TLS
0 0 加载配置
0 0 绑定导入
1b4c80 2d0 IAT
0 0 延迟导入
0 0 COM描述符
0 0 保留
'mathtest-dync-exe-no-llvm.dll'中的节区:
编号 名称 RVA 虚拟大小 数据大小 & 数据 & 重定位 & 行号 # 重定位 # 行号 标志
1 .text 1000 14a346 14a400 400 0 0 0 0 60000020 | CNT_CODE MEM_EXECUTE MEM_READ
2 .rdata 14c000 6fe3c 70000 14a800 0 0 0 0 40000040 | CNT_INITIALIZED_DATA MEM_READ
3 .buildid 1bc000 52 200 1ba800 0 0 0 0 40000040 | CNT_INITIALIZED_DATA MEM_READ
4 .data 1bd000 e2a0 d200 1baa00 0 0 0 0 c0000040 | CNT_INITIALIZED_DATA MEM_READ MEM_WRITE
5 .pdata 1cc000 633c 6400 1c7c00 0 0 0 0 40000040 | CNT_INITIALIZED_DATA MEM_READ
6 .tls 1d3000 20 200 1ce000 0 0 0 0 c0000040 | CNT_INITIALIZED_DATA MEM_READ MEM_WRITE
7 .reloc 1d4000 1280 1400 1ce200 0 0 0 0 42000040 | CNT_INITIALIZED_DATA MEM_DISCARDABLE MEM_READ
未找到符号表如果此输出用于快照测试以验证特定导出是否存在:
⯠zig objdump mathtest-dync-exe-no-llvm.dll --exports --only-symbol=add --redact=rva --elements=-all
导出目录:
0 标志
0 时间戳
0.00 版本
xxx xxxxxxxxxx name_rva
1 序号基数
1 条目数量
1 名称数量
xxx xxxxxxxxxx export_address_table_rva
xxx xxxxxxxxxx name_pointer_table_rva
xxx xxxxxxxxxx ordinal_table_rva
1 0 xx xxxxxx | add红action(--redact=)和元素移除(--elements=)功能用于移除对特定测试不重要的输出部分,以避免因符号的RVA因链接器的其他无关更改而改变时导致误报的失败。-s是简写形式,启用所有红action并移除所有额外输出元素,但特定测试可能不会使用此选项,如果它们关心具体数值的话。
resinator §
#### Windows资源编译迁移到外部包 §
Windows资源脚本编译将在下一个版本中从编译器迁移到官方但外部的构建系统包。因此,对应的std.Build函数和字段(Build.Module.addWin32ResourceFile等)在本版本中已被标记为已弃用。
此次更改后,zig rc子命令仍将保留,以继续支持使用Zig工具链与其他构建系统配合使用的场景。
zig fmt §
#### 新增--complexity标志 §
这是一个简单的工具,用于统计标记和AST节点数量,可以用来分享源文件编辑如何通过比行数更深入的启发式方法增加或减少复杂度。
例如,在旧版ELF链接器目录上运行:
info: src/link/Elf/gc.zig: tokens=1538 nodes=770
info: src/link/Elf/Atom.zig: tokens=15576 nodes=7768
info: src/link/Elf/Merge.zig: tokens=2288 nodes=1092
info: src/link/Elf/Thunk.zig: tokens=1128 nodes=519
info: src/link/Elf/SharedObject.zig: tokens=4566 nodes=2236
info: src/link/Elf/eh_frame.zig: tokens=4840 nodes=2335
info: src/link/Elf/Symbol.zig: tokens=3770 nodes=1872
info: src/link/Elf/synthetic_sections.zig: tokens=13287 nodes=6375
info: src/link/Elf/Object.zig: tokens=13903 nodes=6842
info: src/link/Elf/LinkerDefined.zig: tokens=4140 nodes=2091
info: src/link/Elf/relocatable.zig: tokens=3598 nodes=1848
info: src/link/Elf/Archive.zig: tokens=2176 nodes=1028
info: src/link/Elf/ZigObject.zig: tokens=20783 nodes=10274
info: src/link/Elf/AtomList.zig: tokens=1819 nodes=933
info: src/link/Elf/relocation.zig: tokens=1289 nodes=551
info: src/link/Elf/file.zig: tokens=2330 nodes=1087
info: total: tokens=97031 nodes=47621另一个例子是编辑Lld.zig使用arena.print而不是std.fmt.allocPrint后。行数大致相同但--complexity显示不同故事:
- 修改前:tokens=11929 nodes=5900
- 修改后:tokens=11832 nodes=5852(源代码复杂度降低1%)
未来这个指标可能对自动导入整理器判断是否创建导入别名有所帮助。
路线图 §
- 与ZLS团队合作增强构建服务器协议,直到满足所有使用场景。
- 完成x86_64后端的Windows支持,使其可以默认启用。
- 完成并稳定语言特性。
- 完成aarch64后端并将其设为调试模式的默认后端。
- 改进链接器实现,消除对LLD的依赖并支持增量编译。
- 提升集成的模糊测试工具性能,使其与AFL及其他最先进的模糊测试工具具有竞争力。
- 将对LLVM的库依赖转换为对Clang的进程依赖 ( #16270 )。
- 完成构建系统,特别是包管理功能的实现。
- 审计标准库 ( #1629 )。
## 感谢贡献者! §
以下是在本次发布中至少提交过一次贡献的人员名单:
- Alex Rønne Petersen
- Andrew Kelley
- Matthew Lugg
- Casey Banner
- Jacob Young
- Frank Denis
- Ali Chraghi
- Isaac Freund
- Pavel Verigo
- Ryan Liptak
- Techatrix
- Justus Klausecker
- Linus Groh
- xtex
- rpkak
- David Rubin
- Elaine Gibson
- David Senoner
- K4
- fardragon
- pentuppup
- Krzysztof Wolicki
- Mason Remaley
- Meghan Denny
- Christophe Delage
- Robbie Lyman
- Lukáš Lalinský
- Brandon Black
- Kendall Condon
- hemisputnik
- whatisaphone
- Ben Anderman
- GasInfinity
- Huang Zhichao
- Jakub Konka
- Jari Vetoniemi
- Kleshzz
- Mick Sayson
- Mikołaj Rosowski
- Ryan Mehri
- Sertonix
- jeffkdev
- lg
- Carl Östholm
- EJ
- Hila Friedman
- Quint Daenen
- Saurabh Mishra
- Stephen Gregoratto
- Subo2002
- Ten Eugene
- zacoons
- Arthur Teixeira
- Ben Burkert
- Bernard Assan
- CursedByTheVoid
- Daniel Kareh
- Ennui Langeweile
- Igor Anić
- Janne Hellsten
- Jay Petacat
- Nguyễn Gia Phong
- Ragul R
- Rue04
- Sam Connelly
- Scott Redig
- Theo Fabi
- Vitor Fernandes
- c-kappel
- gero3
- glowsquid
- taoqy
- teflate
- xeondev
- AI Xin
- ARandomOSDever
- Acid Bong
- Adrià Arrufat
- Akshay Trivedi
- Alan Cocanour
- Alex Kladov
- Amilia MacIntyre
- Anders Stenberg
- Andrew Kraevskiii
- Anshul Gupta
- Anthon van der Neut
- Ari Becker
- Ashley (holtowd)
- C19
- Carter Snook
- Chadwain Holness
- Chloé Vulquin
- Chris Boesch
- Christoffer Lerno
- Corentin Kerisit
- David
- Devin J. Pohly
- Diego Peña y Lillo
- Dmitry Mostovenko
- Eric Joldasov
- Erik Schlyter
- FalsePattern
- Fitti
- Gabriel Sa
- Gereon V
- Giuseppe Cesarano
- Gota7
- GrimTyr
- Guillaume Wenzek
- Guy Fischman
- Henry Kupty
- Ignacio Ibarra
- Jan Procházka
- Jan200101
- Jeff Fowler
- Jeremy Linton
- John Benediktsson
- Jonathan Marler
- Joseph Lyncheski
- Josh Megnauth
- Kirk Scheibelhut
- Leon Lombar
- Leonid Emar-Kar
- Mai-Lapyst
- Manlio Perillo
- Marcel W. Wysocki
- Mark Rushakoff
- Mathieu Suen
- Matthew Knight
- Matthias Portzel
- Michael Farber Brodsky
- Miloš Kozák
- Nguyễn Gia Huy
- Nico Elbers
- Noam Rothschild
- Nurul Huda (Apon)
- Paul Anderson
- Paulo Duarte
- Perry Fraser
- Pivok
- Preeternal
- Prokop Randáček
- RadsammyT
- Rayan Halder
- Richalsu
- Richard Levitte
- Ryan Davis
- Ryan King
- Sage Hane
- Samuel Hunter
- Sawyer X
- Siddharth Sinha
- Steve
- Tapir
- Thibault Leclercq
- Yasin Gorgij
- Zhalkhas
- abdessalem
- agave
- ahwayakchih
- akbarhusain
- arshidkv12
- avalyn0x45
- badayvedat
- binarycraft007
- brianferri
- brkzlr
- carmooo
- cheesecakecatttt
- conmaster2112
- drex_vk
- gDator
- gemmaro
- gubbu
- ilovapples
- jmcaine
- johan0A
- jpk68
- krystiann
- kubashi
- l1yefeng
- levinqua
- llogick
- marximimus
- mihael
- mlugg
- nash1111
- ndjenks
- nekogirl
- nyx-xyn
- pancelor
- skdishansachin
- sphaerophoria
- squidy239
- sstochi
- vlkrs
- zirunis
- Ömer Faruk IRMAK
- Έλλην Εμίλια Άννα Zscheile
- 雷欧·程 (Leo Cheng)
## 感谢赞助商! §
特别感谢那些赞助 Zig 的人。由于有多种持续的捐赠,Zig 由开源社区驱动,而不是以盈利为目标。特别是以下这些人在本次发布周期内通过我们首选的捐赠平台平均每月资助 50 美元或更多:
- Sergey M
- Mitchell Kember
- David Vanderson
- Thomas Manner
- Kazuhiro Kondo
- Merlyn Morgan-Graham
- Freddi Linse
- Numan Sachwani
- Aurélien Cibrario
- Erik Dunteman
- Ondra Voves
- Mitchell Gayner
- Dylan Conway
- Trevor John
- Jason Watson
- Greg Clark
- Benjamin Crist
- Alexander Weavers
- Natalie Vais
- Stevie Hryciw
- Kyle Hill
- Felix Queißner
- Srinivasan Balram
- Peter Ronnquist
- Lajos Nagy
- Gauthier Voron
- Andrew Mangogna
- Jacob Sandlund
- Jordan Lucier
- Wolfgang Sanyer
- Nick Macholl
- Ceri Elenbaas
- Michael Keathley
- Daniele Cocca
- Bartosz Bogacz
- James Cox-Morton
- William Canan
- Fabio Arnold
- Johannes Meyer
- Silver van Koten
- Flavius Gruian
- Daniel MacDougall
- Karrick McDermott
- Dan Mack
- Caleb Hearon
- Ingimar Jóhannesson
- David Fendley
- Aaron Cross
- Jeremiah Oard
- Simon Ekström
- Jorge De León
- Rob Green
- Kytezign q
- Mykhailo Tsiuptsiun
- Paul Sargent
- Erik Mållberg
- Igor Anic
- Fawzi Mohamed
- David Jones
- Magnus Holm
- Nicholas Woolmer
- Samarth Kishor
- Charles Haws
- Shlomi Atar
- Andrius Bentkus
- Jean-Luc Geering
- Aaron Mady
- coleman broaddus
- Trace Andreason
- Jim Calabro
- Chris Baldwin
- Ian Johnson
- Michael Lynch
- O Y
- Francesco Gualazzi
- David Sugar
- Malcolm Still
- Yaroslav Zhavoronkov
- Miles McGruder
- Álvaro Justen
- FELIPE SOARES GONCALVES SA ROSA
- Noah Betzen
- Manuel Barkhau
- Rikard Karlsen
- Frank Ittermann
- Eli Janssen
- Peter Snelgrove
- Will Pragnell
- Pete Dietl
- Vaughn Spielman
- Michael Kato
- Daniel Dubecky Hodan
- Dan Boykis
- Richard Feldman
- Markus Ort
- Peyman Mortazavi
- Wilson Bilkovich
- Kev Burns
- Francisco Nevitt Gonçalves
- Mark Banhidi
- Kristoffer Ström
- Carl Distefano
- Alexander Reustle
- Martin Hovda Haugsand
- Lexa Tang
- Lennart Tuijnder
- Enver Bisevac
- Jameson York
- Hong Shick Pak
- Travis Staloch
- Clover Caruso
- Matthew Chavez
- Daniel Gregoire
- Jose M Rico
- Xavier Cochran
- Nas Denkov
- Pavel Rychlý
- papa leromi
- Ronald Zielaznicki
- Tommi Komulainen
- Matthew Jee
- Johan Forsberg
- Łukasz Mróz
- Fabio Leimgruber
- Maurice van Veen
- Dean Simmons
- Pierre Marc Levasseur
- Sebastian Appler
- Sam Windell
- Aksel Hjerpbakk
- Jonathan Helland
- Karl Fleischmann
- Erik Hansen
- Pablo Álvarez
- Jacob Hooper
- Avinash Lakshman
- Joshua Park
- Nicholas Clark
- Ryan Higgins
- Jeffrey Ollie
- Adam Goertz
- David Nowotny
- Gus Louw
- David Francoeur
- David Sparby
- Tyler Bender
- Mark Halonen
- Reinis Taukulis
- Nancy Remaley
- Isaac F
- Kjell Hoffhenke
- Vlad Panazan
- Jordan Rowland
- Jay Van Der Wall
- Jean-Philippe Quenord
- Jakob Külzer
- Varun Pramanik
- Benjamin Edwards
- Andreas Herrmann
- Adam Nilsson
- Joseph Ruiz
- Anthony Nguyen
- Marcin Wolcendorf
- Tobias Lahrmann Hansen
- Pat Smuk
- Martin Weber
- Jordan Kardon
- Benjamin LE BERRE
- John Goen
- Sebastian Ahlman
- Anthony Hernandez
- Shail Patel
- Alexander Genaud
- Morten Dalfoss
- Jason Dubaniewicz
- Mark Hayes
- Eivind Rovik
- Renan Silva
- Isak Källman
- Ladislav Böhm
- LeRoyce Pearson
- Rowan Saunders
- Joshua Masci
- Raymond Imber
- Daniel Worley
- Owen Cabalceta
- Erez Shomron
- Max Grosse
- Ehden Sinai
- Christopher Redden
- Antoine Balaine
- Chris Durkin
- Dave Wallace
- Aura Birb
- Andy Armstrong
- Spencer Brower
- Simon Clavet
- Guido Schmidt
- Peter McGaughey
- Callum McArthur
- David Lei
- David Brotz
- Matti Hänninen
- Joseph Chan
- Vincent Weber
- Jeremy McAdams
- Morgan Gallant
- Brett Pechiney
- Thilina Jayanath Nenathunga Liyanage
- Kevin Bockelandt
- Gunnar Zötl
特别感谢 TigerBeetle、Synadia Communications 和 ZML 的重大贡献。