使用 CGO 和 Zig 构建 Go 静态链接可执行文件
文章介绍了如何使用 Zig 和 CGO 构建 Go 静态链接可执行文件。首先,通过 `zig init` 创建 Zig 库,并简化 `build.zig` 文件。然后,编写一个使用 C ABI 的 Zig 库函数,并创建对应的 C 头文件。接着,编写 Go 程序调用该 Zig 函数,并通过特定的 Bash 命令进行静态链接。最后,通过运行程序和使用 `ldd` 命令验证静态链接是否成功。作者认为 Go 和 Zig 都是优秀的工具。
Jim Calabro
使用 CGO 和 Zig 构建 Go 静态链接可执行文件
这是一篇简短的文章,介绍如何创建一个静态链接的 Go 可执行文件,该文件使用 Zig 调用 CGO 依赖项。 本文的完整代码可在 此仓库 中找到。
默认情况下,如果您使用 CGO,则生成的可执行文件是动态链接的,但我经常希望进行静态链接以避免运行时错误。
首先,让我们使用 zig init 创建一个 Zig 库,然后删除它生成的额外内容,以便我们只剩下一个简单的静态库。 你可以 rm src/main.zig,因为我们不是要创建一个 Zig 可执行文件。
接下来,我们可以将 build.zig 简化为:
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const lib_mod = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
const lib = b.addLibrary(.{
.linkage = .static,
.name = "cgo_static_linking",
.root_module = lib_mod,
});
b.installArtifact(lib);
}
我们可以保留 build.zig.zon 文件不动。
现在,让我们在 src/root.zig 中编写一个使用 C ABI 的简单库函数:
// src/root.zig
const std = @import("std");
pub export fn my_zig_function() void {
std.debug.print("Hello from zig!\n", .{});
}
以及它对应的 C 头文件,命名为 zig_lib.h:
// zig_lib.h
#pragma once
void my_zig_function();
Zig 方面就这样! 现在可以通过简单地运行 zig build 来构建库。
让我们编写调用它的 Go 程序。
// main.go
package main
/*
#cgo LDFLAGS: -L./zig-out/lib -lcgo_static_linking -static
#include "zig_lib.h"
*/
import "C"
import "fmt"
func main() {
fmt.Println("starting program")
defer fmt.Println("done")
C.my_zig_function()
}
我们现在将构建 Go 可执行文件,并使用此 Bash 命令将其静态链接:
CC="zig cc -target x86_64-linux-musl" \
CGO_ENABLED=1 \
CGO_LDFLAGS="-static" \
GOOS=linux GOARCH=amd64 \
go build -a -ldflags '-extldflags "-static"' main.go
让我们检查一下我们的工作:
$ ./main
starting program
Hello from zig!
done
$ ldd ./main
not a dynamic executable
在我看来不错!
我非常感激我正处于工具变得非常优秀的时代。 Go 和 Zig 都很棒!
如果您发现这很有用,不妨考虑向 Zig Software Foundation 捐款!