Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e654aae
build: 新增 Zig 0.17 构建脚本与示例代码
jinzhongjia Oct 4, 2026
6b76ac1
docs: 同步 release 示例与正文到 Zig 0.17
jinzhongjia Oct 4, 2026
c3a1843
docs: 新增 0.17.0 版本说明与升级指南
jinzhongjia Oct 4, 2026
c43c46a
ci: 构建矩阵加入 Zig 0.17.0 并新增 0.17 格式检查
jinzhongjia Oct 4, 2026
46b4a6c
chore: 更新 README 与 AGENTS.md 中的版本支持范围
jinzhongjia Oct 4, 2026
1b89447
docs: 去掉中文引号两侧的空格以通过 autocorrect 检查
jinzhongjia Oct 4, 2026
56f0eff
docs: 移除 0.17 文档中关于 ZLS 暂不可用的提示
jinzhongjia Oct 5, 2026
8429082
docs: echo_tcp_server 去掉写死的 0.16 版本表述
jinzhongjia Oct 5, 2026
e4e4676
docs: 正文中描述当前版本的 0.16 表述改为版本无关的写法
jinzhongjia Oct 5, 2026
a79038b
docs: zig-command 同步 0.17 的 build、init、fmt、translate-c 与 fetch 变化
jinzhongjia Oct 5, 2026
59b2d85
fix(build_system): 修复子项目中过时的测试代码,并在构建时执行 zig build test
jinzhongjia Oct 5, 2026
a2a63d8
fix(import_dependency_build): 按配置与执行分离的模型重写构建脚本
jinzhongjia Oct 5, 2026
16a80c9
fix(loop): main 不再调用演示死循环的 WhileBasic 示例
jinzhongjia Oct 5, 2026
7383c83
refactor(result-location): 以 ArrayList 替代已弃用的 ArrayListUnmanaged
jinzhongjia Oct 5, 2026
68d22fe
docs: 正文中的优化模式名称同步为 0.17 的 debug/safe/fast/small
jinzhongjia Oct 5, 2026
d5e66a6
docs: 正文清理 0.17 已移除或弃用的写法
jinzhongjia Oct 5, 2026
f99ff0f
docs(update): 修正 0.17 版本说明与升级指南中的不准确描述
jinzhongjia Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ jobs:
matrix:
# macos 固定 15:macos-latest 已迁移到 macOS 26,Zig 在其上链接不到系统
# libSystem(所有 libc 符号 undefined),0.11-0.15 全部受影响
# 另外 0.17 要求 macOS 15.0+,macos-15 恰好满足
os: [ubuntu-latest, macos-15, windows-latest]
version: [0.11.0, 0.12.1, 0.13.0, 0.14.0, 0.15.1]
version: [0.11.0, 0.12.1, 0.13.0, 0.14.0, 0.15.1, 0.17.0]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,23 @@ jobs:
--exclude course/code/12/assembly.zig \
--exclude course/code/14/assembly.zig \
.
# 0.17 的 zig fmt 无法解析旧版本示例中已移除的语法(如数组乘法 `**`、
# `errdefer |err|`),因此只用它检查 0.17 相关的代码
lint-0_17:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: 0.17.0
- name: Verify formatting
run: |
zig fmt --check \
build.zig \
build/0.17.zig \
course/code/17 \
course/code/release
19 changes: 11 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
## 核心目标

1. 提供全面的 Zig 编程语言中文文档
2. 支持多个 Zig 版本(0.11 至 0.16)
2. 支持多个 Zig 版本(0.11 至 0.17)
3. 维护可运行的代码示例
4. 记录版本升级指南和破坏性变更
5. 构建高质量的中文 Zig 社区学习资源
Expand All @@ -31,8 +31,9 @@ zig-course/
│ ├── 0.12.zig # Zig 0.12 构建逻辑
│ ├── 0.13.zig # Zig 0.13 构建逻辑
│ ├── 0.14.zig # Zig 0.14 构建逻辑
│ ├── 0.15.zig # Zig 0.15 构建逻辑(当前重点)
│ └── 0.16.zig # Zig 0.16 构建逻辑
│ ├── 0.15.zig # Zig 0.15 构建逻辑
│ ├── 0.16.zig # Zig 0.16 构建逻辑
│ └── 0.17.zig # Zig 0.17 构建逻辑(当前重点)
│
├── course/ # 主要文档内容
│ ├── .vitepress/ # VitePress 配置
Expand All @@ -54,8 +55,10 @@ zig-course/
│ │ ├── 12/ # Zig 0.12 示例
│ │ ├── 13/ → ./12 # 符号链接(与 0.12 兼容)
│ │ ├── 14/ # Zig 0.14 示例
│ │ ├── 15/ # Zig 0.15 示例(当前活跃版本)
│ │ └── release/ → ./15 # 符号链接到最新稳定版
│ │ ├── 15/ # Zig 0.15 示例
│ │ ├── 16/ # Zig 0.16 示例
│ │ ├── 17/ # Zig 0.17 示例(当前活跃版本)
│ │ └── release/ # 与最新稳定版(当前为 17)内容保持一致的独立目录
│ │
│ ├── picture/ # 图片资源
│ └── public/ # 静态网站资源
Expand Down Expand Up @@ -191,7 +194,7 @@ Zig 源文件不在 `pnpm format` 范围内,需单独运行 `zig fmt .`。
**当前符号链接**:

- `course/code/13/` → `./12` (Zig 0.13 与 0.12 兼容)
- `course/code/release/` → `./15` (指向最新稳定版)
- `course/code/release/` 是独立目录(非符号链接),内容需与最新稳定版 `course/code/17/` 保持同步

**维护规则**:

Expand Down Expand Up @@ -269,7 +272,7 @@ zig build

#### 步骤 1:创建代码示例文件

**路径**: `course/code/15/<topic>.zig`(15 为当前活跃版本)
**路径**: `course/code/17/<topic>.zig`(17 为当前活跃版本,完成后同步到 `release/`)

代码文件结构规范:

Expand Down Expand Up @@ -356,7 +359,7 @@ outline: deep
**代码引用语法**:

- `<<<@/code/release/<file>.zig#<anchor>` - 引用指定锚点的代码片段
- `release` 是符号链接,指向当前最新稳定版本(如 15)
- `release` 目录与当前最新稳定版本(如 17)内容保持一致
- 锚点名称必须与代码文件中的 `#region` 名称完全匹配

#### 步骤 3:更新导航配置
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
- **基础入门**: 包括变量、类型、流程控制、错误处理等基础知识
- **高级主题**: 深入探讨 `comptime`、异步、内存管理、C 语言交互等高级特性
- **工程实践**: 涵盖构建系统、包管理、单元测试和代码风格指南
- **版本兼容**: 提供与 Zig 0.11-0.16 版本相对应的代码示例
- **版本兼容**: 提供与 Zig 0.11-0.17 版本相对应的代码示例
- **实战案例**: 包含 TCP 服务器等实际项目示例

## 📁 项目结构
Expand Down Expand Up @@ -84,7 +84,7 @@ zig-course/
### 环境要求

- **Node.js**: 需要 Node.js >= 24(脚本依赖原生 TypeScript 支持),包管理器使用 [pnpm](https://pnpm.io/)
- **Zig**: 支持 0.11-0.16 版本
- **Zig**: 支持 0.11-0.17 版本
- **autocorrect**: 用于中英文排版优化(可选)

### 快速开始
Expand Down
1 change: 1 addition & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub fn build(b: *Build) void {
14 => @import("build/0.14.zig").build(b),
15 => @import("build/0.15.zig").build(b),
16 => @import("build/0.16.zig").build(b),
17 => @import("build/0.17.zig").build(b),
else => @compileError("unknown zig version"),
}
}
129 changes: 129 additions & 0 deletions build/0.17.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const std = @import("std");
const Build = std.Build;
const log = std.log.scoped(.For_0_17_0);
const version = "17";

const relative_path = "course/code/" ++ version;

/// 需要链接 libc 的单文件示例,其余示例一律不链接 libc
const libc_examples = [_][]const u8{
"interact_with_c.zig",
"memory_manager.zig",
"pointer.zig",
};

pub fn build(b: *Build) void {
// get target and optimize
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const io = b.graph.io;

// 0.17 起 configure 阶段(运行 build.zig 的过程)的结果会被缓存。
// 这里在 configure 阶段遍历了示例目录,因此需要显式声明对该目录内容的依赖,
// 这样新增、删除或重命名示例后才会重新执行 configure。
b.dependOnDirectoryContents(b.path(relative_path));

// 0.17 移除了 `b.build_root` 与 `LazyPath.getPath`,改用 `b.root`(`Cache.Path`)
var dir = b.root.openDir(io, relative_path, .{ .iterate = true }) catch |err| {
log.err("open {s} path failed, err is {t}", .{ relative_path, err });
std.process.exit(1);
};
defer dir.close(io);

var iterate = dir.iterate();

while (iterate.next(io) catch |err| {
log.err("iterate examples_path failed, err is {t}", .{err});
std.process.exit(1);
}) |entry| {
switch (entry.kind) {
.file => {
if (!std.mem.endsWith(u8, entry.name, ".zig")) continue;
addSingleFileExample(b, entry.name, target, optimize);
},
.directory => {
if (entry.name[0] == '.' or std.mem.eql(u8, entry.name, "zig-out")) continue;
addProjectExample(b, entry.name);
},
else => {},
}
}
}

/// 单文件示例:编译为可执行文件,并运行其中的单元测试
fn addSingleFileExample(
b: *Build,
file_name: []const u8,
target: Build.ResolvedTarget,
optimize: std.lang.Optimize,
) void {
const output_name = file_name[0 .. file_name.len - ".zig".len];
const path = b.fmt("{s}/{s}", .{ relative_path, file_name });

const imports: []const Build.Module.Import = if (std.mem.eql(u8, file_name, "interact_with_c.zig")) imports: {
const c_header = b.addWriteFiles().add("interact_with_c.h",
\\#define _NO_CRT_STDIO_INLINE 1
\\#include <stdio.h>
);
// `std.Build.Step.TranslateC` 在 0.17 中已被标记为 deprecated,
// 官方推荐改为依赖 translate-c 包;为了让仓库根构建保持零依赖,这里暂时沿用内置步骤。
const translate_c = b.addTranslateC(.{
.root_source_file = c_header,
.target = target,
.optimize = optimize,
});
break :imports b.allocator.dupe(Build.Module.Import, &.{
.{ .name = "c", .module = translate_c.createModule() },
}) catch @panic("OOM");
} else &.{};

const link_libc: ?bool = for (libc_examples) |name| {
if (std.mem.eql(u8, name, file_name)) break true;
} else null;

// build exe
const exe = b.addExecutable(.{
.name = output_name,
.root_module = b.createModule(.{
.root_source_file = b.path(path),
.target = target,
.optimize = optimize,
.imports = imports,
.link_libc = link_libc,
}),
});

// add to default install
b.installArtifact(exe);

// build test
const unit_tests = b.addTest(.{
.name = b.fmt("{s}_test", .{output_name}),
.root_module = b.createModule(.{
.root_source_file = b.path(path),
.target = target,
.optimize = optimize,
.imports = imports,
.link_libc = link_libc,
}),
});
const run_unit_tests = b.addRunArtifact(unit_tests);
// 交叉编译(例如 -Dtarget=x86_64-windows)时跳过无法在宿主机运行的测试
run_unit_tests.skip_foreign_checks = true;

// add to default install
b.getInstallStep().dependOn(&run_unit_tests.step);
}

/// 项目类示例:子目录中带有独立的 build.zig,在 make 阶段执行 `zig build`
///
/// 0.17 将 configure 与 make 拆成了两个进程,configure 结果还会被缓存,
/// 因此不能再像旧版本那样在 build.zig 里直接 spawn 子进程,而要交给 Run 步骤。
fn addProjectExample(b: *Build, dir_name: []const u8) void {
const sub_build = b.addSystemCommand(&.{ b.graph.zig_exe, "build" });
sub_build.setName(b.fmt("zig build ({s}/{s})", .{ relative_path, dir_name }));
sub_build.setCwd(b.path(b.fmt("{s}/{s}", .{ relative_path, dir_name })));
sub_build.stdio = .inherit;

b.getInstallStep().dependOn(&sub_build.step);
}
8 changes: 8 additions & 0 deletions course/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ export default [
text: "版本说明",
collapsed: true,
items: [
{
text: "0.17.0 升级指南",
link: "/update/upgrade-0.17.0",
},
{
text: "0.17.0 版本说明",
link: "/update/0.17.0-description",
},
{
text: "0.16.0 升级指南",
link: "/update/upgrade-0.16.0",
Expand Down
2 changes: 1 addition & 1 deletion course/.vitepress/theme/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
const version: string = "0.16.0";
const version: string = "0.17.0";

export { version };
2 changes: 1 addition & 1 deletion course/advanced/assembly.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ outline: deep

<<<@/code/release/assembly.zig#inline_assembly

上面这段示例当前没有直接执行内联汇编:旧的 `syscall` 写法保留在注释中,实际路径只调用 `std.process.exit(0)`,避免把未迁移的内联汇编语法误当作 Zig 0.16 可运行示例。
上面这段示例当前没有直接执行内联汇编:旧的 `syscall` 写法保留在注释中,实际路径只调用 `std.process.exit(0)`,避免把未迁移的内联汇编语法误当作当前版本可运行的示例。

内联汇编是以 `asm` 关键字开头的一个表达式,这说明它可以返回值(也可以不返回值),`volatile` 关键字会通知编译器,内联汇编的表达式会被某些编译器未知的因素更改(例如操作系统,硬件 MMIO 或者其他线程等等),这样编译器就不会额外优化这段内联汇编。

Expand Down
47 changes: 32 additions & 15 deletions course/advanced/interact-with-c.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,31 @@ Zig 定义了几个对应 C ABI 的基本类型:

## C Header 导入

C 语言共享类型通常通过引入头文件实现。Zig 0.16 起推荐把头文件翻译放到 `build.zig` 中:先用 `addTranslateC` 生成模块,再在 Zig 代码里像普通模块一样 `@import("c")`。
C 语言共享类型通常通过引入头文件实现。`@cImport` 在 Zig 0.16 中被标记为 deprecated,并已在 Zig 0.17 中**彻底移除**,因此头文件翻译必须放到 `build.zig` 中完成:先把 C 头文件翻译为一个 Zig 模块,再在 Zig 代码里像普通模块一样 `@import("c")`。

`build.zig` 中的核心写法如下:
Zig 0.17 官方推荐使用 ZSF 维护的 [translate-c](https://codeberg.org/ziglang/translate-c) 包来完成翻译,它与构建系统内置的 `addTranslateC` 是同一套实现,但提供了更多配置项,并且拥有独立于 Zig 工具链的发布节奏。首先添加依赖:

```sh
zig fetch --save git+https://codeberg.org/ziglang/translate-c#2.0.0
```

::: warning 注意版本

translate-c 的 `main` 分支跟踪的是 Zig 的 master 分支(当前已是 0.18 开发版),使用 Zig 0.17 时请固定到 `2.0.0` 标签(或 `zig-0.17.x` 分支),否则可能拉取到不兼容的版本。

:::

然后在 `build.zig` 中这样使用:

```zig
const translate_c = b.addTranslateC(.{
.root_source_file = b.path("src/c.h"),
const Translator = @import("translate_c").Translator;

const translate_c = b.dependency("translate_c", .{});
const c: Translator = .init(translate_c, .{
.c_source_file = b.path("src/c.h"),
.target = target,
.optimize = optimize,
// 默认 link_libc = true,翻译出的模块会自动链接 libc
});

const exe = b.addExecutable(.{
Expand All @@ -54,11 +70,10 @@ const exe = b.addExecutable(.{
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "c", .module = translate_c.createModule() },
.{ .name = "c", .module = c.mod },
},
}),
});
exe.root_module.linkSystemLibrary("c", .{});
```

`src/c.h` 中放需要翻译的 C 头文件:
Expand All @@ -74,13 +89,13 @@ exe.root_module.linkSystemLibrary("c", .{});

::: info 🅿️ 提示

注意:为了构建这个,我们需要引入 `libc`。在 Zig 0.16 的构建脚本中,可以让对应模块链接 C 标准库,例如 `exe.root_module.linkSystemLibrary("c", .{})`。
注意:为了构建这个,我们需要引入 `libc`。translate-c 包的 `Translator` 默认会让翻译出的模块链接 libc(`link_libc = true`);如果使用内置的 `addTranslateC`,则需要手动让对应模块链接 C 标准库,例如 `exe.root_module.linkSystemLibrary("c", .{})`。

因此通常通过 `zig build` 驱动这个例子;旧的 `@cImport` 单文件代码才适合手动 `zig build-exe source.zig -lc`。
构建系统内置的 `b.addTranslateC` 在 0.17 中仍然可用,但已被标记为 deprecated。本教程仓库的根构建脚本为了保持零外部依赖,暂时仍使用它来构建这个例子。

:::

`@cImport` 仍然保留,但在 Zig 0.16 已进入 deprecated 迁移期;它只适合维护旧的单文件示例或历史代码。新代码不要再把它作为 C 头文件入口,应优先使用上面的 `build.zig` + `@import("c")` 路径。
如果你还在维护使用 `@cImport` 的旧代码,可以参考 [0.17.0 升级指南](../update/upgrade-0.17.0#c-翻译迁移到独立的-translate-c-包) 进行迁移。

## vcpkg C Lib 导入

Expand All @@ -95,9 +110,13 @@ exe.root_module.linkSystemLibrary("c", .{});

那么在 `build.zig` 文件中,

<<<@/code/release/import_vcpkg/build.zig#translate_c

并为可执行文件添加 lib 搜索目录与需要链接的库:

<<<@/code/release/import_vcpkg/build.zig#c_import

假设你想要借用 `gsl` 库来对数值进行傅里叶变换,Zig 0.16 新代码应沿用上面的 `addTranslateC` + `@import("c")` 路径。下面这个历史片段仍使用旧的 `@cImport`,仅用于说明要导入的 GSL 头文件,不作为新项目推荐写法:
假设你想要借用 `gsl` 库来对数值进行傅里叶变换,那么在 Zig 代码中直接导入上面翻译得到的 `gsl` 模块即可:

<<<@/code/release/import_vcpkg/src/main.zig#import_gsl

Expand Down Expand Up @@ -132,18 +151,16 @@ Zig 提供了一个命令行工具 `zig translate-c` 供我们使用,它可以

### 构建系统 `translate-c` 与命令行 `translate-c`

构建系统里的 `addTranslateC` 是 Zig 0.16 推荐的头文件导入路径;命令行 `zig translate-c` 更适合一次性查看或手动修改翻译后的代码,例如:将 `anytype` 修改为更加精确的类型、将 `[*c]T` 指针修改为 `[*]T` 或者 `*T` 来提高类型安全性、启动或者禁用某些运行时的安全性功能。
在构建系统中使用 translate-c 包(或已弃用的内置 `addTranslateC`)是 Zig 0.17 推荐的头文件导入路径;命令行 `zig translate-c` 更适合一次性查看或手动修改翻译后的代码,例如:将 `anytype` 修改为更加精确的类型、将 `[*c]T` 指针修改为 `[*]T` 或者 `*T` 来提高类型安全性、启动或者禁用某些运行时的安全性功能。

## C 翻译缓存

C 翻译功能(通过 `build.zig` 的 `addTranslateC` 或 `zig translate-c` 使用)与 Zig 缓存系统集成。使用相同源文件、目标和 `cflags` 的后续构建将使用缓存,而不是重复翻译相同的代码;构建缓存目录是项目下的 `.zig-cache`。
C 翻译功能(通过 `build.zig` 中的 translate-c 包、`addTranslateC` 或 `zig translate-c` 使用)与 Zig 缓存系统集成。使用相同源文件、目标和 `cflags` 的后续构建将使用缓存,而不是重复翻译相同的代码;构建缓存目录是项目下的 `.zig-cache`。

下面这个 Zig 文件片段是 `addTranslateC` 生成模块后的调用侧:
下面这个 Zig 文件片段是在构建脚本中生成名为 `c` 的模块后的调用侧:

<<<@/code/release/interact_with_c.zig#cTranslate

如果你还在维护旧的 `@cImport` 代码,`--verbose-cimport` 可以临时用于查看旧导入缓存位置,便于迁移或排查。

## C 翻译错误

针对某些 C 的结构,zig 会无法翻译,如:`goto`、使用位域(**bitfields**)的结构体、拼接(**token-pasting**)宏,zig 会暂时简单处理一下它们以继续翻译任务。
Expand Down
Loading
Loading