Zig 构建系统完全教程
1. 何时使用 Zig 构建系统?
Section titled “1. 何时使用 Zig 构建系统?”1.1 适用场景
Section titled “1.1 适用场景”Zig 构建系统在以下场景特别有用:
// 场景1: 命令行过长// zig build-exe src/main.zig -O ReleaseSafe -target x86_64-windows --library c --library m
// 场景2: 多步骤构建// 编译、测试、打包、部署
// 场景3: 需要并发和缓存// 加速大型项目构建
// 场景4: 项目配置选项// 用户可自定义构建参数
// 场景5: 跨平台差异// 不同平台需要不同构建逻辑
// 场景6: 项目依赖// 管理多个依赖项
// 场景7: 避免外部依赖// 不需要 CMake、Make、Shell 等
// 场景8: 提供包给第三方使用// 创建可重用的库
// 场景9: IDE 集成// 为 IDE 提供标准化的构建方式2. 基础构建配置
Section titled “2. 基础构建配置”2.1 简单可执行文件
Section titled “2.1 简单可执行文件”项目结构:
myapp/├── build.zig└── src/ └── main.zigsrc/main.zig:
const std = @import("std");
pub fn main() void { std.debug.print("Hello World!\n", .{});}build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void { // 创建可执行文件 const exe = b.addExecutable(.{ .name = "myapp", // 可执行文件名 .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, // 使用主机目标 }), });
// 安装到默认位置 b.installArtifact(exe);}构建:
# 构建并安装zig build
# 查看输出tree zig-out/# zig-out/# └── bin# └── myapp2.2 添加运行步骤
Section titled “2.2 添加运行步骤”const std = @import("std");
pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
b.installArtifact(exe);
// 创建运行命令 const run_cmd = b.addRunArtifact(exe);
// 传递用户参数 if (b.args) |args| { run_cmd.addArgs(args); }
// 创建运行步骤 const run_step = b.step("run", "运行程序"); run_step.dependOn(&run_cmd.step);}使用:
# 运行程序zig build run
# 带参数运行zig build run -- arg1 arg2
# 查看所有可用步骤zig build --help3. 构建选项配置
Section titled “3. 构建选项配置”3.1 用户选项
Section titled “3.1 用户选项”const std = @import("std");
pub fn build(b: *std.Build) void { // 定义用户选项 const enable_logging = b.option( bool, "enable_logging", "启用日志记录" ) orelse false;
const log_level = b.option( []const u8, "log_level", "日志级别 (debug, info, warn, error)" ) orelse "info";
const max_threads = b.option( u32, "max_threads", "最大线程数" ) orelse 4;
const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
// 传递选项到代码 exe.root_module.addCompileOption("ENABLE_LOGGING", enable_logging); exe.root_module.addCompileOption("LOG_LEVEL", log_level); exe.root_module.addCompileOption("MAX_THREADS", max_threads);
b.installArtifact(exe);}使用选项:
# 查看项目特定选项zig build --help# 输出包含:# Project-Specific Options:# -Denable_logging=[bool] 启用日志记录# -Dlog_level=[string] 日志级别# -Dmax_threads=[integer] 最大线程数
# 使用选项构建zig build -Denable_logging=true -Dlog_level=debug -Dmax_threads=83.2 标准配置选项
Section titled “3.2 标准配置选项”const std = @import("std");
pub fn build(b: *std.Build) void { // 标准目标选项 const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu, }, .supported_wasm_versions = .{ .v1 = true }, });
// 标准优化选项 const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseSafe, });
const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }), });
b.installArtifact(exe);}跨平台构建:
# 构建 Windows 程序zig build -Dtarget=x86_64-windows -Doptimize=ReleaseSmall
# 构建 Linux 程序zig build -Dtarget=x86_64-linux-gnu -Doptimize=ReleaseFast
# 构建 WebAssemblyzig build -Dtarget=wasm32-wasi -Doptimize=ReleaseSafe3.3 条件编译选项
Section titled “3.3 条件编译选项”const std = @import("std");
pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
// 创建选项模块 const options = b.addOptions(); options.addOption([]const u8, "version", b.option([]const u8, "version", "版本号") orelse "0.1.0"); options.addOption(bool, "enable_feature_x", b.option(bool, "enable_feature_x", "启用特性X") orelse false); options.addOption(u32, "buffer_size", b.option(u32, "buffer_size", "缓冲区大小") orelse 1024);
// 添加到模块 exe.root_module.addOptions("config", options);
b.installArtifact(exe);}代码中使用:
const std = @import("std");const config = @import("config");
pub fn main() void { std.debug.print("版本: {s}\n", .{config.version});
if (config.enable_feature_x) { std.debug.print("特性X已启用\n", .{}); }
const buffer = std.heap.page_allocator.alloc(u8, config.buffer_size) catch unreachable; defer std.heap.page_allocator.free(buffer);}4. 库的构建
Section titled “4. 库的构建”4.1 静态库
Section titled “4.1 静态库”lib/math.zig:
export fn add(a: i32, b: i32) i32 { return a + b;}
export fn multiply(a: i32, b: i32) i32 { return a * b;}build.zig (静态库):
const std = @import("std");
pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{});
// 创建静态库 const lib = b.addStaticLibrary(.{ .name = "mymath", .root_module = b.createModule(.{ .root_source_file = b.path("lib/math.zig"), .target = target, .optimize = optimize, }), });
b.installArtifact(lib);
// 可选的演示程序 const enable_demo = b.option(bool, "enable_demo", "构建演示程序") orelse false;
if (enable_demo) { const demo = b.addExecutable(.{ .name = "demo", .root_module = b.createModule(.{ .root_source_file = b.path("examples/demo.zig"), .target = target, .optimize = optimize, }), });
demo.linkLibrary(lib); // 链接静态库 b.installArtifact(demo); }}4.2 动态库
Section titled “4.2 动态库”build.zig (动态库):
const std = @import("std");
pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{});
// 创建动态库 const lib = b.addDynamicLibrary(.{ .name = "mymath", .root_module = b.createModule(.{ .root_source_file = b.path("lib/math.zig"), .target = target, .optimize = optimize, }), .version = .{ .major = 1, .minor = 0, .patch = 0, }, });
b.installArtifact(lib);}输出结构:
zig-out/lib/├── libmymath.so -> libmymath.so.1├── libmymath.so.1 -> libmymath.so.1.0.0└── libmymath.so.1.0.05. 测试配置
Section titled “5. 测试配置”5.1 单元测试
Section titled “5.1 单元测试”tests/math_test.zig:
const std = @import("std");const math = @import("../src/math.zig");
test "测试加法" { try std.testing.expect(math.add(2, 3) == 5); try std.testing.expect(math.add(-1, 1) == 0);}
test "测试乘法" { try std.testing.expect(math.multiply(4, 5) == 20); try std.testing.expect(math.multiply(0, 100) == 0);}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 = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }), });
b.installArtifact(exe);
// 单元测试 const unit_tests = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("src/math.zig"), .target = target, .optimize = optimize, }), .kind = .test, });
const run_unit_tests = b.addRunArtifact(unit_tests);
// 跳过跨平台检查 run_unit_tests.skip_foreign_checks = true;
const test_step = b.step("test", "运行单元测试"); test_step.dependOn(&run_unit_tests.step);
// 跨平台测试 const cross_test_targets = [_]std.Target.Query{ .{}, // 本机 .{ .cpu_arch = .x86_64, .os_tag = .linux }, .{ .cpu_arch = .aarch64, .os_tag = .macos }, .{ .cpu_arch = .wasm32, .os_tag = .wasi }, };
const cross_test_step = b.step("test-cross", "运行跨平台测试");
for (cross_test_targets) |t| { const cross_test = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("src/math.zig"), .target = b.resolveTargetQuery(t), .optimize = optimize, }), .kind = .test, });
const run_cross_test = b.addRunArtifact(cross_test); run_cross_test.skip_foreign_checks = true;
cross_test_step.dependOn(&run_cross_test.step); }}6. 链接系统库
Section titled “6. 链接系统库”const std = @import("std");
pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
// 链接系统库 exe.linkSystemLibrary("z"); // zlib exe.linkSystemLibrary("ssl"); // OpenSSL exe.linkSystemLibrary("crypto"); exe.linkLibC(); // C标准库
// 条件链接 const use_sdl = b.option(bool, "use_sdl", "使用SDL2") orelse false; if (use_sdl) { exe.linkSystemLibrary("SDL2"); }
b.installArtifact(exe);}使用系统路径:
# 添加搜索路径zig build --search-prefix /usr/local
# 设置系统根目录zig build --sysroot /path/to/sysroot7. 文件生成和工具
Section titled “7. 文件生成和工具”7.1 运行系统工具
Section titled “7.1 运行系统工具”const std = @import("std");
pub fn build(b: *std.Build) void { // 生成配置文件 const generate_config = b.addSystemCommand(&.{"sh", "-c"}); generate_config.addArgs(&.{ "echo '{\"version\": \"1.0\", \"timestamp\": \"", }); generate_config.addArg(@embedFile("timestamp")); generate_config.addArgs(&.{"\"}' > config.json"});
const config_output = generate_config.captureStdOut();
// 安装生成的文件 b.getInstallStep().dependOn( &b.addInstallFileWithDir(config_output, .prefix, "config.json").step );
const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
b.installArtifact(exe);}7.2 运行项目工具
Section titled “7.2 运行项目工具”tools/generate_data.zig:
const std = @import("std");
pub fn main() !void { const args = try std.process.argsAlloc(std.heap.page_allocator); if (args.len != 3) { std.debug.print("用法: generate_data <输入> <输出>\n", .{}); std.process.exit(1); }
const input = args[1]; const output = args[2];
// 读取输入文件 const data = try std.fs.cwd().readFileAlloc( std.heap.page_allocator, input, 1024 * 1024 ); defer std.heap.page_allocator.free(data);
// 处理数据 const processed = try processData(data);
// 写入输出文件 try std.fs.cwd().writeFile(output, processed);}
fn processData(input: []const u8) ![]const u8 { // 数据处理逻辑 return input;}build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void { // 构建工具 const tool = b.addExecutable(.{ .name = "generate_data", .root_module = b.createModule(.{ .root_source_file = b.path("tools/generate_data.zig"), .target = b.graph.host, }), });
// 运行工具 const run_tool = b.addRunArtifact(tool); run_tool.addArg("--input"); run_tool.addFileArg(b.path("data/input.txt")); run_tool.addArg("--output"); const output = run_tool.addOutputFileArg("processed_data.bin");
// 安装生成的文件 b.getInstallStep().dependOn( &b.addInstallFileWithDir(output, .prefix, "data.bin").step );
// 主程序 const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
b.installArtifact(exe);}7.3 生成用于 @embedFile 的资源
Section titled “7.3 生成用于 @embedFile 的资源”const std = @import("std");
pub fn build(b: *std.Build) void { // 资源生成工具 const resource_tool = b.addExecutable(.{ .name = "resource_gen", .root_module = b.createModule(.{ .root_source_file = b.path("tools/resource_gen.zig"), .target = b.graph.host, }), });
// 运行工具生成资源 const run_resource = b.addRunArtifact(resource_tool); const resource_file = run_resource.addOutputFileArg("resources.bin");
// 主程序 const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
// 将生成的文件作为模块导入 exe.root_module.addAnonymousImport("resources", .{ .root_source_file = resource_file, });
b.installArtifact(exe);}代码中使用:
const std = @import("std");const resources = @import("resources");
pub fn main() void { const data: []const u8 = @embedFile("resources"); std.debug.print("资源大小: {}字节\n", .{data.len});}7.4 生成 Zig 源代码
Section titled “7.4 生成 Zig 源代码”tools/generate_code.zig:
const std = @import("std");
pub fn main() !void { const args = try std.process.argsAlloc(std.heap.page_allocator); const output = args[1];
var file = try std.fs.cwd().createFile(output, .{}); defer file.close();
try file.writer().print( \\// 自动生成的代码 \\pub const Version = struct {{ \\ major: u32 = {d}, \\ minor: u32 = {d}, \\ patch: u32 = {d}, \\}}; \\ \\pub const Features = struct {{ \\ has_network: bool = {s}, \\ has_graphics: bool = {s}, \\ max_users: u32 = {d}, \\}}; , .{1, 0, 0, "true", "false", 100});}build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void { // 代码生成工具 const codegen = b.addExecutable(.{ .name = "codegen", .root_module = b.createModule(.{ .root_source_file = b.path("tools/generate_code.zig"), .target = b.graph.host, }), });
// 运行工具 const run_codegen = b.addRunArtifact(codegen); const generated_code = run_codegen.addOutputFileArg("generated.zig");
// 主程序 const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
// 导入生成的模块 exe.root_module.addAnonymousImport("generated", .{ .root_source_file = generated_code, });
b.installArtifact(exe);}8. 文件操作
Section titled “8. 文件操作”8.1 多个生成文件
Section titled “8.1 多个生成文件”const std = @import("std");
pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
// 创建写入文件步骤 const write_files = b.addWriteFiles();
// 写入多个文件 _ = write_files.add("version.txt", "1.0.0"); _ = write_files.add("config.json", "{\"debug\": true}"); _ = write_files.addCopyFile(exe.getEmittedBin(), "bin/myapp");
// 获取目录和文件 const files_dir = write_files.getDirectory(); const version_file = write_files.getPath("version.txt");
// 打包步骤 const tar = b.addSystemCommand(&.{ "tar", "czf" }); tar.setCwd(files_dir); const tar_file = tar.addOutputFileArg("package.tar.gz"); tar.addArg(".");
// 安装打包文件 b.getInstallStep().dependOn( &b.addInstallFileWithDir(tar_file, .prefix, "dist/package.tar.gz").step );}8.2 原地修改源文件
Section titled “8.2 原地修改源文件”const std = @import("std");
pub fn build(b: *std.Build) void { // 代码生成工具 const proto_gen = b.addExecutable(.{ .name = "proto_gen", .root_module = b.createModule(.{ .root_source_file = b.path("tools/proto_gen.zig"), .target = b.graph.host, }), });
// 运行工具生成代码 const run_gen = b.addRunArtifact(proto_gen); const generated_file = run_gen.addOutputFileArg("protocol.zig");
// 更新源文件 const update_source = b.addUpdateSourceFiles(); update_source.addCopyFileToSource(generated_file, "src/protocol.zig");
// 更新步骤 const update_step = b.step("update-protocol", "更新协议文件"); update_step.dependOn(&update_source.step);
// 主程序 const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.graph.host, }), });
b.installArtifact(exe);}9. 实用示例
Section titled “9. 实用示例”9.1 多目标发布构建
Section titled “9.1 多目标发布构建”const std = @import("std");
// 支持的目标平台const release_targets = [_]std.Target.Query{ .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu }, .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl }, .{ .cpu_arch = .x86_64, .os_tag = .windows }, .{ .cpu_arch = .aarch64, .os_tag = .macos }, .{ .cpu_arch = .wasm32, .os_tag = .wasi },};
pub fn build(b: *std.Build) !void { // 为每个目标构建 for (release_targets) |target_query| { const target = b.resolveTargetQuery(target_query); const triple = try target.zigTriple(b.allocator);
const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = .ReleaseSafe, }), });
// 安装到特定目录 const install_exe = b.addInstallArtifact(exe, .{ .dest_dir = .{ .override = .{ .custom = triple, }, }, });
b.getInstallStep().dependOn(&install_exe.step); }
// 创建打包步骤 const package_step = b.step("package", "创建发布包");
for (release_targets) |target_query| { const target = b.resolveTargetQuery(target_query); const triple = try target.zigTriple(b.allocator);
// 为每个平台创建压缩包 const tar = b.addSystemCommand(&.{ "tar", "czf" }); tar.addArg(b.fmt("myapp-{s}.tar.gz", .{triple})); tar.addArg(b.fmt("zig-out/{s}/", .{triple}));
package_step.dependOn(&tar.step); }}构建发布包:
# 构建所有目标zig build
# 创建发布包zig build package
# 输出:# myapp-x86_64-linux-gnu.tar.gz# myapp-x86_64-linux-musl.tar.gz# myapp-x86_64-windows.tar.gz# myapp-aarch64-macos.tar.gz# myapp-wasm32-wasi.tar.gz10. 高级特性
Section titled “10. 高级特性”10.1 自定义构建步骤
Section titled “10.1 自定义构建步骤”const std = @import("std");
pub fn build(b: *std.Build) void { // 文档生成步骤 const docs = b.addSystemCommand(&.{"zig", "build-lib"}); docs.addArgs(&.{ "--docs", "docs/", "--emit", "docs=docs.tar", "src/main.zig", });
const tar = b.addSystemCommand(&.{"tar", "xf"}); tar.addFileArg(docs.captureStdOut()); tar.setCwd(b.path("."));
const docs_step = b.step("docs", "生成文档"); docs_step.dependOn(&tar.step);
// 清理步骤 const clean = b.addSystemCommand(&.{"rm", "-rf"}); clean.addArg("zig-out"); clean.addArg(".zig-cache");
const clean_step = b.step("clean", "清理构建文件"); clean_step.dependOn(&clean.step);}10.2 性能优化
Section titled “10.2 性能优化”const std = @import("std");
pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }), });
// 优化选项 exe.root_module.sanitize_c = false; // 禁用C代码消毒 exe.root_module.sanitize_thread = false; // 禁用线程消毒 exe.root_module.red_zone = true; // 启用红区 exe.root_module.omit_frame_pointer = true; // 省略帧指针
// 链接时优化 exe.root_module.lto = switch (optimize) { .ReleaseFast, .ReleaseSafe => .thin, else => .none, };
// 单指令多数据优化 switch (target.result.cpu.arch) { .x86_64 => { exe.root_module.code_model = .medium; exe.root_module.mcpu = "x86-64-v3"; }, .aarch64 => { exe.root_module.mcpu = "apple-m1"; }, else => {}, }
b.installArtifact(exe);}11. 最佳实践总结
Section titled “11. 最佳实践总结”- 模块化构建: 将构建逻辑分解为可重用的函数
- 配置选项: 为用户提供灵活的配置选项
- 缓存友好: 避免破坏构建缓存的操作
- 错误处理: 提供清晰的错误信息和文档
- 跨平台支持: 考虑不同平台的差异
- 性能优化: 合理利用并行和缓存
- 工具集成: 支持 IDE 和其他工具
- 文档生成: 自动生成 API 文档
- 测试集成: 完善的测试框架支持
- 发布准备: 多目标构建和打包
通过 Zig 构建系统,你可以创建灵活、高效、跨平台的构建配置,满足从简单脚本到复杂项目的各种需求。