Skip to content

Commit 2f880f0

Browse files
committed
feat(docs): support 0.16.0
1 parent 6f92eea commit 2f880f0

4 files changed

Lines changed: 1125 additions & 1 deletion

File tree

course/.vitepress/sidebar.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,14 @@ export default [
220220
text: "版本说明",
221221
collapsed: true,
222222
items: [
223+
{
224+
text: "0.16.0 升级指南",
225+
link: "/update/upgrade-0.16.0",
226+
},
227+
{
228+
text: "0.16.0 版本说明",
229+
link: "/update/0.16.0-description",
230+
},
223231
{
224232
text: "0.15.1 升级指南",
225233
link: "/update/upgrade-0.15.1",

course/.vitepress/theme/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
const version: string = "0.15.1";
1+
const version: string = "0.16.0";
22

33
export { version };
Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
---
2+
outline: deep
3+
comments: false
4+
showVersion: false
5+
---
6+
7+
# `0.16.0`
8+
9+
2026/4/13,`0.16.0` 发布,历时 8 个月,有 244 位贡献者参与,一共进行了 1183 次提交!
10+
11+
如果要用一句话概括这个版本,那就是:**`0.16.0` 把上一轮预告过的大量基础设施重构真正落地了。**
12+
13+
`0.15.x` 还在为 `std.Io`、增量编译和新的工具链架构铺路,到了 `0.16.0`,这些方向已经进入可以大规模体验的阶段:I/O 统一为接口、`main` 可以直接拿到 `io``gpa`、增量编译进一步可用、新 ELF linker 开始接入默认流程,同时语言层也继续清理历史设计。
14+
15+
## 目标支持
16+
17+
`0.16.0` 在目标支持上的一个重要变化,是 Zig 对“哪些平台值得持续投入工程质量”这件事变得更明确了。
18+
19+
比较值得注意的点有:
20+
21+
- `aarch64-freebsd``aarch64-netbsd``loongarch64-linux``powerpc64le-linux``s390x-linux``x86_64-freebsd``x86_64-netbsd``x86_64-openbsd` 这些目标现在都会在 Zig 的 CI 中原生测试
22+
- 新增 `aarch64-maccatalyst``x86_64-maccatalyst` 的交叉编译支持
23+
- 新增 `loongarch32-linux` 的初始支持,不过当前仍不支持 libc
24+
- Alpha、KVX、MicroBlaze、OpenRISC、PA-RISC、SuperH 等架构加入了基础支持
25+
- Oracle Solaris、IBM AIX、z/OS 支持被移除;`illumos` 不受影响,仍然保留支持
26+
- 栈回溯支持进一步扩大,几乎所有主流目标在崩溃时都能得到更可靠的 stack trace
27+
28+
对普通用户来说,这意味着 Zig 在常见 Linux / BSD / macOS / Windows 目标上的“可用性底线”又往前推了一步;而对于比较边缘的平台,官方也更清晰地区分了“支持”“实验性支持”和“不再支持”。
29+
30+
## 系统最低版本要求
31+
32+
| 操作系统(Operating System) | 最低版本要求(Minimum Version) |
33+
| :--------------------------- | :-----------------------------: |
34+
| DragonFly BSD | 6.0 |
35+
| FreeBSD | 14.0 |
36+
| Linux | 5.10 |
37+
| NetBSD | 10.1 |
38+
| OpenBSD | 7.8 |
39+
| macOS | 13.0 |
40+
| Windows | 10 |
41+
42+
## 语言变动
43+
44+
### `switch` 继续补齐语义
45+
46+
`switch` 是这一轮里继续被打磨的语言特性之一。现在,`packed struct``packed union` 可以直接作为 prong item,比较规则按照 backing integer 来做;同时,decl literals、需要结果类型的表达式、union tag capture 等场景也获得了更一致的支持。
47+
48+
这类变更本身并不一定会让旧代码报错,但它明显减少了过去一些“语言明明应该支持、但实现上还没补齐”的边角问题。
49+
50+
### `@cImport` 正式进入“迁移期”
51+
52+
`0.16.0` 仍然保留了 `@cImport`,但已经明确将其标记为 deprecated。官方方向是把 C 头文件翻译迁到构建系统中,通过 `build.zig` 里的 `addTranslateC` 生成模块,再在 Zig 代码里使用 `@import("c")`
53+
54+
这和 Zig 未来“逐步把对 LLVM / Clang 的库级依赖转向进程级依赖”的方向是一致的。
55+
56+
同时,`translate-c` 的实现现在已经从 `libclang` 切换到了 Aro / translate-c 方案。对大多数用户来说这是透明的,但如果你升级后发现 C 头文件翻译行为有差异,它更可能是实现 bug,而不是新的预期行为。
57+
58+
### `@Type` 被拆分为多个独立内建函数
59+
60+
这是 `0.16.0` 最明显的语言级 breaking change 之一。`@Type` 被移除,原来依赖它造类型的元编程代码,需要迁移到新的内建函数:
61+
62+
- `@EnumLiteral()`
63+
- `@Int()`
64+
- `@Tuple()`
65+
- `@Pointer()`
66+
- `@Fn()`
67+
- `@Struct()`
68+
- `@Union()`
69+
- `@Enum()`
70+
71+
这项改动的核心目标,是让“构造类型”这件事更直观,也让常见场景不必再绕一层 `std.meta.Int``std.meta.Tuple` 之类的辅助函数。
72+
73+
### packed / extern 相关规则更严格
74+
75+
这次发布继续收紧了位级布局和 ABI 边界的隐式行为:
76+
77+
- `packed union` 现在要求更明确的 backing integer 语义
78+
- `packed struct` / `packed union` 不再允许直接放指针字段
79+
- `extern` 场景下,`enum``packed` 类型不能再依赖隐式推断的底层整数类型
80+
81+
从设计上看,这些限制的方向非常统一:**凡是会影响 ABI 或精确内存布局的内容,Zig 都更倾向于要求你显式写出来。**
82+
83+
### 向量语义进一步收紧
84+
85+
`0.16.0` 禁止了运行时向量索引,同时也不再鼓励通过旧式内存强转在数组和向量之间来回转换。简单来说,向量更明确地被当成“值语义上的 SIMD 数据”,而不是“碰巧可以按数组方式随便访问的内存”。
86+
87+
另外,小整数类型在“绝对不会丢精度”的前提下,现在可以安全地隐式转换为浮点类型,这也让数值代码更顺手了一些。
88+
89+
### 类型解析与依赖环错误大幅重做
90+
91+
`0.16.0` 还重做了编译器内部的类型解析流程。这个改动的影响非常深:
92+
93+
- 许多以前会误报 dependency loop 的代码现在可以正常工作
94+
- 增量编译和普通编译之间的一致性明显增强
95+
- 一小部分本来就存在真实依赖环的代码,现在会更早、更明确地报错
96+
97+
如果你升级后遇到以前没见过的 dependency loop,先别急着回退版本。因为 `0.16.0` 的错误报告已经能更清楚地指出环路是怎么形成的,通常只要打断其中一条依赖即可。
98+
99+
## 标准库
100+
101+
### I/O 作为 Interface
102+
103+
这是 `0.16.0` 最重头的内容,没有之一。
104+
105+
从这个版本开始,所有输入输出相关能力都围绕 `std.Io` 展开。更准确地说,凡是可能阻塞控制流,或会引入非确定性的操作,都被纳入了 `Io` 的抽象边界内。
106+
107+
当前官方提供了几种典型实现:
108+
109+
- `Io.Threaded`:基于线程,功能最完整,也是从 `0.15.x` 升级时最接近旧行为的实现
110+
- `Io.Evented`:仍在实验阶段,用来推动接口演进
111+
- `Io.failing`:用于模拟“不支持任何操作”的环境
112+
113+
围绕它,标准库引入了整套新的任务和并发抽象:
114+
115+
- `Future`
116+
- `Group`
117+
- `Batch`
118+
- `Select`
119+
- `Queue(T)`
120+
- 统一的 cancelation 模型
121+
122+
这不仅是 API 改名,而是 Zig 对“并发 I/O 应该怎样进入语言生态”给出的新答案。文件系统、网络、进程、同步原语、定时器等能力,都围绕这套接口重新组织了。
123+
124+
### `Juicy Main`
125+
126+
为了配合新的 `std.Io``main` 也获得了一个很实用的新入口:`std.process.Init`
127+
128+
只要把 `main` 写成:
129+
130+
```zig
131+
const std = @import("std");
132+
133+
pub fn main(init: std.process.Init) !void {
134+
const gpa = init.gpa;
135+
const io = init.io;
136+
_ = gpa;
137+
_ = io;
138+
}
139+
```
140+
141+
你就能直接拿到:
142+
143+
- `gpa`
144+
- `io`
145+
- `arena`
146+
- `environ_map`
147+
- `preopens`
148+
- `minimal.args` / `minimal.environ`
149+
150+
这让应用入口第一次真正成了“进程上下文的注入点”。对于应用开发来说,这个改动的体感甚至不亚于 `std.Io` 本身。
151+
152+
### 环境变量和进程参数不再是全局状态
153+
154+
`Juicy Main` 配套的另一项重要变化,是环境变量和进程参数都不再被鼓励当成全局状态来访问。
155+
156+
现在,环境变量原则上只存在于应用入口的 `Init` 里;需要使用它们的函数,应当显式接收需要的值,或者接收 `*const std.process.Environ.Map`
157+
158+
这个方向很符合 Zig 一贯的设计哲学:尽量少依赖隐式的全局上下文,让副作用和依赖关系都显式体现在函数签名里。
159+
160+
### 线程与分配器模型继续更新
161+
162+
围绕新的 `std.Io`,标准库的并发相关设施也继续收敛:
163+
164+
- `std.Thread.Pool` 被移除,官方建议迁移到 `std.Io.async` / `std.Io.Group.async`
165+
- `std.heap.ArenaAllocator` 变成了 thread-safe 且 lock-free
166+
- `std.heap.ThreadSafeAllocator` 被移除
167+
168+
如果把这些变化放在一起看,会发现 Zig 正在逐步放弃一些“靠包装器补线程安全”的旧路子,转而更偏向于:让真正需要并发的基础组件自己具备合适的并发语义。
169+
170+
### 文件系统、路径与容器 API 持续整理
171+
172+
除了 `std.Io` 大迁移之外,这次标准库还有很多看起来零碎、但真实影响升级体验的整理工作:
173+
174+
- `std.io` 继续收敛到 `std.Io`
175+
- `std.fs` 的一批常用入口迁到 `std.Io.Dir` / `std.Io.File`
176+
- `std.process.getCwd*` 改名为 `currentPath*`
177+
- `fs.path.relative` 变成纯函数,需要显式传入上下文
178+
- `File.Stat.atime` 变成可选值
179+
- `std.mem` 里 “index of” 系列统一更名为 “find”
180+
- 一批容器继续向 unmanaged 方向迁移,`PriorityQueue` / `PriorityDequeue` 的命名也更统一了
181+
182+
这些调整单看都不算大新闻,但合在一起,就是一次很典型的 Zig 式“去历史包袱”整理。
183+
184+
### Windows 标准库实现继续下沉
185+
186+
Windows 也是 `0.16.0` 里非常有意思的一条线:
187+
188+
- 网络 API 不再依赖 `ws2_32.dll`,而是直接基于 AFD 实现
189+
- 标准库继续向 NtDll 收敛
190+
- `std.Progress` 现在也支持 Windows 下的跨进程进度上报
191+
192+
这些工作虽然对多数用户不可见,但会真实影响程序的健壮性、性能,以及 cancelation / batch 模型在 Windows 上的完整度。
193+
194+
## 构建系统
195+
196+
### 依赖目录改到项目本地 `zig-pkg`
197+
198+
`0.16.0` 开始,依赖包会被拉取到项目根目录旁边的 `zig-pkg` 目录,而不是继续使用过去那种全局解压缓存模式。
199+
200+
这个变化的好处很直接:
201+
202+
- 你可以更方便地阅读、搜索、修改依赖源码
203+
- 可以更自然地把依赖目录换成本地 git clone
204+
- IDE 也更容易直接索引整棵依赖树
205+
206+
### `zig build --fork`
207+
208+
构建系统新增了 `--fork=[path]` 参数,可以让你临时用本地目录里的 fork 覆盖依赖树中的匹配包。
209+
210+
这对生态 breakage 的排查非常有帮助:你可以在不改版本元数据的前提下,直接调试一整串依赖之间的兼容问题。
211+
212+
### 依赖元数据更严格
213+
214+
`0.16.0` 还提高了 `build.zig.zon` 的要求:
215+
216+
- 缺少 `fingerprint` 会直接失败
217+
- `name` 不能再用字符串,必须写成 enum literal
218+
- 旧 hash 格式支持已被移除
219+
220+
这意味着旧项目在升级时,最好顺手检查一遍所有依赖元数据,而不是等到 `zig build` 报错再逐个补。
221+
222+
### 新增测试超时与错误输出样式
223+
224+
`zig build` 新增了几项很适合日常开发的参数:
225+
226+
- `--test-timeout`
227+
- `--error-style`
228+
- `--multiline-errors`
229+
230+
同时,旧的 `--prominent-compile-errors` 被移除了,对应的新写法是 `--error-style minimal`
231+
232+
### 临时文件 API 被重构
233+
234+
`Build.makeTempPath``RemoveDir` step 都被清理掉了,新的推荐路径是:
235+
236+
- `Build.addTempFiles`
237+
- `Build.addMutateFiles`
238+
- `Build.tmpPath`
239+
240+
这项重构背后的核心思路,是把“临时目录”“可变文件”“缓存语义”这些东西从一开始就表达清楚,而不是让旧 API 在 configure 阶段偷偷做一堆文件系统副作用。
241+
242+
## Compiler
243+
244+
### `translate-c` 改用 Aro
245+
246+
编译器内部的 `translate-c` 现在基于 Aro / translate-c,而不是 `libclang`。这使 Zig 离“摆脱对 LLVM 的库级依赖”又近了一步。
247+
248+
对普通用户来说,这更多体现为长期方向上的信号:Zig 仍在持续拆除自己对 LLVM 的深绑定。
249+
250+
### 类型解析重构
251+
252+
前面在“语言变动”里提过,`0.16.0` 大幅重做了类型解析。这件事对编译器本身还有两个非常重要的连锁收益:
253+
254+
- 依赖环报错更可解释
255+
- 增量编译和普通编译之间的一致性更强
256+
257+
这也是为什么你会发现,本版本许多看似分散的改动,最后都会回到“为了更可靠的增量编译”这个主题上。
258+
259+
### 增量编译继续前进
260+
261+
`0.16.0` 的增量编译已经比 `0.15.x` 实用得多:
262+
263+
- 大多数场景下减少了“过度重编译”
264+
- LLVM 后端也开始支持增量编译
265+
- ELF 目标在 `-fincremental` 下会默认启用新的 ELF linker
266+
- 稳定性明显提升,虽然依然不是默认开启
267+
268+
官方现在明确鼓励大家实际使用:
269+
270+
```sh
271+
zig build -fincremental --watch
272+
```
273+
274+
当然,它仍然有已知 bug,甚至可能包含误编译;所以这项功能在 `0.16.0` 里依然不是默认值。
275+
276+
### 后端进展
277+
278+
这一轮里:
279+
280+
- x86 自托管后端修了 11 个 bug,仍然是 Debug 模式下的默认后端
281+
- aarch64 后端因为 `std.Io` 带来的标准库 churn 暂时放慢了节奏
282+
- Zig 的 WebAssembly 后端目前通过了 1813 / 1970(约 92%)项行为测试
283+
284+
## 链接器(Linker)
285+
286+
### 新 ELF Linker
287+
288+
`0.16.0` 的新 ELF linker 可以通过 `-fnew-linker` 显式启用,或者在 build 脚本里设置 `exe.use_new_linker = true`。更重要的是:**`-fincremental` 且目标是 ELF 时,它现在会默认启用。**
289+
290+
官方给出的一个数据点非常直观:对 Zig 编译器本体做单行改动时,旧 linker 需要大约 `194ms`,而新 linker 只需要 `65ms`,几乎接近“完全跳过链接”的速度。
291+
292+
这也意味着过去那种专门暴露 `-Dno-bin`、只求快速拿到编译错误的工作流,收益已经没有以前那么明显了。
293+
294+
不过要注意,新 linker 目前还没完全补齐旧 linker / LLD 的能力,例如生成物还缺少 DWARF 信息。所以它已经够快、够值得试,但还没有到“所有场景都能无脑切换”的程度。
295+
296+
## Fuzzer(模糊测试器)
297+
298+
### `Smith` 取代 `[]const u8`
299+
300+
Fuzz 测试接口是 `0.16.0` 里另一个会直接影响用户代码的 breaking change。过去 fuzz test 习惯接收 `[]const u8` 输入;现在统一改成 `*std.testing.Smith`,由它来生成结构化值。
301+
302+
这套接口不仅更适合做复杂输入生成,还支持权重、范围、哈希相关性等能力,明显比过去的“原始字节切片”模式更强。
303+
304+
### 多进程、多核与 crash dump
305+
306+
除了接口变化之外,fuzzer 本身也更强了:
307+
308+
- 现在可以利用多核,受 `-j` 控制
309+
- 多个 fuzz test 会自动轮换并优先运行更“有产出”的测试
310+
- 崩溃输入会自动落盘,便于复现
311+
312+
## Bug 修复
313+
314+
本轮发布周期内,Zig 一共关闭了 345 个 bug 报告。
315+
316+
不过官方也直说了:**这个版本仍然包含已知 bug、误编译和回归问题。** 对于稍微复杂一点的项目,使用 `0.16.x` 仍然意味着要准备好参与 issue 反馈、最小复现和版本试验。
317+
318+
这并不意外。因为 `0.16.0` 本质上是一个“大迁移版本”,它把很多还在演进中的长期工程方向一次性推到了用户面前。
319+
320+
## 工具链(Toolchain)
321+
322+
### LLVM 21
323+
324+
`0.16.0` 升级到了 LLVM `21.1.0`,覆盖了 Clang、libc++、libc++abi、libunwind、libtsan 等组件。
325+
326+
不过这里有一个非常值得注意的 caveat:为了规避 LLVM 上游的严重回归,Zig 在 `0.16.x`**完全禁用了 loop vectorization**。这会让某些代码生成结果比理想情况更保守,但它仍然比“在常见配置下误编译 Zig 编译器自身”要好得多。
327+
328+
官方预计这个性能回退不止会影响 `0.16.x`,甚至还会延续到 `0.17.x`,大概率要等到 `0.18.x` 才会彻底解决。
329+
330+
### libc 与系统头文件更新
331+
332+
这一轮工具链同时带来了:
333+
334+
- `musl 1.2.5`(附带安全修复回移)
335+
- `glibc 2.43`
336+
- Linux `6.19` headers
337+
- macOS `26.4` headers
338+
- FreeBSD `15.0` libc
339+
- 交叉编译时支持动态链接的 OpenBSD libc
340+
341+
### `zig libc` 继续扩张
342+
343+
`zig libc` 继续吞并原来来自 musl、MinGW-w64、WASI libc 的一部分 C 实现。`0.16.0` 中,随 Zig 分发的 C 源文件总数从 `2270` 降到了 `1873`,减少了约 `17%`
344+
345+
这里尤其值得一提的是:很多数学函数,以及 `malloc` 相关函数,现在都已经进入 `zig libc` 的实现范围。
346+
347+
### `zig cc`
348+
349+
`zig cc` / `zig c++` 现在基于 Clang `21.1.8`。这意味着 Zig 在“C / C++ 工具链外壳”这条线上,也继续和整体 LLVM 版本一同推进。
350+
351+
## 路线图(Roadmap)
352+
353+
官方对 `0.17.0` 的规划很明确:这是一个相对短周期版本,主要目标是升级到 LLVM `22`,并完成“把构建执行阶段和 `build.zig` 配置阶段分离”的工作。
354+
355+
在这之后,更长期的大方向仍然是:
356+
357+
- 继续完成并稳定语言本身
358+
- 做完 aarch64 后端,并让它成为 Debug 模式默认后端
359+
- 继续增强链接器,减少对 LLD 的依赖,并服务增量编译
360+
- 继续增强内置 fuzzer
361+
- 继续把对 LLVM 的依赖,从“链接库”转向“调用 Clang 进程”
362+
363+
如果说 `0.15.x` 还是“这些方向马上就要影响到你了”,那 `0.16.0` 就是“它们已经开始真正影响你的日常开发了”。

0 commit comments

Comments
 (0)