Building Statically Linked Go Executables with CGO and Zig

https://news.ycombinator.com/rss Hits: 16
Summary

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"...

First seen: 2025-03-28 16:25

Last seen: 2025-03-29 16:29