Building Zig projects that depend on C code may seem complex. However, Zig tries to make that process as painless as possible. In this article, we will build a Zig library wrapper to help you better understand the Zig build system.
To showcase the process, we will build a wrapper around https://github.com/tidwall/btree.c .
btree.c
is a B-tree implementation in C. The lib has no dependencies, so the build for it will be straightforward.
First, we need to fetch the btree.c
as a dependency. We could use git submodules, however, zig’s package manager Zon can conveniently manage dependency for us.
To add btree_c
as a dependency run:
zig fetch --save https://github.com/tidwall/btree.c/archive/v0.6.1.tar.gz`
.{
.name = "btree-zig",
.version = "0.0.1",
.dependencies = .{
.btree_c = .{
.url = "https://github.com/tidwall/btree.c/archive/v0.6.1.tar.gz",
.hash = "122032a19f309225db04415bcecfa87c95d3110b1d90d1223a613f3302a2a46e7f6f"
}
},
.paths = .{
"",
},
}
After we fetch our dependency, we can utilize it in our build.
Building btree-zig
Now, let’s focus on building our Zig wrapper. We call it btree-zig
.
Since it’s a library, we will not have any executables. Instead, we will define btree-zig
as a static library.
const btree_zig = b.addStaticLibrary(.{
.name = "btree-zig",
.root_source_file = .{ .path = "src/btree.zig" },
.target = target,
.optimize = optimize,
});
Then we need to add our dependency btree_c
const dep_btree_c = b.dependency("btree_c", .{
.target = target,
.optimize = optimize,
});
The code above will create a new dependency in the build graph, which we will use to link with our static lib (btree-zig
).
Our build process involves building btree_c
, so we need to add source files and headers.
btree_zig.addCSourceFiles(.{
.dependency = dep_btree_c,
.files = &.{"btree.c"},
});
btree_zig.installHeadersDirectoryOptions(.{
.source_dir = dep_btree_c.path(""),
.install_dir = .header,
.install_subdir = "",
.include_extensions = &.{"btree.h"},
});
And finally we can build the btree-zig
btree_zig.linkLibC();
b.installArtifact(btree_zig);
In the zig-out
folder, you should have the include
folder with the headers for btree_c
and the lib
folder with the libbtree-zig.a
.
Exporting btree-zig as a module
To export btree-zig
, we need to take some additional steps.
First, create a new module and add it to the build.
const module = b.addModule("btree_c_zig", .{
.root_source_file = .{ .path = "src/btree.zig" },
});
We also need to expose header files from btree_c
, as a part of the module to avoid consumers dealing with missing headers.
// Include header files from btree.c lib
module.addIncludePath(dep_btree_c.path(""));
Using btree-zig
The consumers can now import btree-zig
into their projects.
.dependencies = .{
.@"btree-zig" = .{
.url = "https://github.com/almmiko/btree.c-zig/archive/<git-ref>.tar.gz",
.hash = "1220450bb9feb21c29018e21a8af457859eb2a4607a6017748bb618907b4cf18c67b",
},
},
And adding it as a dependency at build.zig
.
const btree_zig = b.dependency("btree-zig", .{
.target = target,
.optimize = optimize,
});
const btree_zig_module = btree_zig.module("btree_c_zig");
exe.root_module.addImport("btree-zig", btree_zig_module);
exe.linkLibrary(btree_zig.artifact("btree-zig"));
Wrapping up
Zig’s build system is powerful and can be effectively used to build complex projects.
In this article, we briefly see it in action to learn how to use Zig to build a wrapper for C libraries.
The source code for btree-zig
you can find on the github https://github.com/almmiko/btree.c-zig