For some strange reason, my brain finds it difficult to really parse what goes on within build.zig
file.
I read that it is based on modeling the project as a directed acyclic graph (DAG) of steps, which are independently and concurrently run. But alas that does not help me much
So for example reading this page Zig Build System ⚡ Zig Programming Language I see this
const std = @import("std");
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "hello",
.root_source_file = b.path("hello.zig"),
.target = b.host,
});
b.installArtifact(exe);
const run_exe = b.addRunArtifact(exe);
const run_step = b.step("run", "Run the application");
run_step.dependOn(&run_exe.step);
}
The first confusion is, this is a function and that would be called, hence I read it in the imperative way I would read any function. But I believe this creates some confusion in my mind.
First question is how do I map what I type as part of zig build or run or whatever
to what is defined in this build.zig
file?
For example with package.json in yarn in javascript or make file, I can see the command defined and what instructions is should execute. But with this model if build.zig
, that happens when what command is executed is not clear.
For example when I run zig build
the project is built and the exe placed in the out directory. I believe the following code is responsible for that
const exe = b.addExecutable(.{
.name = "hello",
.root_source_file = b.path("hello.zig"),
.target = b.host,
});
b.installArtifact(exe);
But no where is it clear that running zig build
is what will trigger this. This becomes confusing when I read build.zig file of larger projects as it is difficult to read the zig.build file and know straight away the command I need run.
The second question is how to really understand this so called DAG. So for example in the code above, I could have the following interpretations:
// INTERPRETATION:
// When the build is executed, instruct the build system to build the source files
// with name, path to source and the target
const exe = b.addExecutable(.{
.name = "hello",
.root_source_file = b.path("hello.zig"),
.target = b.host,
});
// INTERPRETATION:
// Instructs the build system to copy the executable to a location
b.installArtifact(exe);
// INTERPRETATION:
// Instruct the build system to be able to run the exe.
// But I am confused. When I run `build run` how does this lead to this instruction?
const run_exe = b.addRunArtifact(exe);
// INTERPRETATION
// Now i am creating a generic step? But why. We did not need this for the `zig build`, why is this needed for `zig run`?
const run_step = b.step("run", "Run the application");
// INTERPRETATION
// instructs the build system to first run the `run_exe` step before running `run_step`.
// Question: But why? I mean all this is being defined in a `build()` function which I believe would be executed at some point, but how does running all the code here, leads to the ability to execute the generated zig binary when I run `zig run`?
run_step.dependOn(&run_exe.step);
}
Also looking into the return type of these functions I am confused, but I suspect understanding the return type is a clue to further understanding how the build system works.
In some cases, these function return void. In some case it returns *Step.???
and in some cases it returns just *Step
.
What are these return types and how does it tie into how the build system works?