# Linking Libraries

### Linking Libraries

Calling a C function is only half the job. The linker must also find the code for that function.

A C declaration tells Zig what exists:

```zig
extern fn add(a: c_int, b: c_int) c_int;
```

But the declaration does not contain the function body. The body must come from a C source file, an object file, a static library, a shared library, or the system C library.

The smallest case is a C source file.

```c
int add(int a, int b) {
    return a + b;
}
```

Save it as `add.c`.

The Zig program:

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

extern fn add(a: c_int, b: c_int) c_int;

pub fn main() void {
    std.debug.print("{d}\n", .{add(3, 4)});
}
```

Build both files together:

```sh
zig build-exe main.zig add.c
```

Run the result:

```sh
./main
```

The output is:

```text
7
```

Zig compiles the C file and links it into the executable.

A C file may also be compiled first:

```sh
zig cc -c add.c -o add.o
```

Then the object file can be linked:

```sh
zig build-exe main.zig add.o
```

This is useful when object files come from another build system.

A static library is an archive of object files. On Unix-like systems, its name often looks like this:

```text
libmathlib.a
```

If the file is in the current directory, link it directly:

```sh
zig build-exe main.zig libmathlib.a
```

Or use a library search path and library name:

```sh
zig build-exe main.zig -L. -lmathlib
```

`-L.` adds the current directory to the library search path.

`-lmathlib` asks the linker to find a library named `mathlib`. On Unix-like systems, this usually means a file named `libmathlib.a` or `libmathlib.so`.

A shared library is loaded by the operating system at run time. On Unix-like systems it often has this form:

```text
libmathlib.so
```

On macOS:

```text
libmathlib.dylib
```

On Windows:

```text
mathlib.dll
```

The build command is similar:

```sh
zig build-exe main.zig -L. -lmathlib
```

At run time, the operating system must also be able to find the shared library. That is separate from compiling and linking.

For functions from the C standard library, link libc:

```sh
zig build-exe main.zig -lc
```

For example:

```zig
const c = @cImport({
    @cInclude("stdio.h");
});

pub fn main() void {
    _ = c.puts("hello");
}
```

Build it:

```sh
zig build-exe main.zig -lc
```

Without `-lc`, the declarations may still be known, but the final executable may fail to link because the implementation is missing.

When using `build.zig`, linking is written as part of the build graph.

```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 = "demo",
        .root_module = b.createModule(.{
            .root_source_file = b.path("main.zig"),
            .target = target,
            .optimize = optimize,
        }),
    });

    exe.addCSourceFile(.{
        .file = b.path("add.c"),
        .flags = &.{},
    });

    b.installArtifact(exe);
}
```

Now build with:

```sh
zig build
```

To link libc in `build.zig`:

```zig
exe.linkLibC();
```

To link a system library:

```zig
exe.linkSystemLibrary("m");
```

To add an include path:

```zig
exe.addIncludePath(b.path("include"));
```

To add a library path:

```zig
exe.addLibraryPath(b.path("lib"));
```

Linking is target-dependent. The same Zig source may need different libraries or different names on Linux, macOS, Windows, or a freestanding target.

Good Zig code keeps this difference in the build file, not scattered through the program.

The source file should say what functions it calls. The build file should say where those functions come from.

