使用CGO和Zig构建静态链接的Go可执行文件
Building Statically Linked Go Executables with CGO and Zig

原始链接: https://calabro.io/zig-cgo

本指南演示如何使用Zig创建静态链接的Go可执行文件,该文件利用CGO依赖项。首先,它在Zig中创建一个简单的静态库,包含一个`my_zig_function`函数和相应的C头文件(`zig_lib.h`)。使用`zig build`构建Zig库。 然后,Go程序使用CGO导入C库,并指定静态链接所需的链接器标志。此过程的核心是使用特定的环境变量编译Go可执行文件:`CC`设置为`zig cc`用于交叉编译,`CGO_ENABLED`启用CGO,`CGO_LDFLAGS`设置静态链接标志,`GOOS`和`GOARCH`定义目标平台。最后,使用`-a`标志调用`go build`强制重新构建包,并使用`-ldflags`将`-static`传递给外部链接器。 然后使用`ldd`验证生成的执行文件是否为静态链接,确认它没有动态依赖项。这种方法可以创建自包含的可执行文件,避免运行时依赖性问题。

Hacker News 最新 | 往期 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 使用 CGO 和 Zig 构建静态链接的 Go 可执行文件 (calabro.io) 8 分,来自 todsacerdoti,1 小时前 | 隐藏 | 往期 | 收藏 | 讨论 加入我们,参加 6 月 16-17 日在旧金山举办的 AI 初创公司学校! 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系我们 搜索:
相关文章
  • Zig 中的 C 宏反射 2024-07-31
  • (评论) 2024-07-31
  • Gio UI – Go 的跨平台 GUI 2024-05-19
  • 我们应得的 Rust 调用约定 2024-04-20
  • (评论) 2024-07-16

  • 原文

    Building Statically Linked Go Executables with CGO and Zig

    This is a short post about how to create a statically linked Go executable that calls in to CGO dependencies using Zig. The full code for this post is available in this repo.

    By default, if you're using CGO, the executable you generate dynamically links, but I frequently want to statically link to avoid runtime errors.

    First, let's create a zig library, with zig init, then trim back the excess stuff it generates so we're left just with a simple static library. You can rm src/main.zig since we're not creating a zig executable.

    Next, we can trim build.zig to just:

    // 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);
    }
    

    We can leave the build.zig.zon file alone.

    Now, let's actually write a simple library function that uses the C ABI in src/root.zig:

    // src/root.zig
    const std = @import("std");
    
    pub export fn my_zig_function() void {
        std.debug.print("Hello from zig!\n", .{});
    }
    

    And its corresponding C header file named zig_lib.h:

    // zig_lib.h
    #pragma once
    
    void my_zig_function();
    

    That's it on the zig side! You can build the library now by simply running zig build.

    Let's write the Go program that calls it.

    // 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()
    }
    

    We'll now build the Go executable and statically link it with this bash command:

    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
    

    Let's check our work:

    $ ./main
    starting program
    Hello from zig!
    done
    
    $ ldd ./main
            not a dynamic executable
    

    Looks good to me!

    I'm incredibly grateful that I'm building at a time where our tools are getting extremely good. Go and Zig are both amazing!

    If you find this useful as I do, perhaps consider making a donation to the Zig Software Foundation!

    联系我们 contact @ memedata.com