Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Artifacts, Modules, and Generated Files

The build graph tracks three kinds of compilable or producible outputs: artifacts, modules, and generated files.

Artifacts

Artifacts are the primary compiled outputs of a package.

KindMethodOutput
Executablegraph.add_exeBinary
Static librarygraph.add_static_lib.a / .lib
Shared librarygraph.add_shared_lib.so / .dylib
Test bundlegraph.add_testRunnable test binary

All artifact constructors accept the same base config record:

var app = graph.add_exe({
    name     = "app",      // required: output name
    root     = "src/main.fol",  // required: entry-point source file
    target   = target,     // optional: Target handle
    optimize = optimize,   // optional: Optimize handle
});

name must be lowercase. Allowed characters: a-z, 0-9, -, _, ..

Artifact Name Validation

The build system validates artifact names at evaluation time. Invalid names (uppercase, spaces, special characters) produce a build error.

Linking

Static and shared libraries can be linked into executables using artifact.link(dep):

var core = graph.add_static_lib({ name = "core", root = "src/core/lib.fol" });
var app  = graph.add_exe({ name = "app", root = "src/main.fol" });
app.link(core);

Typed system-library requests can be linked the same way:

var ssl = graph.add_system_lib({ name = "ssl", mode = "dynamic" });
app.link(ssl);

Framework-style requests use the same surface:

var metal = graph.add_system_lib({
    name = "Metal",
    framework = true,
});
app.link(metal);

Linking is transitive through the graph. If core itself links utils, app will also see utils.

Installation

Any artifact can be marked for installation:

graph.install(app);
graph.install(core);

Files and directories can also be installed directly:

var defaults = graph.file_from_root("config/defaults.toml");
var assets = graph.dir_from_root("assets");
graph.install_file({ name = "defaults", source = defaults });
graph.install_dir({ name = "assets", source = assets });

Modules

Modules are named source units that can be shared across artifacts without being standalone binaries.

var utils = graph.add_module({ name = "utils", root = "src/utils.fol" });
var app   = graph.add_exe({ name = "app", root = "src/main.fol" });
app.import(utils);

artifact.import(module) makes the module visible in the importing artifact’s source scope. Equivalent to Zig’s artifact.root_module.addImport(name, dep).

Modules from dependencies are accessed via dep.module(name):

var build  = .build();
var dep    = build.add_dep({ alias = "mylib", source = "loc", target = "../mylib" });
var logger = dep.module("logger");
app.import(logger);

dep.module(name) resolves only explicitly exported build modules. It does not change the ordinary package import rules used in source files.

Generated Files

Generated files are outputs produced before compilation. They must be declared in the graph so the build system knows to produce them and what depends on them.

Kinds

KindMethodDescription
Writegraph.write_fileWritten with literal string contents
Copygraph.copy_fileCopied from a source path
Tool outputgraph.add_system_toolProduced by an external tool
Tool dirgraph.add_system_tool_dirProduced as a generated directory
Codegengraph.add_codegenProduced by the FOL codegen pipeline
Codegen dirgraph.add_codegen_dirProduced as a generated directory
Captured runrun.capture_stdout()Stdout of a run step

Connecting Generated Files

A generated file must be connected to the graph entity that depends on it.

Attach to a step (the step triggers its production):

var schema = graph.file_from_root("schema/api.yaml");
var defaults = graph.write_file({
    name = "defaults",
    path = "gen/defaults.txt",
    contents = "strict",
});
var gen  = graph.add_system_tool({
    tool = "flatc",
    args = { "--fol" },
    file_args = { schema, defaults },
    env = { MODE = "strict" },
    output = "gen/types.fol",
});
var step = graph.step("proto");
step.attach(gen);

Add to an artifact (artifact cannot compile without it):

var schema = graph.add_codegen({
    kind   = "schema",
    input  = "schema/api.yaml",
    output = "gen/api.fol",
});
var app = graph.add_exe({ name = "app", root = "src/main.fol" });
app.add_generated(schema);

Capture stdout and feed it as an arg to another run:

var gen_tool   = graph.add_exe({ name = "gen", root = "tools/gen.fol" });
var gen_run    = graph.add_run(gen_tool);
var gen_output = gen_run.capture_stdout();

var app_run = graph.add_run(app);
app_run.add_file_arg(gen_output);

Generated directories can be installed or exported as dirs:

var assets = graph.add_system_tool_dir({
    tool = "assetpack",
    output_dir = "gen/assets",
});

build.export_dir({ name = "assets", dir = assets });
graph.install_dir({ name = "assets", source = assets });

Steps

Steps are named build phases. The build system has several implicit steps (build, run, test, install). Custom steps are declared with graph.step.

var docs = graph.step("docs", "Generate documentation");

Steps are executed in dependency order. A step depends on another step via step.depend_on:

var compile = graph.step("compile");
var docs    = graph.step("docs");
docs.depend_on(compile);

Default Step Bindings

When only one executable exists in a package, the build system automatically binds it to the default build and run steps. When multiple executables exist, explicit step bindings are required via graph.add_run(artifact).

Selecting Steps at the Command Line

fol code build         # run the install steps
fol code build docs    # run the "docs" step
fol code run           # run the default run step
fol code run --step serve  # run the "serve" step
fol code test          # run test steps

Graph Validation

After the build program executes, the graph is validated:

  • No step dependency cycles
  • All artifact inputs (modules, generated files) are resolvable
  • Install targets point to declared artifacts

Validation errors are reported as build evaluation errors before any compilation begins.