让 Zig 成为你的 C/C++ 编译系统

可移植性问题

  打开普通的 Makefile,你会发现大量的能力校验(brittle capability checks)会完全破坏任何形式的交叉编译尝试。实际上,在上一篇文章中,我们在研究 Redis 时已经看到了一个非常温和的版本,但情况可能会更糟。

  值得庆幸的是,Zig 的编译器中集成了一个编译系统,可以通过 zig build 子命令来实现。

为什么使用 Zig Build

无依赖性

  由于您已经使用了 Zig 编译器,因此您可以在所有支持的平台上构建您的项目,而无需依赖任何系统依赖性,甚至无需依赖构建必备项、Xcode 或 MSVC。

作为一等公民的交叉编译

  Zig 将能够从任何目标编译到任何目标视为其主要目标之一。使用 Zig build 可以更容易地集成 Zig 的交叉编译功能。

声明式但无特殊语法

  zig 联编子命令依赖于 build.zig 文件。联编系统使用声明式系统来描述联编流水线(对于联编运行程序的检测非常有用),但它使用普通的 Zig 语法。如果你懂 C 或 C++,就能轻松读懂 Zig 代码。

翻译 Makefile

  在我们继续之前,我必须提醒您:如果您不熟悉 C/C++ 生态系统,对某些构建系统进行逆向工程并非易事。

  例如,如果你想看看我和安德鲁如何将 Redis 的构建系统翻译成 Zig,请查看安德鲁 Vimeo 上的直播流。在视频中,你会发现安德鲁知道该怎么做,因为他在 C/C++ 领域工作了足够长的时间,知道所有的技巧。

了解 build.zig

  要进一步了解 Zig 构建系统使用的类型和约定,请参阅 @xq 的系列文章:zig build explained - part 1

完整的 build.zig

  这是一个完整的 build.zig 文件,可以将 redis-cli 和 redis-server 与它们各自的静态依赖关系一起打包。这里看不到的是 jemalloc 和 systemd 支持,留给读者自己练习。

  显示完整的 build.zig 文件

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const target = b.standardTargetOptions(.{});
    const mode = b.standardReleaseOptions();

    const hiredis = b.addStaticLibrary("hiredis", null);
    hiredis.setTarget(target);
    hiredis.setBuildMode(mode);
    hiredis.linkLibC();
    hiredis.force_pic = true;
    hiredis.addCSourceFiles(&.{
        "deps/hiredis/alloc.c",
        "deps/hiredis/async.c",
        "deps/hiredis/hiredis.c",
        "deps/hiredis/net.c",
        "deps/hiredis/read.c",
        "deps/hiredis/sds.c",
        "deps/hiredis/sockcompat.c",
    }, &.{
        "-Wall",
        "-W",
        "-Wstrict-prototypes",
        "-Wwrite-strings",
        "-Wno-missing-field-initializers",
    });

    const lua = b.addStaticLibrary("lua", null);
    lua.setTarget(target);
    lua.setBuildMode(mode);
    lua.linkLibC();
    lua.force_pic = true;
    lua.addCSourceFiles(&.{
        "deps/lua/src/fpconv.c",
        "deps/lua/src/lapi.c",
        "deps/lua/src/lauxlib.c",
        "deps/lua/src/lbaselib.c",
        "deps/lua/src/lcode.c",
        "deps/lua/src/ldblib.c",
        "deps/lua/src/ldebug.c",
        "deps/lua/src/ldo.c",
        "deps/lua/src/ldump.c",
        "deps/lua/src/lfunc.c",
        "deps/lua/src/lgc.c",
        "deps/lua/src/linit.c",
        "deps/lua/src/liolib.c",
        "deps/lua/src/llex.c",
        "deps/lua/src/lmathlib.c",
        "deps/lua/src/lmem.c",
        "deps/lua/src/loadlib.c",
        "deps/lua/src/lobject.c",
        "deps/lua/src/lopcodes.c",
        "deps/lua/src/loslib.c",
        "deps/lua/src/lparser.c",
        "deps/lua/src/lstate.c",
        "deps/lua/src/lstring.c",
        "deps/lua/src/lstrlib.c",
        "deps/lua/src/ltable.c",
        "deps/lua/src/ltablib.c",
        "deps/lua/src/ltm.c",
        "deps/lua/src/lua_bit.c",
        "deps/lua/src/lua_cjson.c",
        "deps/lua/src/lua_cmsgpack.c",
        "deps/lua/src/lua_struct.c",
        "deps/lua/src/lundump.c",
        "deps/lua/src/lvm.c",
        "deps/lua/src/lzio.c",
        "deps/lua/src/strbuf.c",
    }, &.{
        "-std=c99",
        "-Wall",
        "-DLUA_ANSI",
        "-DENABLE_CJSON_GLOBAL",
        "-DLUA_USE_MKSTEMP",
    });

    const redis_cli = b.addExecutable("redis-cli", null);
    redis_cli.setTarget(target);
    redis_cli.setBuildMode(mode);
    redis_cli.install();
    redis_cli.linkLibC();
    redis_cli.linkLibrary(hiredis);
    redis_cli.addIncludeDir("deps/hiredis");
    redis_cli.addIncludeDir("deps/linenoise");
    redis_cli.addIncludeDir("deps/lua/src");
    redis_cli.addCSourceFiles(&.{
        "src/adlist.c",
        "src/ae.c",
        "src/anet.c",
        "src/cli_common.c",
        "src/crc16.c",
        "src/crc64.c",
        "src/crcspeed.c",
        "src/dict.c",
        "src/monotonic.c",
        "src/mt19937-64.c",
        "src/redis-cli.c",
        "src/release.c",
        "src/redisassert.c",
        "src/siphash.c",
        "src/zmalloc.c",
        "deps/linenoise/linenoise.c",
    }, &.{
        "-std=c11",
        "-pedantic",
        "-Wall",
        "-W",
        "-Wno-missing-field-initializers",
    });

    const redis_server = b.addExecutable("redis-server", null);
    redis_server.setTarget(target);
    redis_server.setBuildMode(mode);
    redis_server.install();
    redis_server.linkLibC();
    redis_server.linkLibrary(hiredis);
    redis_server.linkLibrary(lua);
    redis_server.addIncludeDir("deps/hiredis");
    redis_server.addIncludeDir("deps/lua/src");
    redis_server.addCSourceFiles(&.{
        "src/acl.c",
        "src/adlist.c",
        "src/ae.c",
        "src/anet.c",
        "src/aof.c",
        "src/bio.c",
        "src/bitops.c",
        "src/blocked.c",
        "src/childinfo.c",
        "src/cluster.c",
        "src/config.c",
        "src/connection.c",
        "src/crc16.c",
        "src/crc64.c",
        "src/crcspeed.c",
        "src/db.c",
        "src/debug.c",
        "src/defrag.c",
        "src/dict.c",
        "src/endianconv.c",
        "src/evict.c",
        "src/expire.c",
        "src/geo.c",
        "src/geohash.c",
        "src/geohash_helper.c",
        "src/gopher.c",
        "src/hyperloglog.c",
        "src/intset.c",
        "src/latency.c",
        "src/lazyfree.c",
        "src/listpack.c",
        "src/localtime.c",
        "src/lolwut.c",
        "src/lolwut5.c",
        "src/lolwut6.c",
        "src/lzf_c.c",
        "src/lzf_d.c",
        "src/memtest.c",
        "src/module.c",
        "src/monotonic.c",
        "src/mt19937-64.c",
        "src/multi.c",
        "src/networking.c",
        "src/notify.c",
        "src/object.c",
        "src/pqsort.c",
        "src/pubsub.c",
        "src/quicklist.c",
        "src/rand.c",
        "src/rax.c",
        "src/rdb.c",
        "src/redis-check-aof.c",
        "src/redis-check-rdb.c",
        "src/release.c",
        "src/replication.c",
        "src/rio.c",
        "src/scripting.c",
        "src/sds.c",
        "src/sentinel.c",
        "src/server.c",
        "src/setcpuaffinity.c",
        "src/setproctitle.c",
        "src/sha1.c",
        "src/sha256.c",
        "src/siphash.c",
        "src/slowlog.c",
        "src/sort.c",
        "src/sparkline.c",
        "src/syncio.c",
        "src/t_hash.c",
        "src/t_list.c",
        "src/t_set.c",
        "src/t_stream.c",
        "src/t_string.c",
        "src/t_zset.c",
        "src/timeout.c",
        "src/tls.c",
        "src/tracking.c",
        "src/util.c",
        "src/ziplist.c",
        "src/zipmap.c",
        "src/zmalloc.c",
    }, &.{
        "-std=c11",
        "-pedantic",
        "-Wall",
        "-W",
        "-Wno-missing-field-initializers",
        "-fno-sanitize=undefined",
    });
}

  您也可以在 GitHub 上找到这段代码

下一步是什么?

  既然我们使用了 zig 编译,就可以非常轻松地进行交叉编译,而不需要外部依赖。这是个不错的地方,但如果你还想体验最后的乐趣,我可以教你如何将 Zig 代码添加到现有的 C 项目中。

  可重复性脚注
  Zig 0.8.1,Redis commit be6ce8a。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值