Zig 安装与使用指南
Zig 既是一门系统编程语言,也是一套非常实用的 C/C++ 工具链。对嵌入式和 Linux 开发者来说,它有两个很直接的价值:
- 可以直接把
zig cc、zig c++当作gcc、g++使用 - 对交叉编译支持很好,很多场景下比手工维护交叉工具链更省事
本文按“安装、环境配置、常用命令、交叉编译、工程构建”的顺序整理,适合拿来直接落地。
1. Zig 是什么
先明确一点,Zig 不只是“一门新语言”。
它至少有两种常见用法:
- 把 Zig 当作编程语言使用,编写系统工具、命令行程序或底层模块。
- 把 Zig 当作 C/C++ 编译工具链使用,用
zig cc、zig c++来编译已有工程。
如果你当前主要做嵌入式软件、Linux 应用或服务端程序,第二种用法通常更容易快速产生价值。
2. Linux 下安装 Zig
最稳妥的方式是从 Zig 官方发布包安装,而不是依赖系统仓库里的旧版本。
2.1 下载并解压
下面以 Linux x86_64 平台为例。实际使用时,把文件名替换成你下载的 Zig 版本即可。
wget https://ziglang.org/download/<version>/zig-linux-x86_64-<version>.tar.xz
tar -xf zig-linux-x86_64-<version>.tar.xz
sudo mv zig-linux-x86_64-<version> /opt/zig
如果你下载的是开发版构建包,目录名通常会更长,处理方式相同。
2.2 配置环境变量
echo 'export PATH="/opt/zig:$PATH"' >> ~/.bashrc
source ~/.bashrc
如果你使用的是 zsh,则改写到 ~/.zshrc。
2.3 验证安装
zig version
zig env
zig version用于确认 Zig 已经可执行zig env用于查看 Zig 当前使用的缓存目录、目标平台信息和工具链配置
3. 第一次上手:最常用的几个命令
如果你以前主要使用 GCC/CMake,可以先记住下面几条命令。
3.1 创建一个 Zig 工程
zig init
这会生成一个最小工程骨架,通常包含:
build.zigbuild.zig.zonsrc/main.zig
3.2 编译、运行、测试
zig build
zig build run
zig test src/main.zig
常见理解如下:
zig build:按build.zig描述构建工程zig build run:构建并运行默认可执行文件zig test:编译并执行测试代码
3.3 直接编译单文件
如果只是临时写一个小工具,不一定要先建工程。
zig build-exe hello.zig
./hello
也可以直接运行:
zig run hello.zig
4. 把 Zig 当作 C/C++ 编译器使用
这部分往往是 Zig 最先带来收益的地方。
4.1 基本编译
zig cc 对应 gcc,zig c++ 对应 g++。
zig cc main.c -o main
zig c++ main.cpp -o main
如果你已有 C/C++ 项目,可以先从这里替换编译器开始,而不必立即引入 Zig 语言代码。
4.2 常见编译选项
zig cc -O2 main.c -o main
zig cc -g main.c -o main
zig cc -Wall -Wextra main.c -o main
这些用法和 GCC 基本一致,迁移成本很低。
4.3 使用 Zig 做交叉编译
Zig 的一个强项是交叉编译。目标平台通过 -target 指定,格式通常为:
架构-操作系统-ABI
例如:
# 编译为 x86_64 Linux 程序
zig cc -target x86_64-linux-gnu main.c -o main
# 编译为 ARM Linux 硬浮点程序
zig cc -target arm-linux-gnueabihf main.c -o main
# 编译为 aarch64 Linux 程序
zig cc -target aarch64-linux-gnu main.c -o main
# 编译为 Windows 可执行文件
zig cc -target x86_64-windows-gnu main.c -o main.exe
如果你的目标设备比较老,还可以显式指定 glibc 版本:
zig cc -target x86_64-linux-gnu.2.27 main.c -o main
这对“开发机系统较新,目标机系统较旧”的部署场景很有帮助。
4.4 静态链接 musl
如果希望可执行文件尽量摆脱目标机运行库依赖,可以考虑使用 musl 目标:
zig cc -target x86_64-linux-musl main.c -o main_static
这个方式常见于:
- 小型部署环境
- 容器镜像精简
- 嵌入式 Linux 设备分发
但要注意,静态链接不是所有项目都适合,尤其是涉及插件、运行时加载或某些系统库依赖时,需要单独评估。
5. 在现有 CMake 工程里使用 Zig
如果项目已经使用 CMake,通常不需要立刻重写构建系统。更现实的做法是先让 Zig 接管编译器。
mkdir -p build
cd build
CC="zig cc -target aarch64-linux-gnu" \
CXX="zig c++ -target aarch64-linux-gnu" \
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . -j4
这个方式适合:
- 已有大型 C/C++ 工程
- 先验证 Zig 交叉编译是否稳定
- 不想马上替换掉原有 CMake 流程
如果你修改过编译器配置,建议清理旧缓存后再重新生成:
rm -rf build
mkdir build
cd build
6. Zig 语言最小示例
如果你想顺手试一下 Zig 语法,可以先看一个最小程序。
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, Zig!\n", .{});
}
编译并运行:
zig run hello.zig
这段代码里有几个 Zig 的典型特征:
const默认不可变!void表示函数可能返回错误try用于向上传递错误
7. Zig 的内存管理特点
Zig 的一个重要设计点是:内存分配尽量显式化,不鼓励隐藏分配。
下面是一个带注释的简单示例:
const std = @import("std");
pub fn main() !void {
// 通用分配器,适合学习和一般开发阶段使用。
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// 显式申请 128 字节缓冲区。
const buf = try allocator.alloc(u8, 128);
defer allocator.free(buf);
// 对缓冲区进行写入。
@memset(buf, 0);
const stdout = std.io.getStdOut().writer();
try stdout.print("buffer size = {}\n", .{buf.len});
}
这类“显式分配、显式释放”的风格,对嵌入式和高性能系统会更友好,因为资源边界更清晰。
8. Zig 调用 C 代码
Zig 与 C 的互操作性很好,这也是它适合作为工程过渡语言的原因之一。
const c = @cImport({
@cInclude("stdio.h");
});
pub fn main() void {
_ = c.printf("Hello from C API\n");
}
如果工程里已经有很多 C 头文件和库,这种方式可以帮助你逐步迁移,而不必一次性重写整个项目。
9. 最小 build.zig 示例
如果你不想继续使用 CMake,也可以直接使用 Zig 自带构建系统。
下面是一个最小的 build.zig 示例:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "my_app",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
}
然后执行:
zig build
zig build run
如果项目是 C 工程,也可以在 build.zig 中加入 C 源文件:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "my_c_app",
.target = target,
.optimize = optimize,
});
exe.addCSourceFile(.{
.file = b.path("src/main.c"),
.flags = &.{"-std=c11"},
});
exe.linkLibC();
b.installArtifact(exe);
}

Comments NOTHING