Zig 构建系统实用入门
2025 年 5 月 2 日
Zig 的构建系统一开始可能看起来有点陌生,但它其实是 Zig 最强大的特性之一。通过把 Zig 本身作为配置语言,build.zig 让你可以用完整的程序化方式控制编译、链接、测试等流程,而不需要额外工具或专用 DSL。
第 1 步:什么是 build.zig?
任何包含多个文件或自定义构建步骤的 Zig 项目,都会使用 build.zig 脚本。这个脚本使用 Zig 的 std.Build API 来定义应用应该如何构建。
第 2 步:最小 build.zig 示例
下面是一个用于 Zig 可执行程序的简单构建脚本:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const mode = b.standardReleaseOptions();
const exe = b.addExecutable(.{
.name = "hello",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = mode,
});
b.installArtifact(exe);
}
这段代码为 src/main.zig 定义了构建配置,并包含目标平台和优化模式等选项。
第 3 步:添加库
如果你想构建静态库或动态库,而不是可执行文件,可以这样写:
const lib = b.addStaticLibrary(.{
.name = "mylib",
.root_source_file = .{ .path = "src/lib.zig" },
.target = target,
.optimize = mode,
});
然后可以把这个库链接到可执行文件:
exe.linkLibrary(lib);
第 4 步:添加测试
你也可以直接在构建系统中定义并运行测试:
const tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = mode,
});
b.installArtifact(tests);
然后运行:
zig build test
第 5 步:自定义步骤
可以使用 b.step() 把任意逻辑注入构建流水线:
const my_step = b.step("message", "Print a message");
my_step.makeFn = fn (step: *std.Build.Step, _: *std.Progress) anyerror!void {
std.debug.print("Custom step executed!\n", .{});
return;
};
使用下面的命令运行:
zig build message
build.zig 的优缺点
优点
- 使用 Zig 编写,不需要额外构建语言。
- 拥有完整的程序化控制能力。
- 很容易集成测试、库和自定义步骤。
- 内置交叉编译和 release 模式。
缺点
- 学习曲线比
make或cargo更陡。 - 高级特性的文档相对有限。
- 对非常小的脚本来说可能有些过重。
总结
一旦熟悉了 build.zig,你会在每个新的 Zig 项目中自然地使用它的灵活性。无论你是在构建命令行工具、跨平台库,还是复杂的多阶段程序,Zig 的构建系统都能给你明确的控制能力,而不是隐藏在魔法背后。