I’m trying to figure out what would prevent zig build from bringing in libc. (To satisfy my curiosity. Zig 0.17.0 on Macos from times past.)
What do I have to change in build.zig to make zig build complain about either not finding stdio.h or printf (or both)? (And why?)
To my surprise, this still builds and runs - adding the flag "-ffreestanding" would finally give me a complaint about not finding _main:
build.zig
const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "program",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = false,
.link_libcpp = false,
.no_builtin = true,
}),
});
exe.root_module.addCSourceFiles(.{
.files = &.{"main.cpp"},
.flags = &.{
"-nostdlib",
"-nostdinc",
},
});
b.installArtifact(exe);
}
main.cpp
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hi!\n");
return 0;
}
Interesting, it doesn’t build for me (Zig 0.17.0, Debian 13).
zig build
install
└─ install program
└─ compile exe program debug native 1 errors
./main.cpp:1:10: error: 'stdio.h' file not found
#include <stdio.h>
^~~~~~~~~~
error: 1 compilation errors
failed command: /home/vincent/.local/lib/zig-x86_64-linux-0.17.0/zig build-exe -cflags -nostdlib -nostdinc -- ./main.cpp -fno-builtin -Odebug -Mroot --cache-dir .zig-cache --global-cache-dir /home/vincent/.cache/zig --build-root . --name program --zig-lib-dir /home/vincent/.local/lib/zig-x86_64-linux-0.17.0/lib/ --listen=-
Build Summary: 0/3 steps succeeded (1 failed)
install transitive failure
└─ install program transitive failure
└─ compile exe program debug native 1 errors
Setting .link_libc = true allows it to build and run as expected.
P.S. That’s C code, so you should call it main.c.
alanza
October 11, 2026, 2:30pm
3
you can’t not link libc on macOS, because libc is required for doing syscalls on that target
i think in this case it should return an error instead of quietly linking with it regardless of the setting
alanza
October 11, 2026, 4:48pm
5
seems like a reasonable thing to file an issue for!
Same as all those *BSD… Libc is required for system calls.
Thanks for the replies. Very helpful. On (Arch) Linux, as expected, toggling .link_libc between true and false (same as default it seems) does make the code compile or not. All the other flags I’ve included in my build.zig are irrelevant YOLO noise and not relevant related to my specific question.
(Btw using cpp because I’m handmade-ing 99.9% C with 0.1% C++ .)