Skip to content

Instantly share code, notes, and snippets.

@pfgithub
Last active January 15, 2021 17:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfgithub/d08da0bbe6fc95698a618e34dbb2b101 to your computer and use it in GitHub Desktop.
Save pfgithub/d08da0bbe6fc95698a618e34dbb2b101 to your computer and use it in GitHub Desktop.
build.zig

(written on zig version 0.7.1+d96f5b38a)

Basics

zig build <step> runs a specified step from the build.zig file. build.zig is a file written in zig that describes all the available things that can be built

An empty build file:

const std = @import("std");
const Builder = std.build.Builder;

pub fn build(b: *Builder) void {

}

Running zig build on this file will do nothing. zig build --help will show two available steps, install (default) and uninstall that both do nothing.

Building and running some code

Make a step to build the code and then a step to run the built code, then give commands to these steps

const std = @import("std");
const Builder = std.build.Builder;

pub fn build(b: *Builder) void {
    const target = b.standardTargetOptions(.{});
    const mode = b.standardReleaseOptions();

    const exe = b.addExecutable("exe_name", "src/main.zig");
    exe.setTarget(target);
    exe.setBuildMode(mode);
    exe.install();
}

A build-exe step is created (b.addExecutable), and then .install() adds it to the default zig build install step.

b.standardReleaseOptions() adds project specific options -Drelease-safe, -Drelease-fast, and -Drelease-small. These choose what optimization mode to build with, with the default being debug. exe.setBuildMode(mode) sets the -O flag on the build. -O Debug or -O ReleaseFast or … depending on what the mode is.

b.standardTargetOptions(.{}) adds the project specific option -Dtarget= so you can specify a cross-compiling target with zig build. zig build install -Dtarget=x86_64-linux-musl.

You can add your own options with b.option() but that is later.

Running the exe:

    const run_cmd = exe.run();
    run_cmd.step.dependOn(&exe.install_step.?.step);
    
    const run_step = b.step("run", "Run the project");
    run_step.dependOn(&run_cmd.step);

runs. The default build file made with zig init-exe uses run_step.dependOn(b.getInstallStep()), but if your build file has multiple executables this will require building all of them even if the run step only depends on one executable.

c stuff

system libraries with

    b.linkSystemLibrary("SDL2");
    b.linkSystemLibrary("fontconfig");

this searches your system sometimg. it might use pkg-config or some other tool on linux and similar tools on windows and mac.

c and c++ files can be added to the build with .addCSourceFile

    exe.addIncludeDir("src/c/");
    exe.addCSourceFile("src/c/code.c", &[_][]const u8{});

currently, all c files use the same include directories. there is no way to build c with one include directory and use a seperate set of include directories for zig code's @cInclude()

zig debug builds use the llvm undefined behaviour sanitizer, which some c code might crash with because it unknowingly uses undefined behaviour. This should be fixed, but the undefined behaviour sanitizer can be disabled in the meantime.

    exe.addCSourceFile("deps/some_broken_library.c", &[_][]const u8{"-fno-sanitize=undefined"});

b.option

const value = b.option([]const u8, "some-option", "option description")

this will add an option -Dsome-option=value, and whatever the user types for value is returned

it returns an optional in case the user doesn't specify an option, in which case you can have a default value or error

const renderer = b.option(enum{sdl, raylib}, "renderer", "renderer") orelse .raylib;
const value = b.option([]const u8, "value", "value") orelse {
    @panic("expected -Dvalue=…");
};

steps should not be added based on the result of options because that will break --help.

libraries and tests and formatting code

= b.addStaticLibrary("name", "src/main.zig")
    … = b.addTest("src/main.zig");
    … = b.addFmt(&[_][]const u8{"src", "build.zig"});

external commands

= b.addSystemCommand(&[_][]const u8{"touch", "hi.zig"});

default targets

    exe.setTarget(std.zig.CrossTarget.parse(.{ .arch_os_abi = "wasm32-freestanding" }) catch @panic("err"));

There might be a better way to do this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment