社区内的最新进展,信息来源:Zig NEWS、Zig monthly、Lobsters、Reddit、Zig weekly newsletter、Ziggit、用户推荐
月刊
- 202411
- 202410 | 向 Zig 软件基金会认捐 30 万美元
- 202407 | Zig 成为最热门的编程语言
- 202406 | 0.13 来了
- 202405
- 202404 | Zig 0.12.0 正式释出
- 202403 | ziglang.cc 正式上线
- 202402 | Zig 2024 Roadmap 新鲜出炉
- 202311 | 传值或传引用,这是个大问题
- 202310
- 202309 | Bun 正式发布 1.0
- 202308 | 0.11 正式发布
- 202307 | 异步缺席 0.11
- 202306 | Zig 要分叉了?
- 202305 | HTTP is built-in
- 202304 | 首次闯入 Tiobe 前 50
- 202303 | 并发编译
- 202302 | 精益求精的包管理
- 202301 | 包管理来了
- 202211 | 0.10 横空出世
- 202210 | 0.10 蓄势待发
- 202209 | 锋芒毕露
- 202208 | stage2 默认开启
- 202207 | 开刊 HelloWorld
202411
观点/教程
Why am I writing a JavaScript toolchain in Zig?
JAM 作者写的一篇文章,分析里市面上现有的 JS 工具链(bundler、formatter、linter 等),虽然已经很好用,但是不够快。下面是他举的几个例子:
- Lossless, cache efficient syntax trees,现在通用的 JS 语法树表示是 ESTree,尽管设计上很简洁,但在遍历时不够高效,需要有遍历多次 才能得到有用信息(eslint 里就有四次!),而且都是指针的树结构非常不利用重复利用 CPU,Carbon 编译器就有一种更紧凑的 AST 表示。
Compile time AST query processing。Lint 的规则大部分都是模式匹配,大部分时候都有多个嵌套的 if 逻辑,为了简化插件开发者,eslint 采用了一种 esquery 的语法,示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
if ( node.type == "CallExpression" && node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "child_process" ) { // many of these checks are to satisfy typescript^ } if (matches( 'CallExpression[callee.object.name = child_process]', node )) { // much better }
esquery 的问题在于执行效率,通过借助于 zig 的 comptime 来在编译器翻译 esquery 就避免了运行时开销。
Advent of Code in Zig | Loris Cro's Blog
一年一度的 AoC 又到了,这篇文章里给出了一些使用的技巧来帮助大家用 Zig 来解决 AoC 问题。
- 工具链,最新的版本 0.13 和 zls
- 手册,和 How to read the standard library source code · ziglang/zig Wiki
使用
embedFile
来嵌入输入的测试用例:1 2 3 4 5 6 7 8
const std = @import("std"); const input = @embedFile("path/to/input.txt"); pub fn main() !void { for (input) |byte| { //... } }
分词
- std.mem.tokenizeScalar
- std.mem.splitScalar
- std.mem.splitAny
- std.mem.window 滑动窗口,用法可参考:New way to split and iterate over strings - Zig NEWS
数据操作
- 解析数字,
std.fmt.parseInt()
- 位操作,可以用任意宽度的数字(u1,u2 等),
std.BitStack
,std.DynamicBitSet
这两个也非常有用
- 解析数字,
更重要的,作者最后提到 AoC 可能不是学习 Zig 的最好方式:
虽然 AoC 非常有趣,但它并不是练习软件工程的方法。 每个 AoC 练习都要求你找到一个问题的解决方案,虽然你需要编写一个程序来解决这个问题, 但你的程序将是一个只需运行一次(一次正确)的一次性脚本。
当你的软件需要稳健、优化和可维护时,Zig 就会大显身手,而这些对于 AoC 来说都不重要。
因此,请注意,虽然肯定能用 Zig 解决 AoC 问题,而且 Zig 的某些功能甚至能帮助您取得比其他语言更快的进展,但它最终还是针对软件工程进行了优化,而这并不是您在 AoC 中要做的事情。
Zig Reproduced Without Binaries
一个很有趣的实验,在 0.10 版本中,Zig 编译器实现了自举,即可以用老版本的 Zig 来编译 Zig 源码,生成最新的 Zig 二进制。这里重新复习一下这个复杂的流程:
之所以复杂,问题在于老版本的 Zig 从哪里来呢?对于 Zig 来说就是 zig1.wasm,它是用没自举前的 Zig,利用 LLVM 后端,以 wasm32-wasi 为目标生成的二进制文件。 为了保证足够小,这里面只保留了 C 后端,这样就得到了一个小到可以放到代码仓库中的 Zig 编译器。这篇文章就是证明这个文件没有被私自篡改过!
- 之后利用 Zig 团队自己写的 wasm2c.c 把 zig1.wasm 编译成 zig1.c,之后用 cc 编译 zig1.c 就可以得到 stage1 的 zig 编译器
- 之后再用 zig1 编译 zig 源码,由于 zig1 之后 C 后端,因此这里得到的产物是 zig2.c,再利用 cc 就可以可以 stage2 的 zig。 zig2 功能上已经完备,但是速度很慢(没有经过 LLVM 优化)
- 最后再用 zig2 继续编译 zig 源码,得到最后的 zig3,这也是我们下载 zig 安装包时包含的版本
- 如果再继续用 zig3 来编译 zig 源码,得到的 zig4 会和 zig3 一模一样。
细节可以参考:
项目/工具
- Builds (Zig) - GoReleaser
- 版本发布工具 GoReleaser 支持了 Zig
- FOLLGAD/zig-ai: OpenAI SDK with streaming support
- A bunch of links to blog posts, articles, videos, etc for learning Zig
- Super-ZIG/cli: Easy command line interface in ZIG.
- deckarep/zigualizer
- Zigualizer: A music visualizer built with Zig, powered by the FFT algorithm.
- freref/fancy-cat
- PDF reader for terminal emulators using the Kitty image protocol
- Dr-Nekoma/lyceum
- An MMO game written in Erlang (+ PostgreSQL) + Zig (+ Raylib)
202410 | 向 Zig 软件基金会认捐 30 万美元
重大事件
向 Zig 软件基金会认捐 30 万美元
Mitchell 在其最新的博客上宣布:我和我的妻子向 Zig 软件基金会 (ZSF) 捐赠了 300,000 美元。
两年内每年分期支付15万美元。第一期已经转账。
我从 2019 年的某个时候开始关注 Zig 项目。 我在 2021 年公开分享了我对该项目的兴奋之情。 同年晚些时候,我开始使用 Zig,到 2022 年初,我开始撰写关于 Zig 的文章,并为编译器做出贡献。 2023 年,我公开分享了用 Zig 编写的终端项目 Ghostty。
如今,我大部分的编码时间都花在了 Zig 上。 我的家人喜欢支持我们相信的事业2。 作为其中的一部分,我们希望支持那些我们认为可以带来变革和影响的独立软件项目,这既是回馈给我如此之多的社区的一种方式,更重要的是,这也是彰显和鼓励为热爱而构建的文化的一种方式。 Zig 就是这样一个项目。
观点/教程
Zig is everything I want C to be
对 Zig 的特色进行了简单扼要的介绍,主要有:
UB 行为检测。
- Zig 的指针不能是 null,需要用 optional 类型
- C 里面的
void*
等价于 Zig 里面的?*anyopaque
。void
在 C 里面有两个意思,第一是『什么都没有』,第二是『类型不确定』,但void
在 Zig 中只有第一个含义,因此用了anyopaque
来表示类型擦除的指针(type-erased pointers)。 - 数组越界检查
- 整数溢出
Bitfield,
packed struct
可以方便的用来进行协议解析,比如对于 32 位的 RISC-V 的指令,可以这么定义解析:1 2 3 4 5 6 7 8 9 10
const IType = packed struct { opcode: u7, rd: u5, funct3: u3, rs1: u5, imm: i12, // For sign-extension }; const encoded_instr: u32 = 0xFFF34293; const instr: IType = @bitCast(encoded_instr);
- comptime,Zig 进行元编程的基础,类型是一等成员
- 与 C 无缝交互,
zig cc
是交叉编译的首选
Critical Social Infrastructure for Zig Communities | Loris Cro's Blog
对于一个试图共同学习如何制作大家都喜欢的软件的社区来说,能够分享想法并开展合作至关重要,但社交平台的不断起伏会导致连接中断,这对于一个从一开始就希望去中心化的社区来说是个大问题。
我有这种想法已经有一段时间了,但随着时间的推移,我们似乎越来越清楚地认识到,我们需要投资于能够长期保持可靠的交流形式,在这种交流形式中,变化是一种信号,表明社区正在发生转变(因此需要一种新的网络形态),而不是表明所选择的社交平台即将被收购/上市/加入人工智能大战。
开发者日志:迈向可靠社会基础设施的第一步
The Zig Website Has Been Re-engineered
Zig 官网已经用 Zine 重写!
项目/工具
- laohanlinux/boltdb-zig
- a zig implement kv database
- zigler
- Zig NIFs in Elixir
- gdonald/blackjack-zig
- Console Blackjack written in Zig
- rabinnh/zig-vscode-linux
- Instructions on setting up VSCode to debug Zig on Linux
- lframosferreira/brainzuck
- Brainf*ck interpreter written in Zig 0.12.0! Have fun!
- BitlyTwiser/snek
- A simple CLI parser to build CLI applications in Zig
- zml/zml
- High performance AI inference stack. Built for production.
- BitlyTwiser/zdotenv
- A port of Godotenv for Zig
- sbancuz/OpenMP-zig
- An implementation of the OpenMP directives for Zig
- tusharsadhwani/zigimports
- Automatically remove unused imports and globals from Zig files.
- Mario-SO/zigitor
- Video editor 🎬 written in Zig ⚡ using raylib
- pwbh/ymlz
- Small and convenient yaml parser for Zig
202407 | Zig 成为最热门的编程语言
重大事件
在这篇文章里,作者引用 Stackoverflow 2024 年的调查报告,指出 Zig 语言是最热门的编程语言之一,并且 Zig 开发者的薪水都很高,平均年收入为75,332美元!
尽管使用 Zig 语言的开发者仅占调查人数的 1%,但上升趋势明显。Zig 语言的倡导者、自由和开放源码软件开发者 Ali Cheragi 说:
Zig 的魅力在于它的简洁性、现代设计以及在底层控制和运行时安全性之间取得的平衡。
Zig 开发者的一些观点:
- 我选择 Zig 作为我的日常用语,是因为它独特的功能和目标组合。我被 Zig 的安全性所吸引,因为它可以让我控制最底层的部件。
- 与许多其他语言不同,Zig 可以与现有的 C 代码实现真正的无缝互操作。出于多种原因,这一点至关重要。
- Zig 正在对大量编程基础架构进行彻底改造,而这些基础架构在过去 40 年里无人敢碰。 C 和 C++ 是著名的核心编程语言,在这两种语言中,你可以完全控制硬件。 但与此同时,这些语言的工具链却非常糟糕。 Zig 允许用户涉猎这些核心编程语言,但可以使用更好的工具链,兼容各种语言和更丰富的功能。
观点/教程
Improving Your Zig Language Server Experience
Loris Cro 的最新文章,介绍了一个改进 Zig 编码体验的小技巧,十分推荐大家使用。具体来说是这样的: 通过配置 zls,达到保存文件时,自动进行源码检查,而且速度非常快!
|
|
将上述内存保存到 zls 的配置文件中,(路径可以通过 zls --show-config-path
查看 ),zls 就会在保存时,自动执行 zig build check
,这个 check
一般来说是这样的:
|
|
由于 Zig 目前的一个 bug(#18877),这个 exe_check
不能作为 install、run 的依赖,否则在编译时,就不会增加 -fno-emit-bin
选项。
而这个选项的作用就是让 Zig 来分析我们的代码,但是不会调用 LLVM 来生成最终的二进制文件,因此速度会比较快。
这个配置有个缺点,就是它是个全局配置,在 zigtools/zls#1687 有讨论如何改成项目级别的,本质上就是定制 zls 的启动参数。
|
|
这样不同的项目就可以用不同的检查步骤了。
Systems Distributed '24
作者对这次会议的一个回顾总结,议题主要有如下几个方向:
- Systems Thinking and Engineering Culture
- The Rise of New Software Abstractions
- Ensuring Safe and Correct Software
- Lessons from Building Distributed Databases
- Notes from Water Cooler Chats
C Macro Reflection in Zig – Zig Has Better C Interop Than C Itself
该作者分享了利用 typeInfo 来在编译时获取字段名的能力,要知道,在 C 里面是没有这个功能的。
|
|
上面这个函数是 Window 编写窗口应用时用到的回调函数,Window 操作系统会把用户触发的事件通过 uMsg
传递过来,为了能够从一个数字,找对对应的名字,在 Zig 里面可以用如下函数实现:
|
|
A TypeScripter's Take on Zig (Advent of Code 2023)
以下该作者的一些心得体会:
- Zig 没有 scanf 等价物,正则表达式也不方便。因此,对于解析输入,它是拆分、拆分、拆分。最后,我分解出了一些 splitIntoBuf 和提取 IntsIntoBuf 帮助程序,这些帮助程序可以很快地读取大多数问题的输入。
- Zig 支持所有大小的 int,一直到 u65536。如果出现溢出,请尝试使用更大的整数类型。我在一些问题上使用了 u128和 i128。
- StringToEnum 是解析受限制的字符串或字符集的一个简单技巧。
- 可以在结构上定义一个 format 方法,使它们按照您的喜好打印。
- 尽量避免将字符串复制到 StringHashMap 中用作键。从 JS 发出这样的命令感觉很自然,但是在 Zig 中会很尴 尬,因为您需要跟踪这些字符串以便稍后释放它们。如果您可以将您的键放入一个结构或元组中,那将会工作得 更好,因为它们具有值语义。如果需要字符串,可以使用切片。
- 注意数值范围的错误。如果你想包含 max,它是
min..(max + 1)
,而不是min..max
。 - 代码中将有大量的@intCast。
- 我发现奇怪的是 Zig 有一个内置的 PriorityQueue,但是没有内置的 Queue,可以用
std.SinglyLinkedList
替代 - 用于处理字符串的许多函数都在 std.mem 中,例如 std.mem.eql 和 std.mem.startsWith
- 使用 std.met.eql 比较 structs,而不是
=
- 有一个按偏移量和长度切片的技巧:
array [start..][0..length]
- 记忆函数通常是很有用的。我不知道 Zig 有没有通用的方法
- 调试构建比优化构建慢得多,有时候慢10倍。如果你在一个合理的时间内得到一个答案的10倍之内,尝试一个不同的发布模式。
- 迭代时不要对数组列表进行修改
- 在 JavaScript 允许您内联表达式的某些情况下,您可能需要分解出一个变量来澄清生存期。看看这个问题。
项目/工具
- 18alantom/fex
- A command-line file explorer prioritizing quick navigation.
- griush/zm
- SIMD Math library fully cross-platform
202406 | 0.13 来了
重大事件
2024-06-07,0.13.0 发布,历时不足 2 个月,有 73 位贡献者,一共进行了 415 次提交! 这是一个相对较短的发布周期,主要原因是工具链升级,例如升级到 LLVM 18。
一个比较大的 Breaking changes 是 ComptimeStringMap
被重命名为了 StaticStringMap
,
使用方式也发生了变化,更多细节可参考:#19682
|
|
0.14.0 发布周期的主题将是编译速度。将在 0.14.0 发布周期中努力实现一些即将到来的里程碑:
- 使 x86 后端成为调试模式的默认后端。
- COFF 的链接器支持。消除对 LLVM LLD 的依赖。
- 启用增量编译以实现快速重建。
- 将并发引入语义分析,进一步提高编译速度。
观点/教程
Leveraging Zig's Allocators
老朋友 openmymind 的又一篇好文章:如何利用 Zig 的 Allocator 来实现请求级别的内存分配。 Zig Allocator 的最佳应用。这里它的中文翻译。
|
|
On Zig vs Rust at work and the choice we made
这篇文章作者描述了所在公司在改造老 C/C++ 项目时,为什么选择了 Zig 而不是 Rust。 重写的项目运行在多个平台上(Web、移动端、VR 设备),因此最靠谱的方案就是暴露一个 C API,然后通过 FFI 来调用。在做决策时,重点关注以下两点:
- 新语言与 C 的交互性
- 工程师扩展代码库的难易程度(如招聘和维护)
下面是 Zig VS Rust 的优势:
Rust | Zig | |
---|---|---|
成熟度 | 更流行、稳定;使用范围更广 | |
包管理 | Cargo 业界领先 | 比 Makefile 好用 |
安全 | 内存安全 | |
SIMD | nightly 支持 | 通过 Vector 类型支持 |
C 交互性 | 生态丰富 | 编译器本身就是 C 编译器,这样就可以逐步重写项目 |
如果只是根据上面的比较,貌似还看不出选择 Zig 的动机,因此作者在最后提到:
Zig 大大减少了移植现有代码库和确保所有平台兼容性所需的时间和精力。我们的团队无法相信 Rust 能让这一切变得如此简单。
相信这也是大部分人选择 Zig 的原因:简洁、高效。
Packing some Zig before going for the countryside
作者列举的一些 Zig 学习资料、常用类库。该作者的另一篇文章也有不少资料:2024 Collection of Zig resources
Why I am not yet ready to switch to Zig from Rust
Turso CTO 的一篇文章,他本身是个资深 C 程序员,而且也比较喜欢 C,但 C 不是一门安全的语言,因此通过 Rust,作者可以避免 写出 SIGSEGVS 的代码,尽管 Rust 是门复杂的语言,但是因为它有完善的生态(有大公司如微软、谷歌等做背书)、已经内存安全等特点, 已经是作者系统编程的首选。
对于 Zig,尽管作者也表达了喜欢,但由于 Zig 的生态不完善,没有足够多的学习资料,因此作者觉得目前阶段选择 Zig 并不会带来 工作上生产力的提高。这一点说的无可厚非,试想一下,如果一个项目所有的依赖都需要自己做,工作效率确实很难提上去。
但是笔者有一点不能理解,就是该作者觉得 comptime 不好用,相比之下,他更喜欢 C 里面的宏。comptime 就是为了 C 宏的不足 而诞生的,社区普遍也觉得 comptime 是个新颖的设计,笔者也是第一次见到这个观点,只能说,萝卜青菜,各有所爱。
其他社区的一些讨论:Lobsters、Hacker News
项目/工具
- malcolmstill/zware
- Zig WebAssembly Runtime Engine
- Cloudef/zig-aio
- io_uring like asynchronous API and coroutine powered IO tasks for zig
202405
观点/教程
Thoughts on Zig
又一篇 Zig 初学者的使用体验文档,如果你也在犹豫要不要学 Zig,这是个不错的经验参考。
I'm sold on Zig's simplicity : r/Zig
一个具有资深经验开发者,在这里描述了自己选择业余项目语言的经历:
- Rust 越来越复杂,有种发展成 C++ 的趋势
- C++ 新版本的特性(比如 module)LSP 支持的不够好,而且历史包袱严重
- C 缺少元编程,并且没有命名空间
最后从 Andrew 的一个播客了解到 Zig,经过自己尝试,发现了 Zig 没有辜负他的期望,尽管是第一次写 Zig,但基本上没有什么难度, 每次遇到问题,仔细想几分钟就差不多有答案了。下面是他罗列的 Zig 的一些优势:
- 十分简洁,import 返回的是一个 struct,和其他变量一样使用
- 与 C 无缝交换,
- 具有 Result 效果的错误处理
- 唯一缺失的就是『接口』,但这一点并不是很关键,就像在 C里也没有,但是 C 可以做任何事
Zig's New CLI Progress Bar Explained
Andrew 的一篇文章,讲述了在最新版的 Zig 中,对进度条的改进实现,现在的进度展示更加友好。
实现的难点在于在多线程环境下,如何保证高性能,文章中大致讲述了其实现:
- 首先通过预先分配好需要使用的结构,保证后续无需在进行 heap 申请
- 通过 atomic 操作来实现一个无锁的 freelist,用于申请、释放 Node
Writing a task scheduler in Zig
Openmymind 作者的又一力作,通过编写一个任务调度器,讲述了多线程编程的基本要领:
- 共享的数据要加锁
条件变量要和锁一起使用,会有虚假唤醒的问题,因此在被唤醒时,需要重新检查状态是否正确。
1 2 3 4 5 6 7 8 9
fn run(self: *Self) void { while (true) { self.mutex.lock(); while (self.queue.peek() == null) { self.cond.wait(&self.mutex); } // TODO } }
它会在 wait 前释放锁,在 wait 返回时先加锁,类似下面的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13
fn wait(c: *std.Thread.Condition, mutex: *std.Thread.Mutex) void { // do some setup // ... mutex.unlock(); // whatever happens, we'll always return with this locked defer mutex.lock(); // wait for signal // or timeout if calling timedWait // ... }
项目/工具
- zigar
- Enable the use of Zig code in JavaScript project。它可以让你直接在 JS 中调用 zig 代码,背后原理是编译成了 wasm 实现的。
- srijan-paul/nez
- An emulator for the NES console.
- deckarep/ziglang-set
- A generic and general purpose Set implementation for the Zig language
- akarpovskii/tuile
- A Text UI library for Zig
202404 | Zig 0.12.0 正式释出
重大事件
千呼万唤的 0.12.0 版本终于 2024-04-20 正式释出了!这次版本历时 8 个月,有 268 位贡献者,一共进行了 3688 次提交!社区内的一些讨论:Hacker News、Lobsters。 这是它的 Release notes。ZigCC 对这个文档进行了翻译、整理,方便大家阅读:
并且还在 2024-04-27 举行了一次线上的 meetup 来庆祝这次发布,这是会议的总结:0.12.0 Release Party 回顾。
0.12.0 这个版本,对用户来说,最重大的变更就是构建系统的稳定了,这对于 Zig 生态的发展是十分关键的一步,试想一个项目用到的依赖之间版本不兼容, 这是十分痛苦的事情,毫无疑问这是阻碍 Zig 生态发生的绊脚石,没有之一。好在这一切都在 0.12 这个版本解决了,用户可以基于 Step 构成的有向无环图来编译自己的项目,不需要再折腾 CMake、Makefile、Vcpkg、Git submodule 等工具,所有的依赖使用 zon 来管理即可。 读者如果对 Zig 构建系统还不熟悉,可以参考:
- 官方文档:Zig Build System
- Zig 升级: 构建系统
期待一年后 Zig 的生态!
观点/教程
- Zig 中任意精度整数用途与实现
由于 CPU 在访问内存时,一般都会有对齐的要求,对于这种非常规的数字,在内存中的地址会是怎样的呢?可以做一个简单的实验:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
const std = @import("std"); const Foo = packed struct { a: u3, b: u2, }; pub fn main() !void { const vs = [_]u3{ 1, 2, 3 }; for (&vs) |*b| { std.debug.print("{p}-{b}\n", .{ b, b.* }); } std.debug.print("U3 size: {d}\n", .{@sizeOf(u3)}); std.debug.print("Foo size: {d}\n", .{@sizeOf(Foo)}); const foos = [_]Foo{ .{ .a = 1, .b = 3 }, }; std.debug.print("foo as bytes: {b}\n", .{std.mem.sliceAsBytes(&foos)}); for (foos) |b| { std.debug.print("{any}-{any}\n", .{ &b.a, &b.b }); } }
输出:
1 2 3 4 5 6 7
u3@104d11a2c-1 u3@104d11a2d-10 u3@104d11a2e-11 U3 size: 1 Foo size: 1 foo as bytes: { 11001 } u3@16b196367-u2@16b196367
通过前三个输出可以知道,每个 u3 实际占用一个字节,但当用在 packed 结构中,就会变成 3 个 bit。其中的 11001 就是字段 a b 混合后的值,且 a 是三位,b 是高两位。
- Learnings From Building a DB in Zig
- 作者分享了在一次 3 天的 Hackthon 中,使用 Zig 开发一个数据库的经历。
- build.zig.zon dependency hashes
- 讲解了 zon 中依赖的 hash 是怎么计算出来的
- play with new comptime var rule of zig 0.12.0
- To SIMD and beyond: Optimizing a simple comparison routine
- 作者在这里循序渐进的介绍了几种数字比较的技巧,从基本的方案,到 Vector,到最后利用 bit 的特点,来逐步优化,并用 godbolt 查看生成的汇编代码,是一篇不错的文章。
- Documentation takes another step backwards : r/Zig
- 一个 Reddit 用户对文档的抱怨
项目/工具
- rofrol/zig-companies
- A list of companies using Zig in production.
- akarpovskii/tuile
- A Text UI library for Zig
- mntnmntn/zenith
- A very minimal text editor in Zig,支持 0.12.0 版本
- chung-leong/zigar
- Enable the use of Zig code in JavaScript project
- jnordwick/zig-string
- Zig string library that includes small string optimization on the stack
- FalsePattern/ZigBrains
- Yet another zig language plugin for intellij
202403 | ziglang.cc 正式上线
重大事件
之前 ZigCC 所有项目都是托管在 GitHub 之上,网页基于 Pages 构建,域名自然也就是 github.io 的,虽然 GitHub 提供了很多利于开发者的服务,但过于依赖 GitHub 这种商业公司,还是不利于 ZigCC 的长远发展,域名是其中很重要一个,有了独立域名,网页托管选择就多了,比如 Cloudflare Pages。
另一个大家比较关心的问题就是 0.12 的发版,虽然 milestone 显示还剩 10 来个 open 的 issue,但是这只是个幌子,核心团队还是有可能随时 delay。不过从剩下的 issue 来分析,主要问题还剩两大类:
- 构建系统完善
- 修复之前功能带来的回顾问题(regression 这个 tag)
新功能看来是已经 ready 了,但这并不是说剩下的这些工具就好解决了,Andrew 在 Zig with Andrew Kelley 这一期播客里提到的 90-90 理论很好的解释了这一点:
(开发软件时)前 90% 的代码要花费 90% 的开发时间,剩余的 10% 的代码要再花费 90% 的开发时间。
当然,后面 ZigCC 也会紧密关注发布动态,有消息第一时间分享给大家。耐不住寂寞的朋友,可以先去刷刷 Zig 的 discord。
观点/教程
- Redesign How Autodoc Works
Andrew 在这个 PR 里重构了现有的文档系统 Autodoc,之前的实现问题很多。比如:
- 很多功能重复的文件,最夸张的是
lib/docs/ziglexer.js
,它是用 JS 实现的 Zig 的解析器,其实 Zig 已经在标准库中暴露解析相关 API,通过 wasm 就可以调用 - 功能更强,因为新设计方案不再处理 ZIR,而是直接处理源文件,这意味着它拥有100% 的信息,不需要向后拼凑任何东西。
- sources.tar 文件经 HTTP 层解压后,直接进入 wasm 模块的内存。使用 std.tar 对 tar 文件进行解析,并对源文件进行就地解析,同时在哈希表中添加一些额外的计算。虽然可以通过 Worker 来加快解析速度,但单线程的解析速度已经非常快,因此这并不是非常有必要。 快来体验最新的文档系统吧:https://ziglang.org/documentation/master/std/
- 很多功能重复的文件,最夸张的是
- Zig, Rust, and other languages
老朋友 Phil Eaton 的文章,在这里他针对以下几点进行了语言对比:
- 内存管理。Zig 最大的问题是不支持 RAII,一个近似的概念是 arenas 分配器。
标准库,主要是讨论标准库是否应该精简为主,
node_modules
是业界经常提到的一个反面例子,一般支持精简的人会认为,- 语言的 std 不容易出现 breaking changes,想 Python 里就有 urllib、urllib2、urllib3 这三个网络库, 但是社区推荐的并不是这三个,而是 requests,这样 std 的位置就有些尴尬
- Zig 目前的标准库算是中等大小,json、compress 压缩等功能都有
- 显示分配,这算是 Zig 的强项,其他语言很少有支持这个的,因此作者在这建议增加一种类似
must-not-allocate
的注解, 这样高级语言里,也可以保值某些操作不会有内存分配。
- Why does an extraneous build step make my Zig app 10x faster?
作者在这篇文章里分享了自己遇到的一个很有意思的问题, 同一份代码,执行方式不同,竟然有不同的耗时。最小复现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
// src/main.zig const std = @import("std"); pub fn countBytes(reader: anytype) !u32 { var count: u32 = 0; while (true) { _ = reader.readByte() catch |err| switch (err) { error.EndOfStream => { return count; }, else => { return err; }, }; count += 1; } } pub fn main() !void { var reader = std.io.getStdIn().reader(); var timer = try std.time.Timer.start(); const start = timer.lap(); const count = try countBytes(&reader); const end = timer.read(); const elapsed_micros = @as(f64, @floatFromInt(end - start)) / std.time.ns_per_us; const output = std.io.getStdOut().writer(); try output.print("bytes: {}\n", .{count}); try output.print("execution time: {d:.3}µs\n", .{elapsed_micros}); }
两种执行方式:
1 2 3 4 5 6 7
$ echo '00010203040506070809' | xxd -r -p | zig build run -Doptimize=ReleaseFast bytes: 10 execution time: 13.549µs $ echo '00010203040506070809' | xxd -r -p | ./zig-out/bin/count-bytes bytes: 10 execution time: 162.195µs
可以看到,通过
zig build run
的方式来执行时,耗时相比直接执行编译好的二进制要快 10 倍。 问题的关键在于 shell 的 pipeline 的执行机制,对于A | B
这样一个简单的 pipeline,一般本能的会认为 B 只会在 A 执行完后才开始执行,但是实际上它们是同时运行的,因此,在上面的例子里main
函数的执行时间在zig build run
方式下, 其实执行的要晚一些,因为它需要先执行编译操作,因此造成了这个误差。- One Bilion rows in zig
- 作者用 1BRC 这个项目作为 Zig 的练手项目,里面用到了 mstange/samply 这个 Profiler 工具,还起来还比较实用。
- Zig defer Patterns
Matklad 最新的一篇文章,Ziggit 讨论链接。里面讲述了 defer 除了做资源回收外,其他的一些惯用法,里面有几个有趣的点:
1
errdefer comptime unreachable
文中称这个是 Zig 的巅峰用法😅,
errdefer unreachable
还比较好理解,即在执行出错时,执行 unreachable ,加上 comptime 呢?其实这是阻止 Zig 编译器生产错误处理的代码,即在编译时期保证下面的逻辑不会出错,确实用的很巧妙!一个简单的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
const std = @import("std"); test "errdeferWithUnreachable" { errdefer comptime unreachable; const i = try inc(1); try std.testing.expectEqual(i, 2); } fn inc(a: i8) !i8 { if (a > 10) { return error.TooLarge; } return a + 1; }
直接执行
zig test
,在编译时会报下面的错误:
|
|
虽然 a
是个运行时的值,但是 errdefer comptime unreachable
不关心这个,只要 Zig 编译器开始生成 ErrorSet 相关代码,
编译就会报错,去掉上面的 if 代码块后,测试就可以正常执行。一个实际的例子:
- std.hash_map: fix pointer lock safety false positive by andrewrk · Pull Request #19364 · ziglang/zig
|
|
可以看到, 这么修改后,就可以保证 map.deinit(allocator)
语句之前没有错误可能产生!读者可以细细品味一下这个用法。
另一个小技巧是 errdefer 竟然支持错误捕获,即下面这种用法:
|
|
- Build system tricks
- 介绍了 zig build 的使用技巧,这些技巧有助于在确保方便地命名和布局构建步骤的同时,如何使用构建系统的每个部分。
- Using Zig with WebAssembly
- 如何将 Zig 编译成 wasm,并传递复杂的参数。
项目/工具
- xataio/pgzx
Create PostgreSQL extensions using Zig. 一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
const std = @import("std"); const pgzx = @import("pgzx"); comptime { pgzx.PG_MODULE_MAGIC(); pgzx.PG_FUNCTION_V1("char_count_zig", char_count_zig); } fn char_count_zig(input_text: []const u8, target_char: []const u8) !u32 { if (target_char.len > 1) { return pgzx.elog.Error(@src(), "Target char is more than one byte", .{}); } pgzx.elog.Info(@src(), "input_text: {s}\n", .{input_text}); pgzx.elog.Info(@src(), "target_char: {s}\n", .{target_char}); pgzx.elog.Info(@src(), "Target char len: {}\n", .{target_char.len}); var count: u32 = 0; for (input_text) |char| { if (char == target_char[0]) { count += 1; } } return count; }
- Manage Zig installations
又又又叒一个 Zig 管理工具,Rust 开发。
1 2 3
zman default latest zman default master zman default 0.12.0
- mahdifrmz/qooil
- 用 Zig 语言编写的文件传输软件
- timfayz/pretty
- Pretty printer for arbitrary data structures in Zig
- liyu1981/zcmd.zig
- Zcmd is a single file lib to replace zig's std.childProcess.run with the ability of running pipeline like bash.
- zigcc/zig-milestone
- Zig milstone monitor
202402 | Zig 2024 Roadmap 新鲜出炉
重大事件
Andrew 最近在 zigshow 节目中介绍了 Zig 2024 年的规划,主要有以下几点:
- 0.12 版本会尽快发布
编译时间现在太慢,进而导致修 bug 的时间长,因此 core team 会优先解决这个编译时间问题。在这个看板中,有相应的进度,主要是:Ditch LLVM、Incremental Compilation 这两个。
- 很多人都对 Ditch LLVM 这个事情嗤之以鼻,认为这是不自量力,这个 issue 的讨论也比较多,已经有近 200 条回复,最近 Andrew 增加了一条回复,引用了 In Defense of Not-Invented-Here Syndrome,该文章的核心观点是如果一个技术是一个产品的核心点,那么就应该自己写,因为这样才有核心竞争力,文中的例子是 Excel 团队会自己维护一个 C 编译器。
异步的支持,目前还有还有不少需要解决的技术难点,比如:
- async 函数挂起时,会保存所有上下文,但是在递归函数里,容易 oom
- 无法推倒出 函数指针 是不是 async fn 的,async fn 与普通 fn 的调用方式是不一样的
- Donor Bounties,捐赠性悬赏,
- 工具链,目前还没精力,只能让社区先来做
更多细致总结可以参考:Zig Roadmap 2024 - Andrew Kelley #91 B 站搬运地址:https://www.bilibili.com/video/BV1UC4y167w9/
观点/教程
- Fast-growing Zig tops Stack Overflow survey for highest-paid programming language
- 估计是 Bun 带动的贫富差距?!
- Pool with generational references in Zig
- 作者在文中介绍了一种有意思的思路:当有很多指针指向同一个对象时,如何不用遍历这些指针就能让其失效,答案是用一个胖指针,包括两部分:真正的数据指针和指向对象的年龄,当指针的年龄和指向对象的年龄不一致时,即认为该指针失效。
- TCC RISC-V Compiler runs in the Web Browser (thanks to Zig Compiler)
TCC 是一个 64 位 RISC-V 的编译器,作者在这篇文章里利用 Zig 把它编译成 WebAssembly 放到浏览器里执行。其中的难点在于 TCC 会调用 Posix 的一些函数,比如:fopen、fprintf、strncpy、malloc 等,但是这些在 WebAssembly 里是没有的,因此需要自己实现,不过幸好 Zig 社区内已经有不少 libc 的实现了:
- marler8997/ziglibc
- ZigEmbeddedGroup/foundation-libc,A libc implementation written in Zig that is designed to be used with freestanding targets.
- Building the DirectX shader compiler better than Microsoft?
- Porting Zig to NetBSD
- Sig Engineering - Part 2 - Progress on AccountsDB & more
Syndica 公司的 Sig,这是一款用 Zig 编写的、专注于 RPS 的 Solana 验证器客户端。在这篇文章里,他们分析了如何优化 HashMap 的性能,而且实现了一个基于本地磁盘的 Allocator。而且他们还在招聘 Zig 工程师:
项目/工具
- semickolon/kirei
- 🌸 The prettiest keyboard software
- Dok8tavo/Interfacil
- Interfacil is a Zig package for making and using interfaces easily in Zig.
- kamlesh-nb/azure-sdk-for-zig
- Azure Sdk for Zig - Experimental
- ringtailsoftware/zig-wasm-audio-framebuffer
- Examples of integrating Zig and Wasm for audio and graphics on the web
- cztomsik/tokamak
- Server-side framework for Zig, relying heavily on dependency injection.
- The-Z-Labs/cli4bofs
- Command line interface for (running) BOFs
- nelipuu/zbind
- Zig-TypeScript binding generator 🟦 🦎
- sneekyfoxx/ziggy
- 又又一个 Zig 版本管理工具
202311 | 传值或传引用,这是个大问题
重大事件
本月讨论比较多的就是 Zig May Pass Anything By Reference 这篇文章了。
它讲述了 Zig 里面一个比较有争议的点,函数的参数到底是传值还是传引用。
|
|
上面这个例子修改了 b
参数的值,但是打印出来的 a
的值也被修改了。
传值的好处就是不用担心原值会被修改,传引用的好处就是可以减少数据拷贝的代价。但是 Zig 目前采用的方式是由编译器推导来决定合适的方式。这样的目的是减少程序员负担,但这实际上会给程序带来不确定性,比如上述例子。
Andrew 在 Lobster 上回复了这个问题,确实是一个比较严重的问题,一种解法是分析一个变量有多少个 alias,编译器只在确定没问题时才进行优化,但是分析一个变量的 alias 有多少不是件容易的事。
其他语言如 C/C++/Rust 等没有进行这种优化尝试,因此没有这个问题,但是 Zig 作为一个新的语言,想尝试来用一种程序员无感的方式来解决,只是目前还没有想到更完善的方案而已。
一些熟悉 Zig zen 的读者可能会觉得这违背了第一条『Communicate intent precisely』,目前来看确实是这样的,而且 core team 老早就意识到这个问题了,感兴趣的读者可以参考:
观点/教程
- Zig's std.json.Parsed(T)
老朋友 openmymind 的文章,这篇文章主要讲述了使用 Zig 中的 json 库序列化后,如何更好的使用返回值,由于有一个 allocator 参数,因此比不能简单的返回
T
,作者这里定义了一个Managed
来解决:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
pub fn Managed(comptime T: type) type { return struct { value: T, arena: *std.heap.ArenaAllocator, const Self = @This(); pub fn fromJson(parsed: std.json.Parsed(T)) Self { return .{ .arena = parsed.arena, .value = parsed.value, }; } pub fn deinit(self: Self) void { const arena = self.arena; const allocator = arena.child_allocator; arena.deinit(); allocator.destroy(arena); } }; }
- Factor is faster than Zig!
- 一个有意思的案例分享。
- A day with Zig
作者把之前一个 Go 的项目转成 Zig,这里介绍了一些感受,
- 文档缺乏
- 文件级别导入
- @fieldParentPtr
- 对
@fieldParentPtr
使用的介绍 - Generating documentation from zig build
作者在这篇文章里尝试在 zig build 文件中输出文档,目前步骤略微繁琐。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
const std = @import("std"); pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "myprogram", .root_source_file = .{ .path = "src/main.zig" }, .target = b.standardTargetOptions(.{}), .optimize = b.standardOptimizeOption(.{}), }); b.installArtifact(exe); const install_docs = b.addInstallDirectory(.{ .source_dir = exe.getEmittedDocs(), .install_dir = .prefix, .install_subdir = "docs", }); const docs_step = b.step("docs", "Copy documentation artifacts to prefix path"); docs_step.dependOn(&install_docs.step); }
- What's Zig got that C, Rust and Go don't have? (with Loris Cro)
- [视频] Loris 参与的一档播客
- A Simple Example of Calling a C Library from Zig
- 一个简明的教程,演示 Zig 如何引用 C 类库
- What is the Zig philosophy on APIs and abstraction?
一个 Reddit 帖子,讨论 Zig 的在 API 设计上的哲学、理念。一个有意思的点是 Zig 不支持私有的字段,全部都是 public 的。Andrew 在 Proposal: Private Fields #9909 这个 issue 里面讨论过原因,主要根据:
- 一个结构体的抽象,很难保证不泄漏,比如一个类型的 align、size,一个函数是否可以在 comptime 执行
- 一个包的兼容性,应该由文档来解释
- 增加私有字段,会增加语言的复杂度,而且这种复杂性本身是完全可以避免的
项目/工具
- zig build explained – building C/C++ projects
- 经典文章回顾,如何使用 Zig 构建系统编译 C/C++ 项目
- akhildevelops/cudaz
- A Zig Cuda wrapper
202310
重大事件
观点/教程
- Notes From the Field: Learning Zig
- Zig 初学者的使用经验分享
- Friendly Neighbor: A network service for Linux wake-on-demand, written in Zig
- 作者在这篇文章中分享了 用 Zig 重写之前 Ruby 写的一个网络工具,一方面是减轻资源消耗,另一方面是探索用“低级”语言来写程序。不错的案例分享。
- Zig Interfaces
作者介绍了 Zig 中如何实现接口这个经常需要用到的功能。最后的实现也比较巧妙,结合
anytype
与*anyopaque
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
const std = @import("std"); const Writer = struct { // These two fields are the same as before ptr: *anyopaque, writeAllFn: *const fn (ptr: *anyopaque, data: []const u8) anyerror!void, // This is new fn init(ptr: anytype) Writer { const T = @TypeOf(ptr); const ptr_info = @typeInfo(T); const gen = struct { pub fn writeAll(pointer: *anyopaque, data: []const u8) anyerror!void { const self: T = @ptrCast(@alignCast(pointer)); return ptr_info.Pointer.child.writeAll(self, data); } }; return .{ .ptr = ptr, .writeAllFn = gen.writeAll, }; } // This is the same as before pub fn writeAll(self: Writer, data: []const u8) !void { return self.writeAllFn(self.ptr, data); } }; const File = struct { fd: std.os.fd_t, fn writeAll(ptr: *anyopaque, data: []const u8) !void { const self: *File = @ptrCast(@alignCast(ptr)); // os.write might not write all of `data`, we should really look at the // returned value, the number of bytes written, and handle cases where data // wasn't all written. _ = try std.os.write(self.fd, data); } fn writer(self: *File) Writer { return Writer.init(self); } }; pub fn main() !void { var file = try std.fs.createFileAbsolute("/tmp/demo.txt", .{}); var my_file = File{ .fd = file.handle }; const writer = my_file.writer(); try writer.writeAll("hello world"); }
- io_uring basics: Writing a file to disk
- 作者演示了 io_uring 在 Go 与 Zig 中的基本使用,下面表格是一些测试数据
method | avg_time | avg_throughput |
---|---|---|
iouring_128_entries | 0.2756831357s | 3.8GB/s |
iouring_1_entries | 0.27575404880000004s | 3.8GB/s |
blocking | 0.2833337046s | 3.7GB/s |
- Zig is now also a Windows resource compiler
- 相当硬核的文章,作者最近给 Zig 贡献了一个大功能:支持 Windows 资源定义文件的编译,用户可以通过
zig rc
子命令来使用。 - Zig 多版本管理
- 由于 Zig 还在快速开发迭代中,因此项目很有可能出现新版本 Zig 无法编译的情况,这篇文章介绍了一些管理多个 Zig 版本的方式。
项目/工具
- zigcli
- a toolkit for building command lines programs in Zig
- pb2zig
- Pixel Bender to Zig code translator
- zigar
- Enable the use of Zig code in JavaScript project
- jinyus/related_post_gen
- 一个对常见语言进行压测的项目,项目里面有几种纯 CPU 的操作,看看哪个语言最快。
- nolanderc/glsl_analyzer
- Language server for GLSL (autocomplete, goto-definition, formatter, and more)
202309 | Bun 正式发布 1.0
重大事件
Bounties Damage Open Source Projects
在 2023-09-11 号,Wasmerio CEO 创建了 Support WASIX · Issue #17115,表示想赞助 Zig 开发者,让其更好地支持 WASIX 平台。
Andrew 与 Loris 在这篇文章中主要阐述了这么做为什么是伤害社区的行为:
- 助长竞争,牺牲合作
- 在软件开发的商业管理方面,悬赏是一种极为简单的方法,这可能让开发者关注短期效益,忽视长期利益,比如维护成本。
这篇文章其实很符合 Andrew 的理念,不想让过多的热钱涌入 Zig 社区,他更想保证 Zig 的独立性,这也是他们创办 Software You Can Love 的初衷。
Bun 1.0
面包终于出炉了!Bun 毫无疑问是 Zig 的明星项目,它在 2023-09-08 正式发布了 1.0 版本,这对开发者来说可能没什么太大的区别,毕竟就只是个 tag 而已,但是对于广大的用户来说,这无疑意味着可以在生产环境中去使用了。
Bun 并不简单的是个 Node.js 替代品,而是大而全的工具链:
- Transpilers,可以直接运行
js
jsx
mjs
ts
tsx
cjs
文件 - Bundlers,可以直接替代 webpack、esbuild 等工具
- Package managers,兼容 npm,识别
package.json
格式,可以替代:npm、yarn、 - Testing libraries,内置 test runner,支持快照测试、模拟和代码覆盖,可以替代:jest、ts-test
观点/教程
- Kiesel Devlog #1: Now passing 25% of test262
- 另一个 devlog,作者写了一个 JS engine 用来学习 Zig,该作者是 SerenityOS 系统中,Ladybird 浏览器 JS 引擎 LibJS 的作者
- Talk: Introducing Ghostty and Some Useful Zig Patterns
Mitchell Hashimoto 在这篇文章里分享了开发终端 Ghostty 时用的 Zig 常用模式。计划在 2024 年发布 1.0
- Comptime Interface
- Comptime Data Table Generation
- Comptime Type Generation
- B 站视频地址
- Learning Zig
一个 Zig 教程,写的非常易懂,推荐每个 Zig 爱好者阅读。目录
- Language Overview - Part 1
- Language Overview - Part 2
- Style guide
- Pointers
- Stack Memory
- Heap Memory & Allocators
- Generics
- Coding In Zig
- Conclusion
- Debugging a Zig Test Failure
- 非常硬核的文章,作者为了调查一个文件名太长的错误,使用了 DTrace 来探测内核函数的调用,对平时的问题排查非常有帮助
- Intercepting and modifying Linux system calls with ptrace
- 用 Zig 来封装 Dtrace,用于跟踪子进程的 syscall
- Managing Zig Versions with zvm: A Technical Dive
- 另一个 Zig 版本管理工具,不过这次是用 Zig 写的了
- When Zig Outshines Rust – Memory Efficient Enum Arrays
- 一个图文并茂的文章,重点推荐。作者这里通过分析 array of struct 的内存浪费情况,介绍了 Rust/Zig 中不同的解法,Zig 由于有强大的编译期元编程能力,能够更方便的实现 SoA(struct of arrays)
项目/工具
- ZigBrains
- A multifunctional Zig Programming Language plugin for the IDEA platform.
- fulcrum-so/ziggy-pydust
- A toolkit for building Python extensions in Zig.
- zig-curl
- Zig bindings to libcurl.
- darkr4y/OffensiveZig
- Some attempts at using Zig in penetration testing.
- Announcing Zig support for Wasm Workers Server
- Wasm Workers Server 是一个用于开发 serverless 应用的框架,近期增加了对 Zig 的支持,使用文档。
- dantecatalfamo/wireguard
- Command line wireguard configuration manager.
- iacore/libredo
- Reactive signal/Dependency tracking library in Zig.
- buzz-language/buzz
- A small/lightweight statically typed scripting language
Zig 语言更新
- Aro translate
- 用 Zig 写的 Aro 来替换 clang,来实现
translate-c
的功能
202308 | 0.11 正式发布
0.11 正式发布
0.11 终于在 8 月 4 号释出了,下面来看看它的一些重要改进吧。HN 讨论
Peer Type Resolution Improvements
对等类型解析算法得到改进,下面是一些在 0.10 中不能解析,但在 0.11 中可以解析的例子:
Peer Types | Resolved Type |
[:s]const T, []T | []const T |
E!*T, ?*T | E!?*T |
[*c]T, @TypeOf(null) | [*c]T |
?u32, u8 | ?u32 |
[2]u32, struct { u32, u32 } | [2]u32 |
*const @TypeOf(.{}), []const u8 | []const u8 |
而且现在使用 @intCast
这类 builtin 都只接受一个参数,目前类型根据上下文自动推断出来。
Multi-Object For Loops
可以同时对多个对象进行遍历:
|
|
@min and @max
主要有两个改动:
- 这两个 builtin 现在支持任意多个参数
- 返回的类型,会尽可能的紧凑
|
|
@inComptime
新加的 builtin,用于判断执行是否在 comptime 环境下执行:
|
|
类型转化相关 builtin 的重命名
之前 @xToY
形式的 builtin 现在已经改成了 @yFromX
,这样的主要好处是便于阅读(从右向左),这是草案。
Tuple 类型声明
现在可以直接用无 field 名字的 struct 来声明 tuple 类型:
|
|
之前只能用 std.meta.Tuple
函数来定义:
|
|
排序
现在排序算法分布两类:
- 稳定,blocksort 算法
- 不稳定,pdqsort 算法,它结合了随机快速排序的快速平均情况和堆排序的快速最坏情况。
与堆排的快速最差情况相结合,同时在具有特定模式的输入上达到线性时间。
Stack Unwinding
Zig 之前依赖 frame pointer 来做堆栈回卷,但它本身有些代价,因此线上环境可能会通过 -fomit-frame-pointer
将其禁用掉。
为了在这种情况下依然能够获取 panic 是的堆栈信息,Zig 现在支持了通过 DWARF unwind tables 和 MachO compact unwind information 来会恢复堆栈,详见:#15823。
包管理
0.11 首次正式引入了包管理器,具体解释可以参考:Zig Build System,而且很重要一点,step 之间可以并发执行,
Bootstrapping
C++ 实现的 Zig 编译器已经被彻底移除,这意味着 -fstage1
不再生效,Zig 现在只需要一个 2.4M 的 WebAssembly 文件和一个 C 编辑器即可,工作细节可以参考:Goodbye to the C++ Implementation of Zig。
代码生成
虽然 Zig 编译器现在还是主要使用 LLVM 来进行代码生成,但在这次发布中,其他几个后端也有了非常大的进步:
- C 后端,行为测试通过 98%,而且生成的 C 代码兼容微软的 MSVC,用在了 bootstrapping 中
- x86 后端,行为测试通过 88%
- aarch64 后端,刚开始
- WebAssembly 后端,行为测试通过 86%,
- SPIR-V 后端,SPIR-V 是在 GPU 上运行的着色器(shader)和内核的字节码表示法。目前,Zig 的 SPIR-V 后端专注于为 OpenCL 内核生成代码,不过未来可能也会支持兼容 Vulkan 的着色器。
增量编译
虽然这仍是一个高度 WIP 的功能,但这一版本周期中的许多改进为编译器的增量编译功能铺平了道路。其中最重要的是 InternPool。Zig 用户大多看不到这一改动,但它为编译器带来了许多好处,其中之一就是我们现在更接近增量编译了。增量编译将是 0.12.0 发布周期的重点。
观点/教程
- Error Handling In Zig
- 又一篇讨论错误处理的文章
- Commiting Type Crimes in Zig
- 对 Zig 类型系统的另一种用法,有些和邱奇数类似。
- Zig in 100 Seconds
- Zig 宣传视频
- Zig Build System & How to Build Software From Source • Andrew Kelley • GOTO 2023
- Andrew 关于构建系统的视频,B 站链接、Youbute
- Wrap your NIF with Zig
- NIF 是 Elixir 中进行 FFI 调用的方式,如果用原生 C 接口来用,会需要写很多胶水代码,
作者这里用 comptime 特性来定义了一个
make_nif_wrapper
来简化 NIF 的实现,这个技巧在与 C 项目交互时十分有用。 - Types and the Zig Programming Language
- matklad 对 Zig 类型系统的总结
- So Long, Twitter and Reddit
- Andrew 的最新文章,远离社交平台!
- WTF is Zig Comptime (and Inline)
- Taking off with Zig: Putting the Z in Benchmark — Double Trouble
项目/工具
202307 | 异步缺席 0.11
重大事件
Andrewk 在最新的文章 The Upcoming Release Postponed Two More Weeks and Lacks Async Functions 中指出,即将发布的 0.11 中将不会包含对异步的支持,现在异步是在 stage2-async 这个分支上来开发,但是在开发过程中,总是有其他事情出现,然后 Andrewk 就先去搞这些事情了。因此,把对异步的支持放到 0.12 上了。
另一件事是 Jacob Young Joins the Core Zig Team,Core Team 迎来了另一位全职开发者,常用 ID jacobly0,下面是他最近的提交记录:
恭喜 Core Team,又添一虎将!
观点/教程
- Copy Hunting | TigerBeetle
- 比较有意思的文章,通过分析 LLVM 的 IR,来避免程序中不必要的 memcpy 以及如何减少 binary 体积
- Taking off with Zig: Putting the Z in Benchmark
- Zig 入门文章,作者使用 Zig 来实现了一个 benchmark 库,里面有作者的感受,语言小巧,主要的语言特点:独特的错误处理、显式的内存控制、comptime 执行
- The New Wave of Programming Languages: Pony, Zig, Crystal, Vlang, and Julia
- 多种语言的对比,Zig 部分的对比:
Pros | Cons |
---|---|
Excellent low-level control over code | Relatively new and evolving |
Emphasis on safety and reliability | Limited library support |
Good interoperability with other languages | Steep learning curve |
- Parsing timestamps and generating RFC3339 dates in Zig
Zig 标准库里有返回 unixtime 时间戳的函数,但是没有格式化函数,作者这里给出了一种实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
pub const DateTime = struct { year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8, }; pub fn fromTimestamp(ts: u64) DateTime { const SECONDS_PER_DAY = 86400; const DAYS_PER_YEAR = 365; const DAYS_IN_4YEARS = 1461; const DAYS_IN_100YEARS = 36524; const DAYS_IN_400YEARS = 146097; const DAYS_BEFORE_EPOCH = 719468; const seconds_since_midnight: u64 = @rem(ts, SECONDS_PER_DAY); var day_n: u64 = DAYS_BEFORE_EPOCH + ts / SECONDS_PER_DAY; var temp: u64 = 0; temp = 4 * (day_n + DAYS_IN_100YEARS + 1) / DAYS_IN_400YEARS - 1; var year: u16 = @intCast(100 * temp); day_n -= DAYS_IN_100YEARS * temp + temp / 4; temp = 4 * (day_n + DAYS_PER_YEAR + 1) / DAYS_IN_4YEARS - 1; year += @intCast(temp); day_n -= DAYS_PER_YEAR * temp + temp / 4; var month: u8 = @intCast((5 * day_n + 2) / 153); const day: u8 = @intCast(day_n - (@as(u64, @intCast(month)) * 153 + 2) / 5 + 1); month += 3; if (month > 12) { month -= 12; year += 1; } return DateTime{ .year = year, .month = month, .day = day, .hour = @intCast(seconds_since_midnight / 3600), .minute = @intCast(seconds_since_midnight % 3600 / 60), .second = @intCast(seconds_since_midnight % 60) }; }
- Custom JSON serialization in Zig
Zig 里面虽然有很好的 JSON 序列化支持,但是有些时候我们需要自定义某个字段的解析,与 Go
json.Marshaller
类似,Zig 会在序列化时查找类型的jsonStringify
函数,通过实现这个函数就可以达到目的,文中给出了个示例:1 2 3 4 5 6 7 8
const NumericBoolean = struct { value: bool, pub fn jsonStringify(self: NumericBoolean, out: anytype) !void { const json = if (self.value) "1" else "0"; return out.print("{s}", .{json}); } };
- Three Different Cuts
- matklad 的文章,介绍了 Rust、Go、Zig 三种语言的 Cut 实现
- Zig Bits 0x4: Building an HTTP client/server from scratch
- 介绍了 std.http 这个模块的使用
- We Put a Distributed Database In the Browser – And Made a Game of It
- TigerBeetle 的新花样,把数据库搬到了 Web 上。HN 讨论
- Zig: great design for great optimizations
- 比较有意思的文章,作者比较了 Clang、Zig 对相同逻辑代码生产的 LLVM IR,Zig 生成的 IR 更加精简
项目/工具
- Zig helped us move data to the Edge. Here are our impressions
- Turso 公司的官博,它们公司的产品时边缘数据库,自动同步 PG 的表到 Edge 端,减少访问的时延。在这篇文章里他们介绍了使用 Zig 编写 PostgreSQL 插件的经历,得益于
translate-c
,他们可以直接从已有的 C 代码开始构建他们的产品。插件地址:pg_turso - tensorush/meduza
- 🦎 🧜♀️ Zig codebase graph generator that emits a Mermaid class diagram
- AndreaOrru/zen
- Experimental operating system written in Zig
- EugenHotaj/zig_gpt2
- GPT-2 inference engine written in Zig
202306 | Zig 要分叉了?
重大事件
一个是这个:The Zig subreddit has closed,现在 Ziggit 算是官方钦定的论坛了。
另一个是月底出来的大新闻:File for Divorce from LLVM · Issue #16270 · ziglang/zig
这个 issue 主要讨论的是把 LLVM 从 Zig 中彻底移除,动机和优势都列在里面了,这里不再赘述,这里重点说下影响:
- 去掉 C++/Objc 的支持,
- 支持的 target 会变少
从 issue 本身和 Lobsters、HN 上的评论看,大家主要担忧的是对 C++ 的支持。由于非常多的基础软件都是构建在 C++ 之上的,如果没有了对 C++ 的支持,那么 Zig 作为工具链这一选择的可行性就大打折扣了,要知道 Zig 之前最主要的卖点就是这个,比如:Maintain it With Zig。
有人提议用 Zig 重写一个 C++ 前端不就好了?但这属于理论上可行,实际没有可操作性的,因为 C++ 太复杂了。
其实 Zig 从 0.10.0 版本开始,就一直在着手 Self-Hosted Compiler 的开发。看得出,Zig 团队一直在追求极致,从编译速度,到二进制大小(以下数字均来自 0.10.0 的 release note):
- Wall Clock Time: 43 seconds to 40 seconds (7% faster)
- Peak RSS: 9.6 GiB to 2.8 GiB (3.5x less memory used)
- As a point of comparison, a stripped release build of Zig with LLVM is 169 MiB, while without LLVM (but with all the code generation backends you see here) it is 4.4 MiB.
这个 issue 在互联网上迅速引起了热烈讨论,当然少不了吃瓜群众,以至于 Andrewk 又追加了一条评论:
I see a lot of speculation in this GitHub Issue from folks who are not involved in Zig in any way. I would respectfully ask you to please take such speculation elsewhere. This issue tracker is for focused technical discussion by those who are actually using Zig, today. The noise in this thread distracts from the valuable comments by users who are sharing their use cases for the relevant features of Zig.
..which, by the way, I'm one of. For example, my music player reboot branch depends on chromaprint which is, dun dun dun, C++ code.
I'm not going to simultaneously shoot myself and valuable community members in the face by yanking a load-bearing feature out from underneath us, without any kind of upgrade path. It's a bit unfortunate that the Internet has taken that narrative and run with it.
For example, one thing to explore, later - once all those boxes above are checked - is whether we can satisfy the C++ compilation use case, as well as the LLVM optimization use case, with the package manager. The results of this exploration will heavily impact the ultimate decision of whether to accept or reject this proposal.
Please, relax. Nothing is going to happen overnight, and nothing is more important than making sure our esteemed Zig users' needs are taken care of, one way or another. Whatever happens will happen in due time, with due respect for real world projects. This proposal is aspirational - something to look forward to and consider in the coming years.
微信群里不少小伙伴也在担忧这个 issue 会不会导致 Zig 的 fork,甚至灭亡。其实看了上面的评论大家就应该放心了,Zig 团队知道用户的需要,不会搬起石头砸自己的脚。
我觉得通过这个事件更能坚定我投资 Zig 的信心了,一个追求极致的团队,不需要我们吃瓜群众瞎操心,有这个时间不如去看看 Zig 的各种 backend 进展,能不能给 fix 几个 regression?!
最后,即便 Zig 这个项目夭折了,我相信通过这个学习的过程也有助于提高我们对系统编程、编译器的理解,不是吗?
观点/教程
- A Note About Zig Books for the Zig Community
- Loris Cro 的博客,由于现在 Zig 的关注度越来越高,一些出版社开始联系社区的人出一本 Zig 的书,Loris 这里阐述了与出版社合作的利弊,以及他也在写一本关于 Zig 的书
Intro to Zig / systems programming
,由于 Zig 还是不停的开发中,因为书中会尽量少的去涉及 stdlib 的内容。 - How far away is 0.11 really?
- 社区用户对 0.11 版本发布时间的疑问?
- Mach: providing an ecosystem of C libraries using the Zig package manager
- 作者在文章讲述了利用 Zig 来打包 C 依赖的优势。
- The Seamstress Event Loop In Zig
- Metaprogramming in Zig and parsing CSS
- Embed git commit in Zig programs
- 把 git 的 commit id 嵌入项目中非常有助于问题排查
- Problems of C, and how Zig addresses them
不错的入门资料,主要内容:
- Comptime over Textual Replacement Preprocessing
- Memory Management, and Zig Allocators
- Billion dollar mistake vs Zig Optionals
- Pointer arithmetics vs Zig Slices
- Explicit memory alignment
- Arrays as values
- Error handling
- Everything is an expression
- C has a more complex syntax to deal with
- Minimal Linux VM cross compiled with Clang and Zig
- 一篇有意思的文章,作者的任务是跑 Linux kernel 的 test,为了能够方便、简单的跑不同的平台,作者尝试用 Zig 的交叉编译能力来解决这个大难题
- Zig dangling pointers and segfaults
- I think Zig is hard…but worth it
- 安利 Zig 的文章,HN 讨论
项目/工具
- pondzdev/duckdb
一个将 DuckDB 数据库通过 HTTP API 暴露出来的代理,主要是利用了 DuckDB C API,示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# open the database in readonly (DB must exist in this case) $ ./duckdb-proxy --readonly db/mydatabase.duckdb $ curl http://localhost:8012/api/1/exec \ -d '{"sql": "select version()"}' { "cols": [ "version()" ], "rows": [ [ "v0.8.1" ] ] }
- ryleelyman/seamstress
- Lua monome + OSC scripting environment
- Rust VS Zig benchmarks
- Which programming language or compiler is faster
- ziglang/shell
- Shell completions for the Zig compiler.
- menduz/zig
- Steamwork bindings for Zig.
202305 | HTTP is built-in
重大事件
这个月主要的事情就是 HTTP server 在标准库的增加了,具体可参考:
观点/教程
- Integrating Zig and SwiftUI
- Mitchell 在用 Zig 实现了一个终端后,虽然没有把源码放出来,但是有了这个文章总结。
- Zig Language Server And Cancellation
- Matklad 对 ZLS 实现分析:如何快速响应用户的编辑命令,在作者来看,最主要是 server 端要能够及时取消已经过期的操作。
- Bootstrapping Uber’s Infrastructure on arm64 with Zig
- Zig 社区的老朋友 Motiejus Jakštys 在 Uber 的 arm 化过程中,探索了如何使用 Zig 提供对 Go 代码的交叉编译。
- The Worst Zig Version Manager
- 在没有 Zig 环境的机器上,如何安装 Zig ?作者的思路是每个项目都附带一个脚本来做这件事,这种方式看似比较笨拙,但很有实用性。
- Writing an init system in a language I don't know
- 作者介绍了使用 Zig 开发一个 init 系统的经历,文中主要吐槽了现在 Zig 的文档严重不足 🙃,但看得出,作者依旧是喜欢 Zig 的。
- SIMD with Zig
- 作者演示了如何利用 SIMD 函数来改进
indexOf
函数 - Anytype Antics
- 作者介绍了如何使用
anytype
,一些示例包括:Duck Type、Traits、Comptime Tagged Unions - Using Zig | My Initial Thoughts on Ziglang
- 视频
- Zig: First Impressions
- 视频
- (Possibly) LVGL in WebAssembly with Zig Compiler
- Initial Commit: Zig Build System
- Writing DNS resolver in Zig
项目/工具
- Zig by Example
- 非常好的学习资料。Learn How to use Zig’s Standard Library, by small examples.
- sleibrock/zigtoys
- All about Zig + WASM and seeing what we can do
- Aandreba/zigrc
- Zig reference-counted pointers inspired by Rust's Rc and Arc
- Hanaasagi/struct
- Deserialize env vars into typesafe structs
- tristanisham/minigrep
- A Zig version of the Rust book's minigrep tutorial program
- jsomedon/night.zig
- Simple tool that just install & update zig nightly.
- 4imothy/termy48
- A 2048 game to run in terminal
- zig-html-example
- 一个有趣的演示,利用 comptime 来定义 HTML 中的 Tag
- KilianVounckx/rayz
- 另一个 Raylib 的 bindings
- mitchellh/zig
- Objective-C runtime bindings for Zig (Zig calling ObjC).
202304 | 首次闯入 Tiobe 前 50
重大事件
在 2023 四月份的 Tiobe 指数上,Zig 排名 46,尽管 Loris 发推表示这个数字对 Zig 来说没什么实际意义,但对于多数吃瓜群众来说,这还是十分让人鼓舞的。
For people who heard about Zig just recently:
- Zig is not 2x faster than Rust, despite what recent benchmarks might lead you to believe.
- You won't find many Zig jobs for a few years still, despite the Tiobe stuff.
- Don't join to the Zig community just to rant about Rust.
— Loris Cro ⚡ (@croloris) April 13, 2023
观点/教程
- When should I use an UNTAGGED Union?
- Loris 的文章,作者利用访问 untagged union 的未赋值字段是一种 safety-checked UB 的行为,来解决数组成员被重新赋值过的情况。
- Data driven polymorphism
- 作者用 Zig 来实现 Clojure 语言中的 defmulti,以达到『动态派发』的效果
- Testing and Files as Structs
- 作者演示了一个文件作为 struct 的效果,这样导入时就可以用
const Node = @import("Node.zig")
的方式了。 - Sneaky Error Payloads
- 一种在错误中携带上下文信息的方式,上一期的月报也有类似讨论。 Errors and Zig
- Regular Expressions in Zig
- 由于 Zig 现在不支持 C 中的 bitfields,因此无法直接使用 Posix 的
regex.h
,这篇文章介绍了一种解决方法。 - Zig Build System
- 对 Zig build 系统的介绍
- Reasonable Bootstrap
- 探讨了编译器如何实现自举的方式
- Data Oriented Parallel Value Interner
- Matklad 探讨了如何实现一个高性能的 Interner
- TigerStyle! (Or How To Design Safer Systems in Less Time)
- Systems Distributed 23 视频。B 站链接
- What Is a Database?
- Systems Distributed 23 视频,B 站链接,作者博客:Scattered Thoughts
项目/工具
- Coming Soon to a Zig Near You: HTTP Client
- 对标准库
std.http
的介绍。 - Zig Bits 0x3: Mastering project management in Zig
- 介绍了如何更好地维护一个 Zig 项目,包括:新增依赖、增加测试覆盖率、增加文档、基于 GitHub Action 做持续集成等。
- ityonemo/zigler
- zig nifs in elixir
- Ziggifying Kilo
- 使用 Zig 重写 kilo 编辑器,目前仅能在 Linux 上运行
- jakubgiesler/VecZig
- Vector implementation in Zig
- b0bleet/zvisor
- Zvisor is an open-source hypervisor written in the Zig programming language, which provides a modern and efficient approach to systems programming.
202303 | 并发编译
观点/教程
- Creating arbitrary error values by using error.Something syntax
下面两种方式是等价的:
1 2
const err = error.FileNotFound; const err = (error {FileNotFound}).FileNotFound;
- Errors and Zig
主要讲述了 Zig 中如何处理错误,如何携带上下文信息
1 2 3 4 5 6 7 8 9
var x = try thingThatCouldFail(); if (thingThatCouldFail()) |good_value| { x = good_value; break; } else |_| { // do something that should fix it for the next time tries -= 1; }
- Zig Bits 0x2: Using defer to defeat memory leaks
- 主要介绍了如何探测内存泄漏,如何用
defer
来规避 - Naive parallel map implementation in Rust and Zig
- The Curious Case of a Memory Leak in a Zig program
- When Zig is safer and faster than Rust
- 比较有趣的文章,作者使用 unsafe rust 与 zig 来实现一个 bytecode 解释器,比较重要的一点是具备 mark-sweep 的 GC 功能。
- Meet Zig: The modern alternative to C | InfoWorld
- 一篇科普 Zig 的文章
- Cross-Compiling and packaging C, Go and Zig projects with Nix
- 文章介绍了如何
利用 Nix 进行交叉编译,对于 C 依赖,作者是通过修改
pkg-config
的*.pc
来支持的 - Zig Quirks
- 介绍 Zig 的一些特点
- Zig And Rust
项目/工具
- macovedj/doink
- Making WebAssembly Components with Zig
- craftlinks/zig_learn_opengl
Follow the Learn-OpenGL book using Zig
- b0bleet/zvisor
- Zig-based Hypervisor (WIP)
- flouthoc/ztick
- Tiny desktop utility to keep notes
- ringtailsoftware/zig-wasm-audio-framebuffer
- Examples of integrating Zig and Wasm for audio and graphics on the web
Zig 语言更新
- zig build: run steps in parallel #14647
一个比较大的更新,编译支持了并发。由于改动比较大,该 PR 合并后出现了一些 bug,一个影响比较大的是 test 的构建方式不一样了。
1 2
- test_step.dependOn(&exe_tests.step); + test_step.dependOn(&exe_tests.run().step);
之前老方式写的 test_step
在新版本不会再执行了。这样对于 Build 系统来说其实是更合理了。
现在 addTest
和 addExecutable
一样,输出都是 CompileStep
,它默认不会执行,需要调用 run()
拿到 run step 才可以。
Zig 构建系统介绍
构建系统其实是 Zig 生态中比较重要的一环,和 Rust 不同,Zig 即是一门编程语言,也是一系列工具链,比如编译 Zig 时,没有 zigc 这个二进制文件,用的是 zig build-exe
或 build-lib
。
build.zig
的作用就是提供了一套声明式 API 来构造 build-exe
的参数。这里面有一个核心概念: Step
,它构成了一个有向无环图,用来驱动整个编译过程。
每个 Step 做的事情是由 MakeFn
定义的,它的签名是:
|
|
但一般来说,我们并不需要自己去实现 MakeFn,内置的 Step 已经可以满足大部分需求,比如:
CompileStep
编译二进制、动态链接库、静态链接库InstallArtifactStep
把编译生成的文件复制到zig-out
中ObjCopyStep
执行 objcopy 命令OptionsStep
可以用来定义编译时的一些常量,作为 module 被当前程序使用,比如把当前项目的构建时间、Git 信息写入到代码中。类似于 Go 里面的go build -ldflags="-X 'package_path.variable_name=new_value'"
RunStep
执行二进制
Step 中有一类比较特殊,称为 TopLevelStep(简称 TLS),它们可以直接通过 zig build {topLevelStep}
的方式来执行,Zig 默认有两个 TLS:
- install,安装二进制
- uninstall,卸载二进制
|
|
上面这段代码就定义了一个 TLS: run
,它依赖 exe 的执行 step,exe 本身又是个编译 step,因此在 zig build run
时,会依次执行:
|
|
Zig 的编译系统设计的还是挺巧妙的,而且 build.zig
是新人接触 Zig 是打交道最多的代码,如果搞不清它的执行过程,一方面心里比较难受,另一实际方面是影响问题排查。
如果读者还是对 build.zig
有所困惑,可以参考下面这两个文章,虽然有些过时,但是原理是一样的:
202302 | 精益求精的包管理
包管理器进展
包管理器自 #14265 合并后一直在不断推进,以下两个是最主要的改变:
build system terminology update: package, project, module, dependency
这里重新梳理了现在的术语,主要有以下几个:
package
文件的集合,由文件的 hash 值唯一指定,一个 package 可能包含任意数目的 compilation artifacts 与 modules。dependency
不同 package 之间的有向边,一个 package 可以有任意个依赖,一个 package 也可以用作任意项目的依赖module
文件的集合,每一个模块都有一个 root 文件,在被@import
时用到。compilation artifact
编译构建产物,可以是 static library,dynamic library,an executable 或 an object file,对应之前版本的LibExeObjStep
introduce Zig Object Notation and use it for the build manifest file (build.zig.zon)
使用 zon 格式替代之前的 ini,格式如下:
1 2 3 4 5 6 7 8 9 10
.{ .name = "awesome-cli", .version = "0.1.0", .dependencies = .{ .simargs = .{ .url = "https://github.com/jiacai2050/simargs/archive/0a1a2afd072cc915009a063075743192fc6b1fd5.tar.gz", .hash = "1220a6554eccb2e9a9d7d63047e062314851ffd11315b9e6d1b5e06a9dde3275f150", }, }, }
一些使用了包管理的实际项目:
也欢迎大家给自己熟悉的 C/C++ 项目提 PR 让其支持 zig build,让构建不再那么痛苦。
观点/教程
- How a Zig IDE Could Work
- Zig tips: v0.11 std.build API / package manager changes | Hexops' devlog
- pcre2 support zig build
- Multi-Object For Loops + Struct-Of-Arrays
Zig's Curious Multi-Sequence For Loops,Lobster 评论 上面这两篇的文章都是演示了最新的 for 语法,开始支持了 range:
1 2 3
for (0..4) |n| { std.debug.print("{} ", .{n}); }
同时也支持了一次性迭代多个数组的功能:
1 2 3 4 5 6
var elems = [_][]const u8 { "water", "earth", "fire", "wind" }; var nats = [_][]const u8 { "tribes", "kingdom", "nation", "nomads" }; for (elems, nats) |e, n| { std.debug.print("{s} {s}\n", .{e, n}); }
- Zig Bits 0x1: Returning slices from functions 这篇文章演示了从一个函数内返回局部变量的问题与解法
- Smoking Hot Binary Search In Zig
202301 | 包管理来了
0.10.1 版本发布
一个小版本,主要是 bugfix。最主要的功能是:Package Manager MVP,Zig 终于开始支持包管理了!
不过才刚刚开始,有一个面板来跟踪相关 issue 进度。使用的配置文件是 build.zig.ini
,格式如下:
[package]
name=libffmpeg
version=5.1.2
[dependency]
name=libz
url=https://github.com/andrewrk/libz/archive/f0e53cc2391741034b144a2c2076ed8a9937b29b.tar.gz
hash=c9b30cffc40999d2c078ff350cbcee642970a224fe123c756d0892f876cf1aae
[dependency]
name=libmp3lame
url=https://github.com/andrewrk/libmp3lame/archive/497568e670bfeb14ab6ef47fb6459a2251358e43.tar.gz
hash=9ba4f49895b174a3f918d489238acbc146bd393575062b2e3be33488b688e36f
build.zig
引用方式:
|
|
其他关注点:
- LLVM 升级到 15.0.7
- 是 0.10.x 的最后一个 release 版本
观点/教程
- Code study: interface idioms/patterns in zig standard libraries
- 由于 Zig 目前还不支持接口抽空,本文介绍了标准库中来实现类似功能的五种方式
- A Zig Diary
- 作者分享了对 Zig 的使用体验
- Why Accounting Needs Its Own Database with Joran Greef of Tiger Beetle
- 播客分享
- Crossplatform JNI builds with Zig
- 又一个使用 Zig 作为交叉编译的例子
项目/工具
- Introducing ⚡zap⚡ - blazingly fast backends in zig
- Zap 是 Zig 对 facil.io - The C Web Application Framework 的封装,本文算是对它的宣传。
- Indexing every Zig for great justice
- 本文介绍了另一种语言服务器协议(LSP):SCIP,并用 zig 实现。项目处于早期阶段。
- dantecatalfamo/zig-git
- Implementing git structures and functions in zig
- axiomhq/zig-hyperloglog
- Zig library for HyperLogLog estimation
- This Week In Zig
- 一个介绍 Zig 的周刊,主要是 master 分支上的改动
202211 | 0.10 横空出世
0.10.0 Release Notes
本月最大的事情就是 0.10 版本发布了,主要功能就是 self-hosted compiler,也称为『自举』,即可以用 Zig 来写 Zig 编译器,自举之所以对于一门语言如此重要,主要在于,这说明了该语言可以处理足够复杂的系统,不再只是玩具而已。编译的提升:
- Wall Clock Time: 43 seconds to 40 seconds (7% faster)
- Peak RSS: 9.6 GiB to 2.8 GiB (3.5x less memory used)
赶紧升级吧,少年!
zigcc 中文社区微信群
欢迎喜欢 Zig 的小伙伴加入!
观点/教程
- Wasmer 3.0 使用 Zig 进行跨平台编译 · Discussion #35 · zigcc/forum
- Easy Interfaces with Zig 0.10.0。由于 Zig 中没有 interface/trait 这种抽象类型,作者这里通过 0.10 提供的一个新功能(inline else)来实现类似效果:
|
|
My hopes and dreams for ‘zig test’。作者对
zig test
一些不满意的地方,这里面有个词比较有意思:paper-cuts,中文直接翻译就是“被纸张划的伤痕”,在软件领域特指:影响用户体验的小缺陷,虽然不严重,但是比较烦人。Writing a SQL database, take two: Zig and RocksDB 。本文作者是 TigerBeetle 的联合创始人 Phil,这篇文章主要演示了基于 Zig 做 RocksDB 的 binding,并在此基础上,增加 SQL 层,实现简单的 CRUD 功能。代码地址:eatonphil/zigrocks
Debugging undefined behavior caught by Zig。Hexops 官博,本文讨论了一个有意思的问题:UBSan 的一个 bug 导致 Mach engine 的测试失败,更准确说是 UBSan 需要内存地址对齐来工作,但是现在主流的处理器(x86、ARM、RISC-V 等)都可以处理非对齐的地址访问。
Using rr to quickly debug memory corruption,本文作者通过使用 rr 这个工具来排查内存损坏的问题
A Programmer-Friendly I/O Abstraction Over io_uring and kqueue。 TigerBeetle 官博,HN 讨论
How zig-spoon (and lots of coffee) helped me sort thousands of pictures。本文作者通过 spoon 这个库开发了一个帮助自己进行图片打标的 UI 工具,
项目/工具
- Zig 程序设计语言中文手册 GitHub 用户 @sxwangzhiwen 制作,论坛相关讨论。
- dantecatalfamo/zig-dns: Experimental DNS library implemented in zig
- Neovim Zig Plugin written in Lua
- trace.zig: A small and simple tracing client library,项目地址:Zig tracing / trace.zig
- Zig Support plugin for IntelliJ and CLion version 0.2.0 released
Zig 语言更新
202210 | 0.10 蓄势待发
观点/教程
- Zig Is Self-Hosted Now, What’s Next? | Loris Cro’s Blog | 0.10 即将在 11-01 号发布,Loris 回顾了目前 stage2 的进展,包管理器是下一个目标,但是不会引入中央仓库
- Loris 会在 Twitch 直播这次的 release party
- Howto Pair Strings with Enums 利用 Zig comptime 的能力为 enum 增加描述信息
- A Database Without Dynamic Memory Allocation | TigerBeetle 讲述了如何静态内存的优势,如何应用到数据库中,以及 Zig 为实现这种设计方式的优势
- That Time I Tried Porting Zig to SerenityOS - sin-ack’s writings
- Building a high-performance database buffer pool in Zig using io_uring’s new fixed-buffer mode
- Zig-style generics are not well-suited for most languages
- Zig and WebAssembly are a match made in heaven
- [视频] Stay Together For The Kids - Andrew Kelley - Software You Can Love 2022
- [视频] Ziglibc: Sweeping out the rug from underneath C - Jonathan Marler - Software You Can Love 2022
- [音频] 005. 与 LemonHX 畅聊新一代编程语言 Zig – RustTalk
项目/工具
- Himujjal/zig-json5: A JSON5 parser/stringifier for Zig resembling the std.json API
- hexops/mach-examples: Mach core & engine examples
- sagemathinc/cowasm: CoWasm: Collaborative WebAssembly for Servers and Browsers. Built using Zig. Supports Python with extension modules, including numpy.
- loc 使用 mmap 后速度快了 2 倍
- 一个 Zig Hackers 的 Twitter 列表:Zig Hero
- A minimal RocksDB example with Zig
Zig 语言更新
202209 | 锋芒毕露
Zig VS Rust 火花
在 9/10 号左右,在 Twitter 上牵起了一小波关于 Zig VS Rust 的小火花,以至于最后 Zig 创始人 Andrew Kelley 发推表示 Let us exist。这里稍微整理下这件事情的过程: 本次事件主要涉及两个人:
- Rust 核心贡献者: Patrick Walton
- Zig 社区 VP: Loris Cro
时间线
- 8/26 号,一篇关于 wasm 2 Game Jam 的分析报告中,使用 Zig 的人数最多
- 9/9 号,这篇报告在 HackerNews 上引起了热烈讨论,其中 Walton 在多处回复中表示 Zig 语言的劣势,并称
It’s perfectly reasonable to take the position that it’s deeply problematic for a language aiming for wide use in 2022 to not be memory safe. There’s no requirement that you “focus on tradeoffs”, especially since real people get hurt by memory safety problems.
- Loris 回复到:
I think you’re actively hurting the project that you care about in your ineffective crusade, but hey, don’t let me stop you.
- 9/10 号,有人发推对 tigerbeetle 内存分配方式表示好奇:所有内存必须在启动时静态分配好
- Walton 回复到:
The weird thing is that this is used as an example of why you supposedly don’t need language-enforced memory safety.
But that literally is language-enforced memory safety! Just way more restrictive than what Rust has: if you hate the borrow check, try the “no heap” check…
This is wrong because you can still have UAF from freed stack frames.
- Loris 针对 Walton 的回复说了句“What a boring, useless take.(原推的回复已经被 Loris 删除了,可以在这里看到历史):
- Walton 发推表示在 2022 年,所有语言都应该是内存安全,应该算是『编程语言界的共识』,并称 Zig 是行业的一大退步 😅
- Loris 专门发了一个 Twitter thread 来阐述『软件的目标不仅仅是内存安全,更重要的是正确』。比如 tigerbeetle 这里提到的。而且即便内存安全,也可能发生 OOM
总结
上面的链接比较多,这里稍微总结下这次争论的问题:
Rust 用户觉得 Zig 不是内存安全的语言,Zig 认为 Rust 的语言过度复杂,这反而会导致程序复杂度挺升,导致程序产生错误行为
使用 Zig 的人大概率也是 Rust 用户,之所以有了安全的 Rust,还来选 Zig,笔者觉得大概率就是本次争论的观点,Rust 过于复杂,导致程序员不仅仅要考虑业务行为,还需要按照 Rust 的风格来编程,这加剧了程序出错的可能性。
观点/教程
- How (memory) safe is zig? 作者重点介绍了在内存安全方面,Zig 的优劣势。尽管 Zig 相比 C 有了明显的改进,但相比 Rust 这种在编译期就能发现程序问题来说,显得有些鸡肋,但在一些可控的环境下,比如 WASM、嵌入式环境中,Zig 还是有发挥的空间
- Hacked std.PriorityQueue for constant time update
- Flutter/Dart + FFI + Zig: Flutter 使用 FFI 调用 Zig 示例
- Building a Tiny Mutex
- Perfecting WebGPU/Dawn native graphics for Zig
- Cross-Compiling and packaging C, Go and Zig projects with Nix 介绍如何基于 Nix 来进行交叉编译
- Revisiting the design approach to the Zig programming language Sourcegraph 的一档播客,对 Zig 创始人的采访,介绍了 Zig 的由来,其中提到一个性能优化点是:untagged union,这里有它的一些介绍:Andrew Kelley claims Zig is faster than Rust in perfomance
- Zig ⚡ Improving the User Experience for Unused Variables
项目/工具
- Zig 开发常用类库,如果读者的 Zig 项目托管在 GitHub,推荐加上 zig-package 这个标签,这样可以自动被 https://zig.pm/ 收录
- https://zig.run/ - 在线运行 zig 代码
- Zig Support plugin for IntelliJ and CLion version 0.0.7 released
- zig-napigen Automatic N-API bindings for your Zig project.
- Dart 通过 FFI 调用 Zig 库示例
- zig-gamedev
- loc in Zig 代码行数统计工具
- Grep in Zig
- randomutils Generate 64-bit random numbers
- zig-pico 树莓派 Pico SDK 的 Zig 绑定库
- stm32f4.zig STM32F4(ARM Cortex M4 的高性能 32 位微控制器) 固件抽象层
Zig 语言更新
202208 | stage2 默认开启
观点/教程
- Growing a {{mustache}} with Zig
作者使用 Zig 开发时的目标:
- Robost,test 代码快
- Optimal,Zig 语言本身就要求开发者去考虑堆分配
- Reusable,用户可以在高性能(better performance)与低内存(minimal memory footprint)使用之间做取舍,以满足不同的场景
- Will Bun JavaScript Take Node’s Crown Hacker News 上的评论。作者从多个方面对比了 Node 与 Bun,Bun 均胜出
- Looking into Zig - Ayende @ Rahien。作者对比了 Zig 与 Rust/C 的区别
- Cool Zig Patterns - Gotta alloc fast。如果需要分配的对象只有一个,如何优化 Allocator 呢?作者给出了一个 memory pool 的实现,23 行代码
- Packed structs in Zig make bit/flag sets trivial | Hexops’ devlog。使用 Zig 的
packet struct
实现 bit set 功能
项目/工具
Virtual tables by vrischmann · Pull Request #100 · vrischmann/zig-sqlite。zig-sqlite 作者正常尝试封装 virtual table 的 API,这样就可以用 Zig 写 SQLite 模块了。
Zig Support plugin for IntelliJ and CLion version 0.1.0 released
Zig 语言更新
- make self-hosted the default compiler by andrewrk · Pull Request #12368
Master 分支默认已经是 stage2,这是个里程碑的事情,作者为了用户平滑升级,还写了份升级指南。优势就是:速度更快、内存占用更少、错误信息更加友好。其他相关改动:
- stage2+stage1: remove type parameter from bit builtins by Vexu · Pull Request #12574 · ziglang/zig
- Adds std.meta.FnPtr for easier stage1/stage2 compatibility by MasterQ32 · Pull Request #12613 · ziglang/zig
- Stage2 fixes by Vexu · Pull Request #12563 · ziglang/zig
- stage2: add note about function call being comptime because of comptime only return type by Vexu · Pull Request #12499 · ziglang/zig
- stage2: implement stack protectors by andrewrk · Pull Request #12472 · ziglang/zig
- Stage2 error set safety improvements by Vexu · Pull Request #12416 · ziglang/zig
- stage2 llvm: implement more C ABI by Vexu · Pull Request #12395 · ziglang/zig
- coff: improve default COFF/PE object parser by kubkon · Pull Request #12575 · ziglang/zig
- autodoc: error sets now display all their members by der-teufel-programming · Pull Request #12583 · ziglang/zig
- Autodoc: anon_init_struct support by kristoff-it · Pull Request #12598 · ziglang/zig
- compilation: avoid pointless caching by kristoff-it · Pull Request #12605 · ziglang/zig
- translate-c: Don’t add self-defined macros to global name table by ehaas · Pull Request #12562 · ziglang/zig
- fix(translate-c): fix off-by-one for leading zeroes by r00ster91 · Pull Request #12490 · ziglang/zig
- libstd: fix off-by-one error in def of ProcSym in pdb.zig by kubkon · Pull Request #12464 · ziglang/zig
- fix memory leak in NativePaths.zig by Techatrix · Pull Request #12469 · ziglang/zig
- std.fs: Fix
WalkerEntry.dir
not always being the containing dir by squeek502 · Pull Request #12444 · ziglang/zig - std.mem.zeroes: Zero sized structs with uninitialized members by N00byEdge · Pull Request #12246 · ziglang/zig
- stage2: Implement explicit backing integers for packed structs by ifreund · Pull Request #12379 · ziglang/zig
- std.io.Reader: bounded array functions by InKryption · Pull Request #12351 · ziglang/zig
202207 | 开刊 HelloWorld
观点/教程
- Zig 初体验 - Keep Coding
- undefined 值的作用
- 用 Zig 优化 yes 命令
- Some Thoughts on Zig — Sympolymathesy, by Chris Krycho
- Zig 语言最吸引人的一点:小巧
- ziglings-solutions 题解
- “these are some really impressively bad semantics to choose for your programming language” / Twitter
- How to Release your Zig Applications
- Zig files are structs - Zig NEWS ⚡
- Is it necessary to know C (or another systems programming language) before starting with Zig? : Zig
项目/工具
- Release bun v0.1.5 · oven-sh/bun
- zls 可以解析 build addPackage 的包
- natecraddock/ziglua: Zig bindings for the Lua C API
- Easily create TUI programs with zig-spoon!
- Zig Support plugin for IntelliJ and CLion version 0.0.6 released
- r4gus/zbor: CBOR parser written in Zig
- How I built zig-sqlite