注本文为 “Zig 编译” 相关合辑。英文引文机翻未校。中文引文略作重排。如有内容异常请看原文。Zig Cross-compilation交叉编译Last updated on Jan 4, 2026 by SobestonBy default, Zig will compile for your combination of CPU and OS. This can be overridden by-target. Let’s compile our tiny hello world to a 64-bit arm Linux platform.默认情况下Zig 会针对你的 CPU 和 OS 组合进行编译。该行为可通过-target参数覆盖。下面我们将小型 hello world 程序编译到 64 位 arm Linux 平台。zig build-exe .\tiny-hello.zig-OReleaseSmall-fstrip-fsingle-threaded-targetaarch64-linuxQEMU or similar may be used to conveniently test executables made for foreign platforms.可使用 QEMU 或类似工具方便地测试为其他平台生成的可执行文件。Some CPU architectures that you can cross-compile for:可进行交叉编译的部分 CPU 架构如下x86_64armaarch64i386riscv64wasm32Some operating systems you can cross-compile for:可进行交叉编译的部分操作系统如下linuxmacoswindowsfreebsdnetbsddragonflyUEFIMany other targets are available for compilation but aren’t as well tested as of now. See Zig’s support table for more information; the list of well-tested targets is slowly expanding.目前还有许多其他可编译目标但测试尚未充分。有关更多信息请参阅 Zig 的支持表格经过充分测试的目标列表正逐步扩展。As Zig compiles for your specific CPU by default, these binaries may not run on other computers with slightly different CPU architectures. It may be useful to instead specify a specific baseline CPU model for greater compatibility. Note: Choosing an older CPU architecture will bring greater compatibility, but means you also miss out on newer CPU instructions; there is an efficiency/speed versus compatibility trade-off here.由于 Zig 默认针对特定的 CPU 进行编译因此这些二进制文件可能无法在 CPU 架构略有不同的其他计算机上运行。为获得更高的兼容性指定一个特定的基准 CPU 型号可能会有所帮助。注意选择较旧的 CPU 架构会带来更高的兼容性但也意味着会错过较新的 CPU 指令此处存在效率/速度与兼容性之间的权衡。Let’s compile a binary for a sandybridge CPU (Intel x86_64, circa 2011), so we can be reasonably sure that someone with an x86_64 CPU can run our binary. Here we can usenativein place of our CPU or OS, to use our system’s.下面我们为 sandybridge CPUIntel x86_64约 2011 年编译一个二进制文件这样我们就可以合理确保拥有 x86_64 CPU 的用户能够运行我们的二进制文件。在此处我们可以使用native替代 CPU 或 OS以使用我们系统的 CPU 或 OS。zig build-exe tiny-hello.zig-targetx86_64-native-mcpusandybridgeDetails on what architectures, OSes, CPUs, and ABIs (details on ABIs in the next chapter) are available can be found by runningzig targets. Note: the output is long, and you may want to pipe it to a file, e.g.zig targets targets.json.可通过运行zig targets命令查看可用的架构、操作系统、CPU 和 ABI下一章将详细介绍 ABI的相关细节。注意输出内容较长你可能需要将其重定向到文件中例如zig targets targets.json。Using Zig As Cross Platform C Toolchain将 Zig 用作跨平台 C 工具链ruoyusun27 Feb 2022I like to learn at least one new programming language every year - it’s mostly for fun - they are rarely useful for projects that I actually have to ship.我每年都会学习至少一门新的编程语言这主要是出于兴趣这些语言很少能应用于我实际需要交付的项目。This year, I’ve decided to look at Zig. After skimming through the official documentation and finishing the ray tracing in one weekend exercise, I realize that Zig can help with my game even though it has zero lines of Zig code.今年我决定了解 Zig。在粗略阅读官方文档并完成周末光线追踪练习后我发现即便游戏中没有一行 Zig 代码Zig 依然能为我的游戏开发提供帮助。A little background information. Most of the gameplay code is written in the game engine’s scripting environment in TypeScript. But there are a few native binaries that I need to ship as well.补充一点背景信息。游戏的大部分玩法逻辑代码使用 TypeScript 在引擎脚本环境中编写同时我还需要交付若干原生二进制文件。Given the game supports six platforms: Windows, Mac, Linux, Web, iOS, and Android, this process is quite tedious (although usually these binaries are only needed for a subset of platforms).由于该游戏支持 6 个平台Windows、Mac、Linux、Web、iOS 与 Android这一流程十分繁琐尽管这些二进制文件通常仅需适配部分平台。Currently, I do not use a cross-platform compilation toolchain - because they are hard to set up and have a lot of issues. Instead, I set up a toolchain for each target platform (I need it anyway to ship the game executable), compile the binary, put it in the repository, and call it a day.目前我并未使用跨平台编译工具链原因是其配置难度高且问题较多。我采用的方式是为每个目标平台单独配置工具链交付游戏可执行文件时本就需要这些工具链完成二进制文件编译后存入代码仓库即完成工作。It’s not an elegant solution but it works - as long as I don’t update them very often.该方案不够简洁但可正常运行前提是不频繁更新这些二进制文件。Compile C with Zig使用 Zig 编译 C 代码Zig has a decent cross compilation support. Not only that, it also provides a way to build C code: zig cc.Zig 具备完善的跨平台编译支持除此之外它还提供了编译 C 代码的方式zig cc。Let’s try with an example project. Duktape is an embeddable JavaScript engine with a small footprint, written in C99.我们以一个示例项目进行演示。Duktape 是一款轻量级可嵌入 JavaScript 引擎采用 C99 编写。Since Windows is my main development environment, there are two choices: MSVC or MinGW(GCC/Clang). Each involves gigabytes of downloads and a complex installation process.由于 Windows 是我的主力开发环境可选工具仅有 MSVC 或 MinGWGCC/Clang二者均需下载数 GB 资源且安装流程复杂。Compared to that, setting up Zig is simple: download the prebuild binary for Windows, extract in a directory, addzigexecutable toPATHand we are good to go.与之相比Zig 的配置十分简便下载 Windows 平台预编译二进制文件解压至指定目录将zig可执行文件路径添加至系统PATH环境变量即可使用。Now we can try to compile the example that comes with DukTape. Here’s the command to do that in the official documentation:接下来尝试编译 DukTape 自带的示例程序官方文档中对应的编译命令如下gcc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lmSo we can replacegccwithzig cc(Note: I am using Git Bash/MinGW64 shell).我们可将命令中的gcc替换为zig cc注当前使用 Git Bash/MinGW64 终端。zig cc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lmThe command finishes without an error - that’s a good sign. Let’s try to run it.命令执行无报错这是良好的信号接下来尝试运行程序。$ ./hello Illegal instructionOops, that doesn’t look good. After some googling, it turns out that by default, zig will pass-fsanitizeundefined -fsanitize-trapundefinedto Clang, which will cause undefined behavior (UB) to generate “illegal instruction”.出现非法指令错误。经检索可知Zig 默认会向 Clang 传递-fsanitizeundefined -fsanitize-trapundefined参数该参数会使未定义行为UB触发“非法指令”。In the DukTape code, there are some UB but since our purpose is not to fix it (we have a game to ship!), let’s ignore it for now by adding-fno-sanitizeundefined.DukTape 代码中存在部分未定义行为而我们的目标并非修复该问题需完成游戏交付因此通过添加-fno-sanitizeundefined参数暂时忽略此类问题。zig cc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lm -fno-sanitizeundefinedNow it looks better!程序可正常运行。$ ./hello Hello world! 235This is very impressive considering all I need is a ~60MB self-contained Zig compiler on the Windows platform.仅需在 Windows 平台使用一个约 60 MB 的独立 Zig 编译器即可实现上述效果表现十分出色。But it’s not only that -zig ccalso supports cross-compilation out of the box.除此之外zig cc还原生支持跨平台编译。Cross Compilation跨平台编译Let’s try compiling the same code on Windows for macOS. This can be achieved by simply adding a target.尝试在 Windows 平台为 macOS 编译相同代码仅需添加目标平台参数即可实现。zig cc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lm -fno-sanitizeundefined -target x86_64-macosThen copy the binary to my Macbook Pro (Intel), make it executable, and run it.将编译后的二进制文件复制至 Intel 版 Macbook Pro赋予执行权限后运行。% chmod x ./hello % ./hello Hello world! 235It just works!程序直接正常运行。Working With C in Zig在 Zig 中使用 C 代码At this point, my game, which has zero line of Zig code, can already benefit from the wonderful toolchain that Zig comes with.至此即便我的游戏中没有一行 Zig 代码也已能借助 Zig 提供的优质工具链获益。But since we are here, let’s maybe convert some of the C code to Zig - after all Zig is a more modern language and is much more pleasant to use.既然已经开始使用 Zig不妨将部分 C 代码转换为 Zig 代码毕竟 Zig 是一门现代化语言使用体验更为友好。We can usezig init-exeto initialize an empty Zig project template. We will get a build scriptbuild.zigand a main source filesrc/main.zig.可通过zig init-exe初始化空 Zig 项目模板生成构建脚本build.zig与主源码文件src/main.zig。To use Duktape in this Zig project, let’s copyduktape.cduktape.handduk_config.htosrc/vendor.为在该 Zig 项目中使用 Duktape将duktape.c、duktape.h与duk_config.h复制至src/vendor目录。There are two main approaches to import C code:cImportandzig translate-c. They both utilize the same underlying infrastructure but the latter offers more flexibility.引入 C 代码主要有两种方式cImport与zig translate-c。二者底层实现相同后者灵活性更高。First, we need to translateduktape.hto Zig and write it to a file.首先将duktape.h转换为 Zig 代码并写入文件。zig translate-c -lc duktape.h duktape.zigThen we can simply import the Zig file in ourmain.随后在主程序中直接导入该 Zig 文件。const std import(std); const duktape import(vendor/duktape.zig); pub fn main() !void { const ctx duktape.duk_create_heap_default(); const code duktape.duk_peval_string(ctx, 51); std.log.info(peval result code {}, .{code}); const result duktape.duk_get_int(ctx, -1); std.log.info(peval result {}, .{result}); }Another benefit ofzig translate-cis that we can get some nice IntelliSense support from IDE/Editor via Zig Language Server.zig translate-c的另一优势是可通过 Zig 语言服务器为 IDE/编辑器提供完善的代码补全支持。To run our project, we need to modify the build script. The default project template should have a section that looks like this:运行项目前需修改构建脚本默认项目模板包含如下代码段const exe b.addExecutable(duktape-zig, src/main.zig); exe.setTarget(target); exe.setBuildMode(mode); exe.install();We need to add the C source file and enablelibclinking (we also need to pass-fno-sanitizeundefinedto Clang as discussed above).需添加 C 源码文件并启用libc链接同时按前文所述向 Clang 传递-fno-sanitizeundefined参数。const flags [_][]const u8 { -fno-sanitizeundefined, }; exe.addCSourceFile(src/vendor/duktape.c, flags); exe.linkLibC();We can now run the project by usingzig build run. However, if we do this, we will get an error:通过zig build run运行项目时会出现如下错误$ zig build run .\src\vendor\duktape.zig:3670:65: error: expected type ?fn(?*anyopaque, usize) callconv(.C) ?*anyopaque, found ?*anyopaque pub inline fn duk_create_heap_default() TypeOf(duk_create_heap(NULL, NULL, NULL, NULL, NULL)) {Let’s inspect the translatedduktape.zigfile:查看转换后的duktape.zig文件内容pub const NULL import(std).zig.c_translation.cast(?*anyopaque, as(c_int, 0)); pub inline fn duk_create_heap_default() TypeOf(duk_create_heap(NULL, NULL, NULL, NULL, NULL)) { return duk_create_heap(NULL, NULL, NULL, NULL, NULL); } pub const duk_alloc_function ?fn (?*anyopaque, duk_size_t) callconv(.C) ?*anyopaque; pub extern fn duk_create_heap(alloc_func: duk_alloc_function, realloc_func: duk_realloc_function, free_func: duk_free_function, heap_udata: ?*anyopaque, fatal_handler: duk_fatal_function) ?*duk_context;This looks complicated at first but after some digging, we can see thatduk_create_heapaccepts an optional function type, butNULL, which is used for bridging C’sNULL, cannot be coerced into that - thus the complaint from the compiler.该问题初看复杂经排查可知duk_create_heap接收可选函数类型参数而用于对接 C 语言NULL的 Zig 常量NULL无法隐式转换为该类型因此编译器报错。There’s in fact an open issue about this. If we look atduktape.hsource file, it looks like this.该问题对应一个公开议题查看duktape.h源码内容如下#defineduk_create_heap_default()\duk_create_heap(NULL,NULL,NULL,NULL,NULL)A simple solution to get our program to compile is to use Zig’snullinstead ofNULL.使程序正常编译的简易方案是使用 Zig 原生null替代转换后的NULL。pub inline fn duk_create_heap_default() TypeOf(duk_create_heap(null, null, null, null, null)) { return duk_create_heap(null, null, null, null, null); }Now if we dozig build run, we will get.再次执行zig build run输出结果如下$ zig build run info: peval result code 0 info: peval result 6Conclusion总结Traditionally, if I need to work with C files but want some batteries included, C is the language to go to.传统开发中若需处理 C 文件并希望获得完备的功能支持通常会选择 C。C has a large feature set and a heavy toolchain but most of the time, I only use a small subset of features. Plus C doesn’t spark joy.C 功能体系庞大工具链繁重而实际开发中仅会使用其少量特性且开发体验不佳。Zig fills this niche nicely. It is easy to set up, has a modern toolchain and build system that works well on different platform.Zig 恰好填补了这一空白。其配置简便具备现代化工具链与构建系统可在多平台稳定运行。It comes with cross-compilation support out of the box. The language is easy to pick up and an absolute joy to work with.该语言原生支持跨平台编译上手难度低开发体验愉悦。If you don’t need the sledgehammer that is C, give Zig a try.若无需使用 C 这般重量级工具可尝试使用 Zig。Zig简化跨架构交叉编译的实现方案clickfling2025-09-14在 ARM、MIPS 等架构嵌入式硬件的开发场景中受硬件运算性能限制通常不在目标硬件上直接执行程序编译操作而是在高性能计算设备上完成交叉编译即在架构 A 的设备环境中生成适用于架构 B 的可执行程序。传统 C/C 程序的交叉编译流程依赖交叉编译工具链该工具链包含编译器、链接器、标准库等组件同时需要对项目构建工具进行适配配置整体操作流程繁琐。Zig 可简化 C/C 程序的交叉编译配置流程操作便捷性与 Go 语言相近。基于 Zig 实现单文件程序的交叉编译本节通过命令行操作演示 Zig 交叉编译的基础流程。下述代码为标准 C 语言 Hello World 示例程序// Filename - hello_world.c#includestdio.hintmain(void){printf(Hello world!);return0;}通过zig cc指令将程序编译为 MIPS 架构可执行文件zig cc-targetmips-linux-musleabi hello_world.c-ohello_mips使用file指令验证编译产物架构信息$filehello_mips hello_mips: ELF32-bit MSB executable, MIPS, MIPS32 rel2 version1(SYSV), statically linked, with debug_info, not strippedZig 内置编译器、链接器、AR、Ranlib 及标准库组件无需额外配置外部工具链。执行zig targets可查看 Zig 支持的目标平台列表并实现平台间的切换$ zig targets .{.arch.{amdgcn,arc,arm,armeb,thumb,thumbeb,aarch64,aarch64_be,...构建系统中 Zig 交叉编译的配置方法工程化项目通常采用构建系统管理编译流程本节介绍 Zig 在两类常用构建系统中的配置方式。CMake 构建系统以 fastfetch 项目为例演示 CMake 环境下 Zig 交叉编译的配置流程。首先克隆 fastfetch 项目源码与 zig-cross 工具集gitclone https://github.com/fastfetch-cli/fastfetchgitclone https://github.com/mrexodia/zig-cross.git进入 fastfetch 项目目录复制 zig-cross 中的 cmake 配置目录与模板文件至当前目录cdfastfetchcp-rf../zig-cross/cmake../zig-cross/xxx.cmake.将模板 cmake 文件重命名为目标平台对应的配置文件cpxxx.cmake mipsel-linux-musleabi.cmake创建构建目录并执行构建配置与编译操作cmake-Bbuild-mipsel-GNinja--toolchainmipsel-linux-musleabi.cmake cmake--buildbuild-mipsel首次编译会触发头文件缺失错误编译器尝试调用主机环境的 libc 头文件该问题由-I/usr/include编译参数导致。解决方案为关闭项目中无关依赖项在配置文件中修改相关选项###################### Configure options ######################include(CMakeDependentOption)cmake_dependent_option(ENABLE_VULKANEnable vulkanOFFLINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNUOFF)...同步关闭 Zlib 依赖option(ENABLE_ZLIBEnable zlibOFF)二次编译仍会触发编译警告错误该现象源于 Zig 默认启用严格的警告检测机制。通过编译选项忽略时间宏相关警告echoadd_compile_options(-Wno-errordate-time)mipsel-linux-musleabi.cmake完成配置后编译成功验证产物架构信息$filebuild-mipsel/flashfetch build-mipsel/flashfetch: ELF32-bit LSB executable, MIPS, MIPS32 rel2 version1(SYSV), statically linked, with debug_info, not stripped目标硬件运行效果如下Meson 构建系统Meson 为项目构建系统操作逻辑相较于 CMake 更为简洁。以 zzz 项目为例演示相关配置流程gitclone--depth1https://github.com/diredocks/zzz.gitcdzzz项目内 cross 目录存储交叉编译配置文件其功能等价于 CMake 工具链文件示例配置内容如下[binaries] c [zig, cc] cpp [zig, c] ar [zig, ar] ranlib [zig, ranlib] lib [zig, lib] dlltool [zig, dlltool] pkg-config pkg-config [host_machine] system linux cpu_family mips cpu mipsel endian little [built-in options] c_args [-target, mipsel-linux-musleabi] c_link_args [-target, mipsel-linux-musleabi]切换其他目标平台时仅需修改-target参数即可。执行构建配置与编译指令meson setup build-mipsel --cross-file cross/mipsel-linux-musleabi.toml meson compile-Cbuild-mipsel编译过程中出现 pcap 头文件缺失错误交叉编译要求依赖库与目标平台架构匹配因此需先编译目标平台版本的 libpcap 库。在 libpcap 源码目录中执行配置与编译操作# 假定 libpcap 源码包已完成下载CCzig cc -target mipsel-linux-musleabi\ARzig ar\RANLIBzig ranlib\./configure--hostx86_64-linux --with-pcaplinux--prefix$(pwd)make-j$(nproc)makeinstallexportPCAP_PATH$(pwd)/lib/pkgconfig/返回 zzz 项目目录配置 pkg-config 依赖查找路径exportPKG_CONFIG_LIBDIR$PCAP_PATH清除原有构建配置并重新编译meson setup--wipebuild-mipsel --cross-file cross/mipsel-linux-musleabi.toml meson compile-Cbuild-mipsel编译完成后验证产物信息$filebuild-mipsel/zzz build-mipsel/zzz: ELF32-bit LSB executable, MIPS, MIPS32 rel2 version1(SYSV), dynamically linked, interpreter /lib/ld-musl-mipsel-sf.so.1, with debug_info, not stripped总结Zig 降低了 C/C 程序交叉编译的操作门槛拓展了跨架构开发的实现选择。zig cc: 跨平台编译 C 语言项目txthinking Updated at: 2023-11-03C 语言的痛C 语言作为一种极简的编程语言其设计理念具有简洁性但在跨平台编译场景中存在不便之处例如在 macOS 系统上编译生成适用于 Linux 系统的二进制文件操作流程较为繁琐。据公开信息显示Uber 公司已将 Zig 编译器应用于生产环境尽管此时 Zig 尚未发布 1.0 正式版本。在编译joker项目项目地址https://github.com/txthinking/joker时实际体验了 Zig 的跨平台编译功能效果较为出色。zig由于 Zig 尚未发布 1.0 正式版本且通过 brew 工具安装的 Zig 包版本较旧因此推荐使用nami工具项目地址https://github.com/txthinking/nami安装 Zig对应的安装配置文件地址为https://github.com/txthinking/nami/blob/master/package/zig.js。使用nami安装 Zig 的命令如下namiinstallzig安装完成后可通过以下三种方式使用zig cc进行跨平台编译。替换 CC该方式对原有项目构建流程的侵入性最小可在执行make命令时直接通过CC变量指定zig cc及目标平台示例命令如下makeCCzig cc -target x86_64-linux-gnu直接使用 zig cc该方式适用于源代码文件数量较少的项目可直接通过zig cc命令指定输出文件、目标平台及源代码文件示例命令如下zig cc-ojoker-targetx86_64-macos-none main.c run.c使用 zig build-exezig build-exe是zig cc的封装子命令使用方式与zig cc类似可通过相关参数指定链接库、输出名称、目标平台及编译优化等级示例命令如下zig build-exe-lc--namejoker-targetaarch64-macos-none-OReleaseSafe main.c run.c其他补充说明zig cc支持通过-stdc11等参数指定 C 语言标准同时支持链接 musl 库。尽管 musl 库的性能略低于 glibc 库但其代码实现简洁清晰符合 KISSKeep It Simple, Stupid设计原则。joker项目的下一个版本将采用静态链接 musl 库的方式进行构建。更多zig cc的可用参数可通过执行zig cc --help命令查看。交叉编译与跨平台的区别交叉编译与跨平台的区别在于目标与场景不同二者相互关联但并非同一概念结合文档中 Zig 相关场景具体说明如下1. 定义与目标交叉编译指在一种架构/系统的主机上编译生成另一种架构/系统的目标机可执行文件的过程。主要涉及“不同平台间的编译动作”解决“目标硬件性能不足无法本地编译”或“需为多目标平台批量构建”的问题。文档中示例如zig build-exe -target aarch64-linux是在当前主机如 x86_64 架构编译出适用于 aarch64-linux 架构的二进制文件。跨平台指软件或工具能够在多种不同的架构/操作系统上运行或适配的特性。主要涉及“软件的兼容性”解决“一份代码/工具可在多平台复用”的问题不局限于编译环节。文档中 Zig 支持linux、macos、windows等多种 OS 目标以及x86_64、aarch64等多种 CPU 架构体现了 Zig 的跨平台特性。2. 关联与区别维度交叉编译跨平台动作编译过程主机 → 目标机软件适配多平台兼容重点编译产物的目标平台适配软件在不同平台的可运行性关系是实现跨平台软件的手段之一是交叉编译的目标之一示例zig cc -target x86_64-linux编译指令Zig 支持多 OS/CPU 架构的目标列表简单来说交叉编译是“为其他平台做编译”的行为跨平台是“能在其他平台用”的特性。Zig 通过提供交叉编译工具zig cc、zig build-exe降低了跨平台软件的构建难度。referenceCross-compilation | zig.guidehttps://zig.guide/build-system/cross-compilation/Using Zig As Cross Platform C Toolchainhttps://ruoyusun.com/2022/02/27/zig-cc.htmlzig cc: 跨平台编译 C 语言项目https://www.txthinking.com/talks/articles/zig-cc.articleZig史上最简单的交叉编译 - 抗性面包https://blog.clickfling.top/posts/zig-cross-compile/Using Zig as cross-platform C toolchain | Hacker Newshttps://news.ycombinator.com/item?id30488979zig 为什么可以成为比 C 更好的编译器 · zigcc · Discussion #73 · GitHubhttps://github.com/orgs/zigcc/discussions/73-第三方库 | Zig 语言圣经https://course.ziglang.cc/appendix/well-known-lib.htmlziglang/zig: General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software. - Codeberg.orghttps://codeberg.org/ziglang/zig
Zig | 交叉编译 / 跨平台编译
注本文为 “Zig 编译” 相关合辑。英文引文机翻未校。中文引文略作重排。如有内容异常请看原文。Zig Cross-compilation交叉编译Last updated on Jan 4, 2026 by SobestonBy default, Zig will compile for your combination of CPU and OS. This can be overridden by-target. Let’s compile our tiny hello world to a 64-bit arm Linux platform.默认情况下Zig 会针对你的 CPU 和 OS 组合进行编译。该行为可通过-target参数覆盖。下面我们将小型 hello world 程序编译到 64 位 arm Linux 平台。zig build-exe .\tiny-hello.zig-OReleaseSmall-fstrip-fsingle-threaded-targetaarch64-linuxQEMU or similar may be used to conveniently test executables made for foreign platforms.可使用 QEMU 或类似工具方便地测试为其他平台生成的可执行文件。Some CPU architectures that you can cross-compile for:可进行交叉编译的部分 CPU 架构如下x86_64armaarch64i386riscv64wasm32Some operating systems you can cross-compile for:可进行交叉编译的部分操作系统如下linuxmacoswindowsfreebsdnetbsddragonflyUEFIMany other targets are available for compilation but aren’t as well tested as of now. See Zig’s support table for more information; the list of well-tested targets is slowly expanding.目前还有许多其他可编译目标但测试尚未充分。有关更多信息请参阅 Zig 的支持表格经过充分测试的目标列表正逐步扩展。As Zig compiles for your specific CPU by default, these binaries may not run on other computers with slightly different CPU architectures. It may be useful to instead specify a specific baseline CPU model for greater compatibility. Note: Choosing an older CPU architecture will bring greater compatibility, but means you also miss out on newer CPU instructions; there is an efficiency/speed versus compatibility trade-off here.由于 Zig 默认针对特定的 CPU 进行编译因此这些二进制文件可能无法在 CPU 架构略有不同的其他计算机上运行。为获得更高的兼容性指定一个特定的基准 CPU 型号可能会有所帮助。注意选择较旧的 CPU 架构会带来更高的兼容性但也意味着会错过较新的 CPU 指令此处存在效率/速度与兼容性之间的权衡。Let’s compile a binary for a sandybridge CPU (Intel x86_64, circa 2011), so we can be reasonably sure that someone with an x86_64 CPU can run our binary. Here we can usenativein place of our CPU or OS, to use our system’s.下面我们为 sandybridge CPUIntel x86_64约 2011 年编译一个二进制文件这样我们就可以合理确保拥有 x86_64 CPU 的用户能够运行我们的二进制文件。在此处我们可以使用native替代 CPU 或 OS以使用我们系统的 CPU 或 OS。zig build-exe tiny-hello.zig-targetx86_64-native-mcpusandybridgeDetails on what architectures, OSes, CPUs, and ABIs (details on ABIs in the next chapter) are available can be found by runningzig targets. Note: the output is long, and you may want to pipe it to a file, e.g.zig targets targets.json.可通过运行zig targets命令查看可用的架构、操作系统、CPU 和 ABI下一章将详细介绍 ABI的相关细节。注意输出内容较长你可能需要将其重定向到文件中例如zig targets targets.json。Using Zig As Cross Platform C Toolchain将 Zig 用作跨平台 C 工具链ruoyusun27 Feb 2022I like to learn at least one new programming language every year - it’s mostly for fun - they are rarely useful for projects that I actually have to ship.我每年都会学习至少一门新的编程语言这主要是出于兴趣这些语言很少能应用于我实际需要交付的项目。This year, I’ve decided to look at Zig. After skimming through the official documentation and finishing the ray tracing in one weekend exercise, I realize that Zig can help with my game even though it has zero lines of Zig code.今年我决定了解 Zig。在粗略阅读官方文档并完成周末光线追踪练习后我发现即便游戏中没有一行 Zig 代码Zig 依然能为我的游戏开发提供帮助。A little background information. Most of the gameplay code is written in the game engine’s scripting environment in TypeScript. But there are a few native binaries that I need to ship as well.补充一点背景信息。游戏的大部分玩法逻辑代码使用 TypeScript 在引擎脚本环境中编写同时我还需要交付若干原生二进制文件。Given the game supports six platforms: Windows, Mac, Linux, Web, iOS, and Android, this process is quite tedious (although usually these binaries are only needed for a subset of platforms).由于该游戏支持 6 个平台Windows、Mac、Linux、Web、iOS 与 Android这一流程十分繁琐尽管这些二进制文件通常仅需适配部分平台。Currently, I do not use a cross-platform compilation toolchain - because they are hard to set up and have a lot of issues. Instead, I set up a toolchain for each target platform (I need it anyway to ship the game executable), compile the binary, put it in the repository, and call it a day.目前我并未使用跨平台编译工具链原因是其配置难度高且问题较多。我采用的方式是为每个目标平台单独配置工具链交付游戏可执行文件时本就需要这些工具链完成二进制文件编译后存入代码仓库即完成工作。It’s not an elegant solution but it works - as long as I don’t update them very often.该方案不够简洁但可正常运行前提是不频繁更新这些二进制文件。Compile C with Zig使用 Zig 编译 C 代码Zig has a decent cross compilation support. Not only that, it also provides a way to build C code: zig cc.Zig 具备完善的跨平台编译支持除此之外它还提供了编译 C 代码的方式zig cc。Let’s try with an example project. Duktape is an embeddable JavaScript engine with a small footprint, written in C99.我们以一个示例项目进行演示。Duktape 是一款轻量级可嵌入 JavaScript 引擎采用 C99 编写。Since Windows is my main development environment, there are two choices: MSVC or MinGW(GCC/Clang). Each involves gigabytes of downloads and a complex installation process.由于 Windows 是我的主力开发环境可选工具仅有 MSVC 或 MinGWGCC/Clang二者均需下载数 GB 资源且安装流程复杂。Compared to that, setting up Zig is simple: download the prebuild binary for Windows, extract in a directory, addzigexecutable toPATHand we are good to go.与之相比Zig 的配置十分简便下载 Windows 平台预编译二进制文件解压至指定目录将zig可执行文件路径添加至系统PATH环境变量即可使用。Now we can try to compile the example that comes with DukTape. Here’s the command to do that in the official documentation:接下来尝试编译 DukTape 自带的示例程序官方文档中对应的编译命令如下gcc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lmSo we can replacegccwithzig cc(Note: I am using Git Bash/MinGW64 shell).我们可将命令中的gcc替换为zig cc注当前使用 Git Bash/MinGW64 终端。zig cc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lmThe command finishes without an error - that’s a good sign. Let’s try to run it.命令执行无报错这是良好的信号接下来尝试运行程序。$ ./hello Illegal instructionOops, that doesn’t look good. After some googling, it turns out that by default, zig will pass-fsanitizeundefined -fsanitize-trapundefinedto Clang, which will cause undefined behavior (UB) to generate “illegal instruction”.出现非法指令错误。经检索可知Zig 默认会向 Clang 传递-fsanitizeundefined -fsanitize-trapundefined参数该参数会使未定义行为UB触发“非法指令”。In the DukTape code, there are some UB but since our purpose is not to fix it (we have a game to ship!), let’s ignore it for now by adding-fno-sanitizeundefined.DukTape 代码中存在部分未定义行为而我们的目标并非修复该问题需完成游戏交付因此通过添加-fno-sanitizeundefined参数暂时忽略此类问题。zig cc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lm -fno-sanitizeundefinedNow it looks better!程序可正常运行。$ ./hello Hello world! 235This is very impressive considering all I need is a ~60MB self-contained Zig compiler on the Windows platform.仅需在 Windows 平台使用一个约 60 MB 的独立 Zig 编译器即可实现上述效果表现十分出色。But it’s not only that -zig ccalso supports cross-compilation out of the box.除此之外zig cc还原生支持跨平台编译。Cross Compilation跨平台编译Let’s try compiling the same code on Windows for macOS. This can be achieved by simply adding a target.尝试在 Windows 平台为 macOS 编译相同代码仅需添加目标平台参数即可实现。zig cc -stdc99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lm -fno-sanitizeundefined -target x86_64-macosThen copy the binary to my Macbook Pro (Intel), make it executable, and run it.将编译后的二进制文件复制至 Intel 版 Macbook Pro赋予执行权限后运行。% chmod x ./hello % ./hello Hello world! 235It just works!程序直接正常运行。Working With C in Zig在 Zig 中使用 C 代码At this point, my game, which has zero line of Zig code, can already benefit from the wonderful toolchain that Zig comes with.至此即便我的游戏中没有一行 Zig 代码也已能借助 Zig 提供的优质工具链获益。But since we are here, let’s maybe convert some of the C code to Zig - after all Zig is a more modern language and is much more pleasant to use.既然已经开始使用 Zig不妨将部分 C 代码转换为 Zig 代码毕竟 Zig 是一门现代化语言使用体验更为友好。We can usezig init-exeto initialize an empty Zig project template. We will get a build scriptbuild.zigand a main source filesrc/main.zig.可通过zig init-exe初始化空 Zig 项目模板生成构建脚本build.zig与主源码文件src/main.zig。To use Duktape in this Zig project, let’s copyduktape.cduktape.handduk_config.htosrc/vendor.为在该 Zig 项目中使用 Duktape将duktape.c、duktape.h与duk_config.h复制至src/vendor目录。There are two main approaches to import C code:cImportandzig translate-c. They both utilize the same underlying infrastructure but the latter offers more flexibility.引入 C 代码主要有两种方式cImport与zig translate-c。二者底层实现相同后者灵活性更高。First, we need to translateduktape.hto Zig and write it to a file.首先将duktape.h转换为 Zig 代码并写入文件。zig translate-c -lc duktape.h duktape.zigThen we can simply import the Zig file in ourmain.随后在主程序中直接导入该 Zig 文件。const std import(std); const duktape import(vendor/duktape.zig); pub fn main() !void { const ctx duktape.duk_create_heap_default(); const code duktape.duk_peval_string(ctx, 51); std.log.info(peval result code {}, .{code}); const result duktape.duk_get_int(ctx, -1); std.log.info(peval result {}, .{result}); }Another benefit ofzig translate-cis that we can get some nice IntelliSense support from IDE/Editor via Zig Language Server.zig translate-c的另一优势是可通过 Zig 语言服务器为 IDE/编辑器提供完善的代码补全支持。To run our project, we need to modify the build script. The default project template should have a section that looks like this:运行项目前需修改构建脚本默认项目模板包含如下代码段const exe b.addExecutable(duktape-zig, src/main.zig); exe.setTarget(target); exe.setBuildMode(mode); exe.install();We need to add the C source file and enablelibclinking (we also need to pass-fno-sanitizeundefinedto Clang as discussed above).需添加 C 源码文件并启用libc链接同时按前文所述向 Clang 传递-fno-sanitizeundefined参数。const flags [_][]const u8 { -fno-sanitizeundefined, }; exe.addCSourceFile(src/vendor/duktape.c, flags); exe.linkLibC();We can now run the project by usingzig build run. However, if we do this, we will get an error:通过zig build run运行项目时会出现如下错误$ zig build run .\src\vendor\duktape.zig:3670:65: error: expected type ?fn(?*anyopaque, usize) callconv(.C) ?*anyopaque, found ?*anyopaque pub inline fn duk_create_heap_default() TypeOf(duk_create_heap(NULL, NULL, NULL, NULL, NULL)) {Let’s inspect the translatedduktape.zigfile:查看转换后的duktape.zig文件内容pub const NULL import(std).zig.c_translation.cast(?*anyopaque, as(c_int, 0)); pub inline fn duk_create_heap_default() TypeOf(duk_create_heap(NULL, NULL, NULL, NULL, NULL)) { return duk_create_heap(NULL, NULL, NULL, NULL, NULL); } pub const duk_alloc_function ?fn (?*anyopaque, duk_size_t) callconv(.C) ?*anyopaque; pub extern fn duk_create_heap(alloc_func: duk_alloc_function, realloc_func: duk_realloc_function, free_func: duk_free_function, heap_udata: ?*anyopaque, fatal_handler: duk_fatal_function) ?*duk_context;This looks complicated at first but after some digging, we can see thatduk_create_heapaccepts an optional function type, butNULL, which is used for bridging C’sNULL, cannot be coerced into that - thus the complaint from the compiler.该问题初看复杂经排查可知duk_create_heap接收可选函数类型参数而用于对接 C 语言NULL的 Zig 常量NULL无法隐式转换为该类型因此编译器报错。There’s in fact an open issue about this. If we look atduktape.hsource file, it looks like this.该问题对应一个公开议题查看duktape.h源码内容如下#defineduk_create_heap_default()\duk_create_heap(NULL,NULL,NULL,NULL,NULL)A simple solution to get our program to compile is to use Zig’snullinstead ofNULL.使程序正常编译的简易方案是使用 Zig 原生null替代转换后的NULL。pub inline fn duk_create_heap_default() TypeOf(duk_create_heap(null, null, null, null, null)) { return duk_create_heap(null, null, null, null, null); }Now if we dozig build run, we will get.再次执行zig build run输出结果如下$ zig build run info: peval result code 0 info: peval result 6Conclusion总结Traditionally, if I need to work with C files but want some batteries included, C is the language to go to.传统开发中若需处理 C 文件并希望获得完备的功能支持通常会选择 C。C has a large feature set and a heavy toolchain but most of the time, I only use a small subset of features. Plus C doesn’t spark joy.C 功能体系庞大工具链繁重而实际开发中仅会使用其少量特性且开发体验不佳。Zig fills this niche nicely. It is easy to set up, has a modern toolchain and build system that works well on different platform.Zig 恰好填补了这一空白。其配置简便具备现代化工具链与构建系统可在多平台稳定运行。It comes with cross-compilation support out of the box. The language is easy to pick up and an absolute joy to work with.该语言原生支持跨平台编译上手难度低开发体验愉悦。If you don’t need the sledgehammer that is C, give Zig a try.若无需使用 C 这般重量级工具可尝试使用 Zig。Zig简化跨架构交叉编译的实现方案clickfling2025-09-14在 ARM、MIPS 等架构嵌入式硬件的开发场景中受硬件运算性能限制通常不在目标硬件上直接执行程序编译操作而是在高性能计算设备上完成交叉编译即在架构 A 的设备环境中生成适用于架构 B 的可执行程序。传统 C/C 程序的交叉编译流程依赖交叉编译工具链该工具链包含编译器、链接器、标准库等组件同时需要对项目构建工具进行适配配置整体操作流程繁琐。Zig 可简化 C/C 程序的交叉编译配置流程操作便捷性与 Go 语言相近。基于 Zig 实现单文件程序的交叉编译本节通过命令行操作演示 Zig 交叉编译的基础流程。下述代码为标准 C 语言 Hello World 示例程序// Filename - hello_world.c#includestdio.hintmain(void){printf(Hello world!);return0;}通过zig cc指令将程序编译为 MIPS 架构可执行文件zig cc-targetmips-linux-musleabi hello_world.c-ohello_mips使用file指令验证编译产物架构信息$filehello_mips hello_mips: ELF32-bit MSB executable, MIPS, MIPS32 rel2 version1(SYSV), statically linked, with debug_info, not strippedZig 内置编译器、链接器、AR、Ranlib 及标准库组件无需额外配置外部工具链。执行zig targets可查看 Zig 支持的目标平台列表并实现平台间的切换$ zig targets .{.arch.{amdgcn,arc,arm,armeb,thumb,thumbeb,aarch64,aarch64_be,...构建系统中 Zig 交叉编译的配置方法工程化项目通常采用构建系统管理编译流程本节介绍 Zig 在两类常用构建系统中的配置方式。CMake 构建系统以 fastfetch 项目为例演示 CMake 环境下 Zig 交叉编译的配置流程。首先克隆 fastfetch 项目源码与 zig-cross 工具集gitclone https://github.com/fastfetch-cli/fastfetchgitclone https://github.com/mrexodia/zig-cross.git进入 fastfetch 项目目录复制 zig-cross 中的 cmake 配置目录与模板文件至当前目录cdfastfetchcp-rf../zig-cross/cmake../zig-cross/xxx.cmake.将模板 cmake 文件重命名为目标平台对应的配置文件cpxxx.cmake mipsel-linux-musleabi.cmake创建构建目录并执行构建配置与编译操作cmake-Bbuild-mipsel-GNinja--toolchainmipsel-linux-musleabi.cmake cmake--buildbuild-mipsel首次编译会触发头文件缺失错误编译器尝试调用主机环境的 libc 头文件该问题由-I/usr/include编译参数导致。解决方案为关闭项目中无关依赖项在配置文件中修改相关选项###################### Configure options ######################include(CMakeDependentOption)cmake_dependent_option(ENABLE_VULKANEnable vulkanOFFLINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNUOFF)...同步关闭 Zlib 依赖option(ENABLE_ZLIBEnable zlibOFF)二次编译仍会触发编译警告错误该现象源于 Zig 默认启用严格的警告检测机制。通过编译选项忽略时间宏相关警告echoadd_compile_options(-Wno-errordate-time)mipsel-linux-musleabi.cmake完成配置后编译成功验证产物架构信息$filebuild-mipsel/flashfetch build-mipsel/flashfetch: ELF32-bit LSB executable, MIPS, MIPS32 rel2 version1(SYSV), statically linked, with debug_info, not stripped目标硬件运行效果如下Meson 构建系统Meson 为项目构建系统操作逻辑相较于 CMake 更为简洁。以 zzz 项目为例演示相关配置流程gitclone--depth1https://github.com/diredocks/zzz.gitcdzzz项目内 cross 目录存储交叉编译配置文件其功能等价于 CMake 工具链文件示例配置内容如下[binaries] c [zig, cc] cpp [zig, c] ar [zig, ar] ranlib [zig, ranlib] lib [zig, lib] dlltool [zig, dlltool] pkg-config pkg-config [host_machine] system linux cpu_family mips cpu mipsel endian little [built-in options] c_args [-target, mipsel-linux-musleabi] c_link_args [-target, mipsel-linux-musleabi]切换其他目标平台时仅需修改-target参数即可。执行构建配置与编译指令meson setup build-mipsel --cross-file cross/mipsel-linux-musleabi.toml meson compile-Cbuild-mipsel编译过程中出现 pcap 头文件缺失错误交叉编译要求依赖库与目标平台架构匹配因此需先编译目标平台版本的 libpcap 库。在 libpcap 源码目录中执行配置与编译操作# 假定 libpcap 源码包已完成下载CCzig cc -target mipsel-linux-musleabi\ARzig ar\RANLIBzig ranlib\./configure--hostx86_64-linux --with-pcaplinux--prefix$(pwd)make-j$(nproc)makeinstallexportPCAP_PATH$(pwd)/lib/pkgconfig/返回 zzz 项目目录配置 pkg-config 依赖查找路径exportPKG_CONFIG_LIBDIR$PCAP_PATH清除原有构建配置并重新编译meson setup--wipebuild-mipsel --cross-file cross/mipsel-linux-musleabi.toml meson compile-Cbuild-mipsel编译完成后验证产物信息$filebuild-mipsel/zzz build-mipsel/zzz: ELF32-bit LSB executable, MIPS, MIPS32 rel2 version1(SYSV), dynamically linked, interpreter /lib/ld-musl-mipsel-sf.so.1, with debug_info, not stripped总结Zig 降低了 C/C 程序交叉编译的操作门槛拓展了跨架构开发的实现选择。zig cc: 跨平台编译 C 语言项目txthinking Updated at: 2023-11-03C 语言的痛C 语言作为一种极简的编程语言其设计理念具有简洁性但在跨平台编译场景中存在不便之处例如在 macOS 系统上编译生成适用于 Linux 系统的二进制文件操作流程较为繁琐。据公开信息显示Uber 公司已将 Zig 编译器应用于生产环境尽管此时 Zig 尚未发布 1.0 正式版本。在编译joker项目项目地址https://github.com/txthinking/joker时实际体验了 Zig 的跨平台编译功能效果较为出色。zig由于 Zig 尚未发布 1.0 正式版本且通过 brew 工具安装的 Zig 包版本较旧因此推荐使用nami工具项目地址https://github.com/txthinking/nami安装 Zig对应的安装配置文件地址为https://github.com/txthinking/nami/blob/master/package/zig.js。使用nami安装 Zig 的命令如下namiinstallzig安装完成后可通过以下三种方式使用zig cc进行跨平台编译。替换 CC该方式对原有项目构建流程的侵入性最小可在执行make命令时直接通过CC变量指定zig cc及目标平台示例命令如下makeCCzig cc -target x86_64-linux-gnu直接使用 zig cc该方式适用于源代码文件数量较少的项目可直接通过zig cc命令指定输出文件、目标平台及源代码文件示例命令如下zig cc-ojoker-targetx86_64-macos-none main.c run.c使用 zig build-exezig build-exe是zig cc的封装子命令使用方式与zig cc类似可通过相关参数指定链接库、输出名称、目标平台及编译优化等级示例命令如下zig build-exe-lc--namejoker-targetaarch64-macos-none-OReleaseSafe main.c run.c其他补充说明zig cc支持通过-stdc11等参数指定 C 语言标准同时支持链接 musl 库。尽管 musl 库的性能略低于 glibc 库但其代码实现简洁清晰符合 KISSKeep It Simple, Stupid设计原则。joker项目的下一个版本将采用静态链接 musl 库的方式进行构建。更多zig cc的可用参数可通过执行zig cc --help命令查看。交叉编译与跨平台的区别交叉编译与跨平台的区别在于目标与场景不同二者相互关联但并非同一概念结合文档中 Zig 相关场景具体说明如下1. 定义与目标交叉编译指在一种架构/系统的主机上编译生成另一种架构/系统的目标机可执行文件的过程。主要涉及“不同平台间的编译动作”解决“目标硬件性能不足无法本地编译”或“需为多目标平台批量构建”的问题。文档中示例如zig build-exe -target aarch64-linux是在当前主机如 x86_64 架构编译出适用于 aarch64-linux 架构的二进制文件。跨平台指软件或工具能够在多种不同的架构/操作系统上运行或适配的特性。主要涉及“软件的兼容性”解决“一份代码/工具可在多平台复用”的问题不局限于编译环节。文档中 Zig 支持linux、macos、windows等多种 OS 目标以及x86_64、aarch64等多种 CPU 架构体现了 Zig 的跨平台特性。2. 关联与区别维度交叉编译跨平台动作编译过程主机 → 目标机软件适配多平台兼容重点编译产物的目标平台适配软件在不同平台的可运行性关系是实现跨平台软件的手段之一是交叉编译的目标之一示例zig cc -target x86_64-linux编译指令Zig 支持多 OS/CPU 架构的目标列表简单来说交叉编译是“为其他平台做编译”的行为跨平台是“能在其他平台用”的特性。Zig 通过提供交叉编译工具zig cc、zig build-exe降低了跨平台软件的构建难度。referenceCross-compilation | zig.guidehttps://zig.guide/build-system/cross-compilation/Using Zig As Cross Platform C Toolchainhttps://ruoyusun.com/2022/02/27/zig-cc.htmlzig cc: 跨平台编译 C 语言项目https://www.txthinking.com/talks/articles/zig-cc.articleZig史上最简单的交叉编译 - 抗性面包https://blog.clickfling.top/posts/zig-cross-compile/Using Zig as cross-platform C toolchain | Hacker Newshttps://news.ycombinator.com/item?id30488979zig 为什么可以成为比 C 更好的编译器 · zigcc · Discussion #73 · GitHubhttps://github.com/orgs/zigcc/discussions/73-第三方库 | Zig 语言圣经https://course.ziglang.cc/appendix/well-known-lib.htmlziglang/zig: General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software. - Codeberg.orghttps://codeberg.org/ziglang/zig