# A Static Library

### A Static Library

A library is code meant to be used by another program. In Zig, a library can be built from the same kind of source files as an executable. The difference is in how the build script exposes it.

We will make a small library named `mathx`.

It has one source file:

```text
src/mathx.zig
```

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

pub fn mul(a: i32, b: i32) i32 {
    return a * b;
}
```

The functions are marked `pub` so code outside the file can use them.

Now create `build.zig`.

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

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

    b.installArtifact(lib);
}
```

Build it:

```sh
zig build
```

The result is a static library in Zig's build output directory.

A static library is linked into the final program at build time. The executable receives the compiled code it uses. There is no separate dynamic library to load at run time.

A library is more useful with tests. Put the tests beside the code.

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

pub fn add(a: i32, b: i32) i32 {
    return a + b;
}

pub fn mul(a: i32, b: i32) i32 {
    return a * b;
}

test "add" {
    try std.testing.expectEqual(@as(i32, 30), add(10, 20));
}

test "mul" {
    try std.testing.expectEqual(@as(i32, 42), mul(6, 7));
}
```

The build script needs a test step.

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

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

    b.installArtifact(lib);

    const tests = b.addTest(.{
        .root_source_file = b.path("src/mathx.zig"),
        .target = target,
        .optimize = optimize,
    });

    const run_tests = b.addRunArtifact(tests);

    const test_step = b.step("test", "Run library tests");
    test_step.dependOn(&run_tests.step);
}
```

Run the tests:

```sh
zig build test
```

The test code is compiled only for the test artifact. It does not become part of the installed library.

A library can also expose a module for other Zig code. Add this to the build script:

```zig
const mathx_mod = b.addModule("mathx", .{
    .root_source_file = b.path("src/mathx.zig"),
});
```

A program in the same build can import that module.

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

pub fn main() void {
    const n = mathx.add(10, 20);
    std.debug.print("{d}\n", .{n});
}
```

The build script must connect the module to the executable.

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

exe.root_module.addImport("mathx", mathx_mod);

b.installArtifact(exe);
```

Now the full build script has both a library and a program that uses it.

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const mathx_mod = b.addModule("mathx", .{
        .root_source_file = b.path("src/mathx.zig"),
    });

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

    b.installArtifact(lib);

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

    exe.root_module.addImport("mathx", mathx_mod);

    b.installArtifact(exe);

    const tests = b.addTest(.{
        .root_source_file = b.path("src/mathx.zig"),
        .target = target,
        .optimize = optimize,
    });

    const run_tests = b.addRunArtifact(tests);

    const test_step = b.step("test", "Run library tests");
    test_step.dependOn(&run_tests.step);
}
```

This build has three separate outputs:

| Output | Purpose |
|---|---|
| static library | compiled library artifact |
| executable | program that imports the module |
| test artifact | test runner for the library |

The source file is the same. The build graph decides how it is used.

This is an important distinction in Zig. Source files do not declare themselves to be packages, libraries, or executables. The build script says what to build.

Exercise 20-21. Add a `sub` function and test it.

Exercise 20-22. Add a `div` function that returns an error on division by zero.

Exercise 20-23. Build the library in release mode.

Exercise 20-24. Add a second executable that uses the same module.

Exercise 20-25. Rename the module without renaming the library artifact.

