# Static and Dynamic Linking

### Static and Dynamic Linking

Linking is the step where the compiler connects your program with the code it depends on.

Your program may use code from:

```text
your own Zig files
the Zig standard library
C libraries
system libraries
third-party packages
```

After compilation, those pieces need to become one runnable program. The linker does that job.

There are two main styles:

```text
static linking
dynamic linking
```

Static linking copies library code into the final executable.

Dynamic linking keeps library code outside the executable and loads it when the program starts.

#### Static Linking

With static linking, the final executable contains the library code it needs.

That means the executable can often run without installing extra library files on the target machine.

For example, if your program uses a static library named:

```text
libmath.a
```

the linker copies the needed code from that library into your program.

The result is one larger executable.

Static linking is useful when you want simple deployment. You can copy one file to a server and run it.

#### Dynamic Linking

With dynamic linking, the final executable does not contain all library code.

Instead, it records that it needs a shared library.

Examples of shared libraries:

```text
Linux:   libssl.so
macOS:   libssl.dylib
Windows: ssl.dll
```

When your program starts, the operating system loads those libraries.

The result is usually a smaller executable, but the target machine must have the right shared libraries available.

#### Static vs Dynamic

| Linking style | What happens | Main benefit | Main cost |
|---|---|---|---|
| Static | Library code is copied into the executable | Easier deployment | Larger binary |
| Dynamic | Library code is loaded at runtime | Smaller binary, shared system libraries | Runtime dependency problems |

For beginner Zig projects, static linking is often simpler. For desktop apps, system integration, plugins, and large shared libraries, dynamic linking may be better.

#### A Simple Zig Executable

A normal executable starts like this:

```zig
const exe = b.addExecutable(.{
    .name = "hello",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    }),
});
```

If this program only uses Zig code, you usually do not need to think much about linking.

Linking becomes more visible when you use C libraries, system libraries, or when you choose static or dynamic outputs yourself.

#### Linking a C Source File

Zig can compile C code as part of the build.

Suppose your project looks like this:

```text
app/
  build.zig
  src/
    main.zig
    add.c
    add.h
```

The C file:

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

The header:

```c
int add(int a, int b);
```

In `build.zig`, you can add the C file:

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

Then link the C runtime if needed:

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

Now Zig builds the Zig code and the C code into the final executable.

#### Linking a System Library

Sometimes you need a library that already exists on the system.

For example, on Unix-like systems, you might link the math library:

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

This tells the linker to link against `libm`.

A more common real-world example is linking a library such as SQLite, OpenSSL, or zlib:

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

This assumes the target system or build environment has that library available.

If the library is missing, the link step fails.

#### Linking libc

C libraries often require libc.

In Zig, you can request libc with:

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

This matters when:

```text
you call C functions
you compile C source files
you link C libraries that depend on libc
```

Pure Zig programs may not need libc. That can make them easier to cross compile and deploy.

#### Static Libraries

A static library usually has one of these forms:

```text
Linux/macOS: libname.a
Windows:    name.lib
```

You can link a static library by adding its path and library name.

A simple pattern is:

```zig
exe.addLibraryPath(b.path("vendor/mylib/lib"));
exe.linkSystemLibrary("mylib");
```

If the linker finds a static version, it can link that.

For more direct control, projects often use Zig packages or build the static library as part of the same build.

#### Dynamic Libraries

A dynamic library usually has one of these forms:

```text
Linux:   .so
macOS:   .dylib
Windows: .dll
```

Dynamic linking means the executable expects that library to be available when it runs.

This can fail at runtime if the library cannot be found.

For example:

```text
error while loading shared libraries: libexample.so: cannot open shared object file
```

This does not mean your Zig code failed to compile. It means the operating system could not find a required dynamic library when starting the program.

#### Building a Static Library in Zig

Zig can build libraries too.

A static library build target looks like this:

```zig
const lib = b.addStaticLibrary(.{
    .name = "mylib",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    }),
});

b.installArtifact(lib);
```

This produces a static library artifact.

Static libraries are useful when you want other programs to link your code into their own executable.

#### Building a Dynamic Library in Zig

A dynamic library build target looks like this:

```zig
const lib = b.addSharedLibrary(.{
    .name = "mylib",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    }),
});

b.installArtifact(lib);
```

This produces a shared library.

A shared library is useful when code should be loaded by another program at runtime, or when multiple programs should share one installed copy of a library.

#### Exporting Functions from a Library

If you want C or another language to call a Zig function, export it:

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

The word `export` makes the function visible outside the compiled library or executable.

The type `c_int` is used for C ABI compatibility.

A dynamic library containing this function can be called from C, Python FFI, Rust FFI, or another host that can load C-compatible symbols.

#### Static Linking and Cross Compilation

Static linking is often useful with cross compilation.

For example:

```bash
zig build -Dtarget=x86_64-linux -Doptimize=ReleaseFast
```

If the result is mostly self-contained, deployment is easier.

But static linking becomes harder when the program depends on large C libraries or platform-specific system libraries.

The rule is simple: every linked library must match the target.

A macOS library cannot be linked into a Linux executable. A Linux x86_64 library cannot be linked into a Windows executable. An ARM library cannot be linked into an x86_64 executable.

#### Dynamic Linking and Deployment

Dynamic linking makes deployment more sensitive.

You need to answer:

```text
Which shared libraries does the program need?
Where will the operating system look for them?
Are the library versions compatible?
Are they installed on the target machine?
```

For server tools, this can be annoying.

For desktop applications, this may be normal.

For plugins, dynamic linking may be required.

#### Checking Linked Libraries

On Linux, you can inspect dynamic library dependencies with:

```bash
ldd ./hello
```

On macOS:

```bash
otool -L ./hello
```

On Windows, tools such as Dependency Walker or `dumpbin` can inspect DLL dependencies.

These tools help you see what your executable expects at runtime.

#### Build Mode and Linking

Optimization mode and linking are separate ideas.

This controls optimization:

```bash
zig build -Doptimize=ReleaseFast
```

This controls target:

```bash
zig build -Dtarget=x86_64-linux
```

Linking choices are usually described inside `build.zig`:

```zig
exe.linkLibC();
exe.linkSystemLibrary("sqlite3");
```

Do not confuse release mode with static linking. A release build can still use dynamic libraries. A debug build can still link statically.

#### Common Mistakes

A common mistake is assuming a program is fully self-contained because it compiled successfully.

Compilation and runtime loading are different. A dynamically linked program may compile correctly but fail to start on another machine.

Another common mistake is linking against a library for the host instead of the target during cross compilation.

Another mistake is forgetting `linkLibC()` when using C code or C libraries that require libc.

Another mistake is exporting Zig functions without C-compatible types when the function is meant to be called from C.

#### The Important Idea

Linking decides how your program connects with library code.

Static linking puts library code into the executable.

Dynamic linking loads library code at runtime.

In `build.zig`, the common linking calls are:

```zig
exe.linkLibC();
exe.linkSystemLibrary("name");
exe.addCSourceFile(.{
    .file = b.path("src/file.c"),
    .flags = &.{},
});
```

For pure Zig programs, linking is often simple. For C libraries, system libraries, cross compilation, and shared libraries, linking becomes one of the most important parts of the build.

