Zig-rocksdb 支持靜態鏈接以及示例介紹

得益於 Zig 與 C 的無縫交互加上構建系統的逐漸完善,我們可以相對教簡單的將一個 C 項目包裝成一個 Zig 綁定庫。以下是 zig-rocksdb[1] 支持靜態鏈接 librocksdb 的構建方式:

fn buildStaticRocksdb(
    b: *std.Build,
    target: std.Build.ResolvedTarget,
    optimize: std.builtin.OptimizeMode,
    strip_lib: bool,
) !?*Step.Compile {
    const is_darwin = target.result.isDarwin();
    const is_linux = target.result.os.tag == .linux;
    const rocksdb_dep = b.lazyDependency("rocksdb", .{
        .target = target,
        .optimize = optimize,
    }) orelse return null;
    const lib = b.addStaticLibrary(.{
        .name = "rocksdb",
        .target = target,
        .optimize = optimize,
        .link_libc = true,
        .strip = if (strip_lib) true else false,
    });
    lib.root_module.sanitize_c = false;
    if (optimize != .Debug) {
        lib.defineCMacro("NDEBUG", "1");
    }
    lib.defineCMacro("ROCKSDB_PLATFORM_POSIX", null);
    lib.defineCMacro("ROCKSDB_LIB_IO_POSIX", null);
    lib.defineCMacro("ROCKSDB_SUPPORT_THREAD_LOCAL", null);
    if (is_darwin) {
        lib.defineCMacro("OS_MACOSX", null);
    } else if (is_linux) {
        lib.defineCMacro("OS_LINUX", null);
    }
    lib.linkLibCpp();
    lib.addIncludePath(rocksdb_dep.path("include"));
    lib.addIncludePath(rocksdb_dep.path("."));
    const cflags = &.{
        "-std=c++17",
        "-Wsign-compare",
        "-Wshadow",
        "-Wno-unused-parameter",
        "-Wno-unused-variable",
        "-Woverloaded-virtual",
        "-Wnon-virtual-dtor",
        "-Wno-missing-field-initializers",
        "-Wno-strict-aliasing",
        "-Wno-invalid-offsetof",
    };
    const src_file = b.path("sys/rocksdb_lib_sources.txt").getPath2(b, null);
    var f = try std.fs.openFileAbsolute(src_file, .{});
    const body = try f.readToEndAlloc(b.allocator, 1024_1000);
    var it = std.mem.splitScalar(u8, body, '\n');
    while (it.next()) |src| {
        // We have a pre-generated a version of build_version.cc in the local directory
        if (std.mem.eql(u8, "util/build_version.cc", src) or src.len == 0) {
            continue;
        }
        lib.addCSourceFile(.{
            .file = rocksdb_dep.path(src),
            .flags = cflags,
        });
    }
    lib.addCSourceFile(.{
        .file = b.path("sys/build_version.cc"),
        .flags = cflags,
    });
    b.installArtifact(lib);
    lib.installHeadersDirectory(rocksdb_dep.path("include/rocksdb"), "rocksdb", .{});
    return lib;
}

核心幾點:

  1. 通過 lazyDependency 進行惰性加載 rocksdb 源碼

  2. defineCMacro 定義 librocksdb 中需要用的到宏

  3. 找到所需 C 文件,調用 addCSourceFile 添加到靜態 lib 中,對於 rocksdb 還比較簡單,就是在 src.mk[2] 中,其他的 C 項目獲取可能要複雜一些

  4. 最後調用 installHeadersDirectory 將相關頭文件放知道構建產物中,這樣上層 module 就可以直接 cImport 的頭文件,不需要在指定 includePath

使用也很簡單,首先下載:

zig fetch --save=rocksdb https://github.com/jiacai2050/zig-rocksdb/archive/refs/tags/v0.1.0.zip

之後在 build.zig 中的 exe 引用即可

const dep_rocksdb = b.dependency("rocksdb", .{});
exe.root_module.addImport("rocksdb", dep_rocksdb.module("rocksdb"));
exe.linkLibC();

這是進行讀寫的示例代碼:

const std = @import("std");
const rocksdb = @import("rocksdb");
pub fn main() !void {
    const allocator = std.heap.page_allocator;
    var db = try rocksdb.Database(.Single).open(
        allocator,
        "/tmp/zig-rocksdb-basic",
        .{
            .create_if_missing = true,
        },
    );
    defer db.deinit();
    const key = "hello";
    try db.put(key, "world", .{});
    const value = try db.get(key, .{});
    if (value) |v| {
        defer rocksdb.free(v);
        std.debug.print("{s} = {s}\n", .{ key, v });
    }
}

參考資料

[1] 

zig-rocksdb: https://github.com/jiacai2050/zig-rocksdb/

[2] 

src.mk: https://github.com/jiacai2050/rocksdb/blob/9ad772e652bb3172ed8821ebacf40757bfbb7da1/src.mk#L2

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/CJovB-KcLyl-brwHAjmvqA