# Why does \`printf\` work even though \`link\_libc = false\`?

**URL:** <https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919>\
**Category:** Help\
**Tags:** c\
**Created:** [October 11, 2026, 12:19pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919 "2026-10-11T12:19:44Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![felixrabe](https://ziggit.dev/user_avatar/ziggit.dev/felixrabe/32/5355_2.png) [@felixrabe](https://ziggit.dev/u/felixrabe)\
**Post date:** [October 11, 2026, 12:19pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919/1 "2026-10-11T12:19:45Z")

</div>

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**

```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**

```cpp
#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Hi!\n");
    return 0;
}

```

---

<div class="post-metadata">

**Author:** ![vincentd](https://ziggit.dev/user_avatar/ziggit.dev/vincentd/32/9870_2.png) [@vincentd](https://ziggit.dev/u/vincentd)\
**Post date:** [October 11, 2026, 2:23pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919/2 "2026-10-11T14:23:37Z")

</div>

Interesting, it doesn’t build for me (Zig 0.17.0, Debian 13).

```console
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`.

---

<div class="post-metadata">

**Author:** ![alanza](https://ziggit.dev/user_avatar/ziggit.dev/alanza/32/6006_2.png) [@alanza](https://ziggit.dev/u/alanza)\
**Post date:** [October 11, 2026, 2:30pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919/3 "2026-10-11T14:30:36Z")

</div>

you can’t _not_ link libc on macOS, because libc is required for doing syscalls on that target

---

<div class="post-metadata">

**Author:** ![naxlavun](https://ziggit.dev/user_avatar/ziggit.dev/naxlavun/32/7596_2.png) [@naxlavun](https://ziggit.dev/u/naxlavun)\
**Post date:** [October 11, 2026, 4:23pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919/4 "2026-10-11T16:23:20Z")

</div>

i think in this case it should return an error instead of quietly linking with it regardless of the setting

---

<div class="post-metadata">

**Author:** ![alanza](https://ziggit.dev/user_avatar/ziggit.dev/alanza/32/6006_2.png) [@alanza](https://ziggit.dev/u/alanza)\
**Post date:** [October 11, 2026, 4:48pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919/5 "2026-10-11T16:48:10Z")

</div>

seems like a reasonable thing to file an issue for!

---

<div class="post-metadata">

**Author:** ![IceGuye](https://ziggit.dev/letter_avatar_proxy/v4/letter/i/b782af/32.png) [@IceGuye](https://ziggit.dev/u/IceGuye)\
**Post date:** [October 11, 2026, 6:50pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919/6 "2026-10-11T18:50:49Z")

</div>

Same as all those \*BSD… Libc is required for system calls.

---

<div class="post-metadata">

**Author:** ![felixrabe](https://ziggit.dev/user_avatar/ziggit.dev/felixrabe/32/5355_2.png) [@felixrabe](https://ziggit.dev/u/felixrabe)\
**Post date:** [October 12, 2026, 11:35pm UTC](https://ziggit.dev/t/why-does-printf-work-even-though-link-libc-false/17919/7 "2026-10-12T23:35:39Z")

</div>

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++ 🙂 .)
