Enable incremental compilation

This gets us incremental compilation and a fast feedback loop.
Instead of a `check` step, this depends on `-Dno-bin`.

Note, we should look into [per-build config](https://zigtools.org/zls/configure/per-build/)
and switching back to simply `check` at some point.
Currently that doesn't seem to play nice with `-fincremental`.
This commit is contained in:
Brendan Hansknecht 2025-03-13 20:31:52 -07:00
parent be24fbdcfd
commit f2fb7a519d
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
4 changed files with 76 additions and 45 deletions

View file

@ -23,7 +23,7 @@ jobs:
run: |
# -Dllvm incurs a costly download step, leave that for later.
# Just the do super fast check step for now.
zig build check -Dfuzz
zig build -Dno-bin -Dfuzz
zig-tests:
needs: check-zig

3
.gitignore vendored
View file

@ -25,9 +25,6 @@
target
generated-docs
# todo remove after upgrade to zig 0.13.0
zig-cache
zig-out
.zig-cache
.direnv

View file

@ -15,7 +15,6 @@ pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const strip = b.option(bool, "strip", "Omit debug information");
const check_step = b.step("check", "Check roc binaries compile");
const run_step = b.step("run", "Build and run the roc cli");
const test_step = b.step("test", "Run all tests included in src/tests.zig");
const fmt_step = b.step("fmt", "Format all zig code");
@ -23,6 +22,7 @@ pub fn build(b: *std.Build) void {
const snapshot_step = b.step("snapshot", "Run the snapshot tool to update snapshot files");
// llvm configuration
const no_bin = b.option(bool, "no-bin", "Skip emitting binaries (important for fast incremental compilation)") orelse false;
const use_system_llvm = b.option(bool, "system-llvm", "Attempt to automatically detect and use system installed llvm") orelse false;
const enable_llvm = b.option(bool, "llvm", "Build roc with the llvm backend") orelse use_system_llvm;
const user_llvm_path = b.option([]const u8, "llvm-path", "Path to llvm. This path must contain the bin, lib, and include directory.");
@ -34,17 +34,19 @@ pub fn build(b: *std.Build) void {
b.addSearchPrefix(b.pathJoin(&.{ path, "bin" }));
}
const install_exe = addMainExe(b, target, optimize, strip, enable_llvm, use_system_llvm, user_llvm_path) orelse return;
const check_exe = addMainExe(b, target, optimize, strip, enable_llvm, use_system_llvm, user_llvm_path) orelse return;
check_step.dependOn(&check_exe.step);
const roc_exe = addMainExe(b, target, optimize, strip, enable_llvm, use_system_llvm, user_llvm_path) orelse return;
b.installArtifact(install_exe);
const run_cmd = b.addRunArtifact(install_exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
if (no_bin) {
b.getInstallStep().dependOn(&roc_exe.step);
} else {
b.installArtifact(roc_exe);
const run_cmd = b.addRunArtifact(roc_exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
run_step.dependOn(&run_cmd.step);
}
run_step.dependOn(&run_cmd.step);
// Add snapshot tool
const snapshot_exe = b.addExecutable(.{
@ -54,15 +56,19 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
.link_libc = true,
});
b.installArtifact(snapshot_exe);
if (no_bin) {
b.getInstallStep().dependOn(&snapshot_exe.step);
} else {
b.installArtifact(snapshot_exe);
const run_snapshot = b.addRunArtifact(snapshot_exe);
// Add a step to run the snapshot tool
const run_snapshot = b.addRunArtifact(snapshot_exe);
run_snapshot.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_snapshot.addArgs(args);
// Add a step to run the snapshot tool
run_snapshot.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_snapshot.addArgs(args);
}
snapshot_step.dependOn(&run_snapshot.step);
}
snapshot_step.dependOn(&run_snapshot.step);
const all_tests = b.addTest(.{
.root_source_file = b.path("src/test.zig"),
@ -70,10 +76,11 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
.link_libc = true,
});
check_step.dependOn(&all_tests.step);
const run_tests = b.addRunArtifact(all_tests);
test_step.dependOn(&run_tests.step);
if (!no_bin) {
const run_tests = b.addRunArtifact(all_tests);
test_step.dependOn(&run_tests.step);
}
// Fmt zig code.
const fmt_paths = .{ "src", "build.zig" };
@ -116,7 +123,7 @@ pub fn build(b: *std.Build) void {
fuzz,
build_afl,
use_system_afl,
check_step,
no_bin,
target,
optimize,
name,
@ -129,7 +136,7 @@ fn add_fuzz_target(
fuzz: bool,
build_afl: bool,
use_system_afl: bool,
check_step: *Step,
no_bin: bool,
target: ResolvedTarget,
optimize: OptimizeMode,
name: []const u8,
@ -148,34 +155,28 @@ fn add_fuzz_target(
const name_exe = b.fmt("fuzz-{s}", .{name});
const name_repro = b.fmt("repro-{s}", .{name});
const run_repro_step = b.step(name_repro, b.fmt("run fuzz reproduction for {s}", .{name}));
const install_repro = b.addExecutable(.{
const repro_exe = b.addExecutable(.{
.name = name_repro,
.root_source_file = b.path("src/fuzz-repro.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
install_repro.root_module.addImport("fuzz_test", fuzz_obj.root_module);
b.installArtifact(install_repro);
repro_exe.root_module.addImport("fuzz_test", fuzz_obj.root_module);
if (no_bin) {
b.getInstallStep().dependOn(&repro_exe.step);
} else {
b.installArtifact(repro_exe);
const run_cmd = b.addRunArtifact(install_repro);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
const run_cmd = b.addRunArtifact(repro_exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
run_repro_step.dependOn(&run_cmd.step);
}
run_repro_step.dependOn(&run_cmd.step);
const check_repro = b.addExecutable(.{
.name = name_repro,
.root_source_file = b.path("src/fuzz-repro.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
check_repro.root_module.addImport("fuzz_test", fuzz_obj.root_module);
check_step.dependOn(&check_repro.step);
if (fuzz and build_afl) {
if (fuzz and build_afl and !no_bin) {
const fuzz_step = b.step(name_exe, b.fmt("Generate fuzz executable for {s}", .{name}));
b.default_step.dependOn(fuzz_step);

View file

@ -21,3 +21,36 @@ This table provides a summary of progress for the zig compiler re-write and shou
- 🚧 Work Started
- 🪫 Tests Passing
- 🔋 Polished
## Fast Feedback Loop
The roc zig compiler can have a very fast feedback loop. We support zigs incremental compilation and watch mode.
By avoiding generating final executables, we can build and typecheck much much faster.
Try it with `zig build -Dno-bin -fincremental --watch`
### Expanding to ZLS
This fast config can also be used with `zls`. Simply follow these steps:
1. run `zls --version` and make sure it is `0.14.0`.
2. run `zls env` and grab the `config_file` path.
3. Edit the config file to include
```json
{
"enable_build_on_save": true,
"build_on_save_args": ["-Dno-bin", "-fincremental"]
}
```
4. Advised, also changing the cache dir, I use `--cache-dir .zig-cache/zls`.
Otherwise, zig commands run manually can lead to the lsp breaking and requiring a restart.
5. Optionally, add `-Dfuzz` above as well to get type checking of fuzz scripts as well.
6. Note, I had to fully delete my `.zig-cache` to get `zls` to start.
Make sure to check the logs if you aren't geting type failures.
7. Enjoy better lsp results.
### Simply testing feedback loop
Sadly, this is not nearly as fast due to building binaries.
One day, we will get dev zig backends, and it should be fast.
Try it with `zig build test -fincremental --watch`