Skip to content

std.build

build.fels defines build :: fn(b: Build); runs in the comptime VM

pub Build :: struct {
id: i32,
}
pub Artifact :: struct {
id: i32,
}
pub Step :: struct {
id: i32,
}

named step: deps first, then its actions in order; paths relative to build.fels

pub depends_on :: fn(self: Step, artifact: Artifact)

build artifact before this step’s actions

pub after :: fn(self: Step, other: Step)

run other before this step

pub command :: fn(self: Step, program: []const u8) -> Command

program on PATH or relative to build.fels; nonzero exit stops the build

pub run :: fn(self: Step, artifact: Artifact) -> Command

build artifact (from this build) and run it, like command

pub copy_file :: fn(self: Step, src: []const u8, dest: []const u8)
pub copy_dir :: fn(self: Step, src: []const u8, dest: []const u8)

copy a folder recursively

pub write_file :: fn(self: Step, path: []const u8, text: []const u8)
pub remove :: fn(self: Step, path: []const u8)

remove a file or a folder recursively

pub print :: fn(self: Step, text: []const u8)

print a line when the step runs

pub Command :: struct {
id: i32,
}

program run by a step

pub arg :: fn(self: Command, text: []const u8)
pub arg_output :: fn(self: Command, artifact: Artifact)

artifact’s output path as an arg; built first only if the step depends on it

pub cwd :: fn(self: Command, dir: []const u8)

working dir, relative to build.fels (default: its folder)

pub env :: fn(self: Command, key: []const u8, value: []const u8)

env var, on top of fels build’s environment

pub Optimize :: enum {
debug,
release_safe,
release_fast,
release_small,
}

all but release_fast keep runtime checks; release_safe = release() = –release release_fast: no checks, so OOB, null, div by 0, big shifts are UB; overflow wraps

pub Subsystem :: enum {
console,
windows,
}
pub executable :: fn(self: Build, name: []const u8, root: []const u8) -> Artifact

executable; root is the entry source

pub shared :: fn(self: Build, name: []const u8, root: []const u8) -> Artifact

shared library (.dll)

pub static :: fn(self: Build, name: []const u8, root: []const u8) -> Artifact

static library (.lib)

pub object :: fn(self: Build, name: []const u8, root: []const u8) -> Artifact

object file (.o), no link step

pub optimize :: fn(self: Artifact, level: Optimize)
pub debug :: fn(self: Artifact)
pub release_safe :: fn(self: Artifact)
pub release_fast :: fn(self: Artifact)
pub release :: fn(self: Artifact)
pub release_small :: fn(self: Artifact)
pub link :: fn(self: Artifact, lib: []const u8)

link a system/import lib by name, no extension (“raylib”); once per lib

pub link_artifact :: fn(self: Artifact, lib: Artifact)

link a lib from this build; built first; a shared lib’s DLL lands next to the output

pub system_library :: fn(self: Artifact, name: []const u8)

alias for link

pub lib_path :: fn(self: Artifact, dir: []const u8)

add a lib search dir

pub link_flag :: fn(self: Artifact, flag: []const u8)

raw linker flag, e.g. “/DEBUG”

pub link_libc :: fn(self: Artifact)

link host libc (windows: UCRT + vcruntime; linux: dynamic glibc); same as –libc

pub LinkMode :: enum {
dynamic,
static,
}

.dynamic (default): import lib, ship the runtime lib; .static: archive + C runtime

pub link_mode :: fn(self: Artifact, mode: LinkMode)
pub dynamic :: fn(self: Artifact)
pub static_link :: fn(self: Artifact)
pub runtime_file :: fn(self: Artifact, path: []const u8)

copy a runtime dep (a .dll) next to the output after building

pub no_default_libs :: fn(self: Artifact)

skip a static C lib’s /DEFAULTLIB deps; you then link every system lib yourself

pub subsystem :: fn(self: Artifact, sub: Subsystem)

PE subsystem: console window or not

pub console :: fn(self: Artifact)

console app (default)

pub windowed :: fn(self: Artifact)

GUI app, no console window

pub entry :: fn(self: Artifact, symbol: []const u8)

linker entry symbol (default: the runtime’s mainCRTStartup)

pub stack_size :: fn(self: Artifact, bytes: u64)

stack size in bytes

pub Target :: enum {
windows,
linux,
linux_gnu,
uefi,
freestanding,
}

.linux: static ELF, no libc; .linux_gnu: glibc via sysroot; no libs for linux yet .uefi: a UEFI application (name.efi); .freestanding: an ELF with no os under it (name.elf)

pub Arch :: enum {
x86_64,
aarch64,
}

.aarch64 for a .uefi or .freestanding target; the rest are x86_64

pub arch :: fn(self: Artifact, a: Arch)
pub target :: fn(self: Artifact, t: Target)
pub sysroot :: fn(self: Artifact, dir: []const u8)

folder with libc.so.6 and the dynamic linker, for .linux_gnu

pub strip :: fn(self: Artifact)

drop the symbol table (linux; windows output has none)

pub Os :: enum {
windows,
linux,
macos,
other,
}
pub host_os :: fn(self: Build) -> Os

OS fels build runs on

pub output :: fn(self: Artifact, path: []const u8)

output path (default: from the name)

pub out_dir :: fn(self: Artifact, dir: []const u8)

output dir for this artifact; overrides out_root

pub version :: fn(self: Artifact, v: []const u8)

semver, shown in the build summary

pub description :: fn(self: Artifact, text: []const u8)

shown by –list

pub install :: fn(self: Artifact)

mark for fels build install: exes/DLLs to bin/, static/import libs to lib/

pub define :: fn(self: Artifact, name: []const u8, value: []const u8)

const in the generated build_options module; importable even with no defines

pub define_int :: fn(self: Artifact, name: []const u8, value: i64)
pub define_bool :: fn(self: Artifact, name: []const u8, value: bool)
pub add_module :: fn(self: Artifact, name: []const u8, dir: []const u8)

named import root: #import name.x reads dir/x.fels, #import name dir/name.fels

pub require_path :: fn(self: Build, name: []const u8, dir: []const u8) -> i32

dep from a local dir; its build.fels runs sandboxed

pub require_git :: fn(self: Build, name: []const u8, url: []const u8) -> i32

dep fetched from git (no revision pinning yet)

pub depend :: fn(self: Artifact, dep: i32)

self depends on dep (id from require_*)

pub provide_lib_path :: fn(self: Build, dir: []const u8)

lib dir for the users’ linker, relative to this build.fels

pub provide_link :: fn(self: Build, lib: []const u8)

lib every user artifact links, no extension (“winmm”)

pub provide_runtime_file :: fn(self: Build, path: []const u8)

file copied next to the users’ output (a DLL), relative to this build.fels

pub workspace :: fn(self: Build, name: []const u8)

workspace name, shown in the build summary

pub install_prefix :: fn(self: Build, dir: []const u8)

install dir, relative to build.fels (default “dist”); –prefix overrides

pub install_file :: fn(self: Build, src: []const u8, dest: []const u8)

copy a file into the install prefix

pub install_dir :: fn(self: Build, src: []const u8, dest: []const u8)

copy a folder recursively into the install prefix

pub out_root :: fn(self: Build, dir: []const u8)

default output dir for all artifacts; per-artifact out_dir wins

pub summary :: fn(self: Build)

print a summary of every artifact after the build

pub option_bool :: fn(self: Build, name: []const u8, default: bool, help: []const u8) -> bool

-Dname or -Dname=true|false (yes/no, on/off, 1/0)

pub option_int :: fn(self: Build, name: []const u8, default: i64, help: []const u8) -> i64

-Dname=; decimal or 0x/0o/0b

pub option_string :: fn(self: Build, name: []const u8, default: []const u8, help: []const u8) -> []const u8

-Dname=

pub option_choice :: fn(self: Build, name: []const u8, choices: []const u8, default: []const u8, help: []const u8) -> []const u8

-Dname=, one of choices (“a|b|c”)

pub option :: fn(self: Build, name: []const u8) -> bool

true if -Dname was passed

pub option_str :: fn(self: Build, name: []const u8, default: []const u8) -> []const u8

value of -Dname=value, else default

pub run_step :: fn(self: Build, name: []const u8, target: Artifact) -> Command

run step: build target, run it with the args after --; returns its Command

pub step :: fn(self: Build, name: []const u8, description: []const u8) -> Step

named step; see Step

pub command :: fn(self: Build, name: []const u8, program: []const u8) -> Command

step that runs one program

pub default_step :: fn(self: Build, step: Step)

what bare fels build runs, instead of the default artifact

pub after :: fn(self: Artifact, step: Step)

run step before building this artifact (codegen)

pub test_dir :: fn(self: Build, name: []const u8, dir: []const u8) -> Tests

test step: each .fels in dir runs as a program, exit 0 passes; -- <text> filters

pub Tests :: struct {
id: i32,
}
pub recursive :: fn(self: Tests)

also the tests in subfolders

pub filter :: fn(self: Tests, text: []const u8)

only test files whose path contains text; repeatable

pub optimize :: fn(self: Tests, level: Optimize)

optimization level (default: debug, checks on)

pub link :: fn(self: Tests, lib: []const u8)

lib the tests link

pub link_artifact :: fn(self: Tests, lib: Artifact)

lib from this build; built before the tests run

pub default :: fn(self: Build, target: Artifact)

artifact bare fels build produces