Skip to content
zig 版本:0.12.0

包管理

随着 0.11 的发布,zig 终于迎来了一个正式的官方包管理器,此前已知是通过第三方包管理器下载并处理包。

zig 当前并没有一个中心化存储库,包可以来自任何来源,无论是本地还是网络上。

当前的包管理模式为,先在 build.zig.zon 添加包的元信息,然后在 build.zig 中引入包。

新的文件结构

build.zig.zon 这个文件存储了包的信息,它是 zig 新引入的一种简单数据交换格式,使用了 zig 的匿名结构和数组初始化语法。

zig
.{
    // 包名字
    .name = "package_management",
    // 包的版本
    .version = "0.0.0",
    // 包的依赖
    .dependencies = .{
        // 包依赖项的名字
        .@"zig-msgpack" = .{
            // url 为包的下载地址
            .url = "https://github.com/zigcc/zig-msgpack/archive/refs/tags/0.0.4.tar.gz",
            // hash 为包的哈希值,但不是对整个包的哈希值,而是对包中的所有文件的哈希值
            .hash = "12204ec362b0784a04825021b1bab2fe62d062db5f07052207363a835af7613bb12e",
        },
    },
    // 包包含的源文件,一般用于在对外提供包时才使用
    .paths = .{
        "",
    },
}

以上字段含义为:

  • name:当前你所开发的包的名字
  • version:包的版本,使用 Semantic Version
  • dependencies:依赖项,内部是一连串的匿名结构体,字段 dep_name 是依赖包的名字,url 是源代码地址,hash 是对应的 hash(源文件内容的 hash)。
  • paths:显式声明包含的源文件,包含所有则指定为空。

🅿️ 提示

小技巧:如何直接使用指定分支的源码?

如果代码托管平台提供分支源码打包直接返回功能,就支持,例如 github 的源码分支打包返回的 url 格式为:

https://github.com/username/repo-name/archive/branch.tar.gz

其中的 username 就是组织名或者用户名,repo-name 就是对应的仓库名,branch 就是分支名。

例如 https://github.com/limine-bootloader/limine-zig/archive/trunk.tar.gz 就是获取 limine-zig 这个包的主分支源码打包。

🅿️ 提示

目前 zig 已支持通过 zig fetch 来获取 hash 并写入到 .zon 中!

编写包

🅿️ 提示

zig 支持在一个 build.zig 中对外暴露出多个模块,也就是说一个包本身可以包含多个模块,并且 libexecutable 两种是完全可以共存的!

如何将模块对外暴露呢?

可以使用 build 函数传入的参数 b: *std.Build,它包含一个方法 addModule, 它的原型如下:

zig
pub fn addModule(b: *Build, name: []const u8, options: Module.CreateOptions) *Module

使用起来也很简单,例如:

zig
const lib_module = b.addModule("package", .{
    .root_source_file = b.path("src/root.zig"),
});
_ = lib_module;

这就是一个最基本的包暴露实现,指定了包名和包的入口源文件地址(b.path 是相对当前项目路径取 Path),通过 addModule 函数暴露的模块是完全公开的。

🅿️ 提示

如果需要使用私有的模块,请使用 std.Build.createModule,使用方式和 addModule 同理。

关于二进制构建结果(例如动态链接库和静态链接库),任何被执行 install 操作的构建结果均会被暴露出去(即引入该包的项目均可看到该包的构建结果,但需要手动 link )。

引入包

可以使用 build 函数传入的参数 b: *std.Build,它包含一个方法 dependency, 它的原型如下:

zig
fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency

其中 name 是在在 .zon 中的包名字,它返回一个 *std.Build.Dependency,可以使用 artifactmodule 方法来访问包的链接库和暴露的 module

zig
// 标准的构建 exe 过程
const exe = b.addExecutable(.{
    .name = "package_management",
    .root_source_file = b.path("src/main.zig"),
    .target = target,
    .optimize = optimize,
});

// 通过 dependency 函数获取到依赖
const msgpack = b.dependency("zig-msgpack", .{
    .target = target,
    .optimize = optimize,
});

// 将 module 添加到 exe 的 root module 中
exe.root_module.addImport("msgpack", msgpack.module("msgpack"));

🅿️ 提示

dependency 包含一个额外的参数 args,这是传给对应的包构建的参数(类似在命令行构建时使用的 -D 参数,通常是我们使用 b.options 获取,通过 std.Build.option 实现),当前包的参数并不会向包传递,需要手动显式指定转发。

TODO:更多示例说明