Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

All the magic seems to happen in

    const lib = b.addLibrary(.{
        .linkage = .static,
        .name = "cgo_static_linking",
        .root_module = lib_mod,
    });
and

/* #cgo LDFLAGS: -L./zig-out/lib -lcgo_static_linking -static #include "zig_lib.h" */

Now I can only guess why it works. A bit of an explanation wouldn't hurt. Good post btw



Zig builds a statically linked library called "cgo_static_linking" from Zig sources. Zig places the artifact into "./zig-out/lib/cgo_static_linking.a" (or maybe some other extension). The library is exported with C ABI, which Go (cgo) compiler supports.

The #cgo line tells the Go compiler to add custom compilation flags: -l flag tells the compiler that you wish to link to a library called "cgo_static_linking" in to the binary. However, the cgo compiler can't find it since it is not in the default search paths for libraries. The -L option extends the library search path to "./zig-out/lib/", allowing "cgo_static_linking" to be found.

The "#include" line inserts the header file contents as-is into the source file (main.go), bringing the definition of the function available to the compiler. The compiler is then able to compile the Go source, and later link it with the other build artifacts to produce the final executable.

The key here is the "C ABI" which acts as common ground for both languages. The rest is just scaffolding to let the compilers find and connect appropriate files together.


Most of the magic is due to two things: 1. Zig comes with clang and musl (C library) for lots of architectures, so can be used for cross-compiling, even for non-Zig projects since clang can build C/C++ no problem 2. Musl is designed to be compatible with static linking (glibc is not), so it's the natural choice here too




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: