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
有所困惑,可以参考下面这两个文章,虽然有些过时,但是原理是一样的: