# libc and Freestanding Builds

### libc and Freestanding Builds

A Zig target may use a C library, or it may use none.

These two targets are both Linux:

```text
x86_64-linux-gnu
x86_64-linux-musl
```

The difference is the ABI.

`gnu` means the program is built for glibc.

`musl` means the program is built for musl libc.

A third target has no C library:

```text
x86_64-linux-none
```

Here the ABI is `none`.

The C library matters when the program calls C code, links C libraries, uses the system allocator, starts through the normal C runtime, or depends on POSIX functions.

A simple Zig program can often avoid libc:

```zig
const std = @import("std");

pub fn main() void {
    std.debug.print("hello\n", .{});
}
```

Build it for Linux with glibc:

```sh
zig build-exe main.zig -target x86_64-linux-gnu
```

Build it for Linux with musl:

```sh
zig build-exe main.zig -target x86_64-linux-musl
```

Build it without libc:

```sh
zig build-exe main.zig -target x86_64-linux-none
```

The last form is a freestanding-style build. It removes many assumptions.

A hosted program can assume an operating system and normal process services. It can open files, read environment variables, allocate through the system, and exit through the normal runtime path.

A freestanding program cannot assume those things.

```zig
const std = @import("std");

pub fn main() !void {
    var file = try std.fs.cwd().createFile("out.txt", .{});
    defer file.close();

    try file.writeAll("hello\n");
}
```

This program is a hosted program. It assumes a current working directory and a filesystem.

A freestanding program is closer to this:

```zig
export fn entry() void {
    while (true) {}
}
```

There may be no `main`. There may be no filesystem. There may be no allocator. There may be no operating system to return to.

For freestanding work, the entry point depends on the environment. A bootloader, firmware, kernel, embedded board, or WebAssembly host may call a specific exported function.

```zig
export fn add(a: i32, b: i32) i32 {
    return a + b;
}
```

This is a common shape for WebAssembly or embedded-style code: export a small function with a known ABI.

The target says what world the program is being built for. The source must match that world.

Use libc when you need C libraries or system conventions. Avoid libc when you want a smaller, more controlled binary or when no C runtime exists.

The practical rule is simple: choose the narrowest target that still gives the program what it needs.

Exercise 17-13. Build the same program with `x86_64-linux-gnu` and `x86_64-linux-musl`.

Exercise 17-14. Try to build a filesystem program for a `freestanding` target and read the compiler error.

Exercise 17-15. Write an exported `add` function and compile it for `wasm32-freestanding-none`.

Exercise 17-16. Explain when a program needs libc.

