Zig build: How to stop after first error?

I searched Zig Build System ⚡ Zig Programming Language and found --summary none, but that still prints a lot of output for failed steps. I would like to take the errors one by one as they happen and not have all other error output printed as well.

I am using zig build 2>&1 | head -n 20 for now, but have to adjust the -n argument depending on output.

You’d have to use a custom test runner that stops on the first error, you can specify one in the addTest options.

You can just copy and modify the default test runner, found at [zig lib dir]/compiler/test_runner.zig.
You can get the zig lib dir from zig env

1 Like

Huh, thanks for mentioning, so the test runner would run zig build itself and then stop at the first error? Interesting, but I will keep my workaround for now.

No, the test runner is built as an executable by the build system with access to the tests of the module (and its imports if referenced) provided to it.

Each test is just a function that the test runner calls.

Ok, but I am missing something, I am trying to build a project, not run any tests?

omg, I completely miss interpreted your issue lol.

I only ever use --sumary to see more detailed info about tests.

For compile errors there is also zig build --prominent-compile-errors.

1 Like

To answer the actual question, depending on the errors, the compiler usually doesn’t print out a lot of errors.

I think you are referring to the verbose amount of information that is given, you can use --prominent-compile-errors to re-order the information so it is readable from bottom to top, instead of top to bottom which is the default.

--sumary controls displaying progress information for the various build tasks. Not the error output.

I tried that option as well, but I am still getting pages and pages of errors where I assume lots of later errors are consequences of prior errors.

Could you post some of the output you’re seeing?

zig build for GitHub - allyourcodebase/cpython: cpython ported to the zig build system

I want to see the first error only:

install
+- install generated/
   +- WriteFile lib\python3.12
      +- compile exe python Debug native
         +- run _freeze_module.py for 'Lib/runpy.py' (frozen_modules/runpy.h)
            +- WriteFile lib\python3.12
               +- compile exe bootstrap_python Debug native
                  +- run exe freeze_module (Python/frozen_modules/importlib._bootstrap.h)
                     +- compile exe freeze_module Debug native
                        +- add module sources/includes to freeze_module exe
                           +- run exe makesetup (gen)
                              +- run exe replace (Setup.stdlib)
                                 +- compile exe replace Debug native 1 errors
replace.zig:47:20: error: root source file struct 'Io' has no member named 'bufferedWriter'
    var bw = std.io.bufferedWriter(out_file.writer());
             ~~~~~~^~~~~~~~~~~~~~~
C:\Users\LeimgruberF\scoop\apps\zig\0.15.1\lib\std\Io.zig:1:1: note: struct declared here
const builtin = @import("builtin");
^~~~~
referenced by:
    callMain [inlined]: C:\Users\LeimgruberF\scoop\apps\zig\0.15.1\lib\std\start.zig:627:37
    WinStartup: C:\Users\LeimgruberF\scoop\apps\zig\0.15.1\lib\std\start.zig:443:53
    2 reference(s) hidden; use '-freference-trace=4' to see all references

...

[a lot of more errors]

...

First is a tree of tasks from the build system, important as you could and likely do have multiple compilation tasks, you need to know which the error comes from.

Then is a single error and a note which is additional information, in this case where Io is defined.

Io is a file, so it’s pointing to the first line of the file as it’s definition, it can’t point to an @import as imports can be cyclical and repeated, so there is no import that is the origin.

Lastly, two places Io is referenced, as well as 2 hidden references as the information is too long. Which you can configure with -freference-trace, if you don’t specify a limit it will show all references.

Thanks for breaking that down in detail. But my point is that I only want to see that error, not the hundreds of lines of errors that follow :slight_smile: see also the linked Pastebin paste.

the amount of errors have to do with building Python. According to the readme, no system dependencies are needed if your build with musl.

Supports building a static python executable for linux with the musl abi (i.e. zig build -Dtarget=x86_64-linux-musl ).

are you adding the target flag when you build?

I see the point about system dependencies and amount of errors related to building Python, as building Python is what the zig build is all about. But I fail to see how that is related to my question?

FWIW, I am building on Windows, so zig build -Dtarget=x86_64-windows-gnu.

Edit 2: Turns out I completely misunderstood how this works. See below. Thanks @castholm.

Leaving this here for posterity

zig build-( lib | exe | obj ) has an --error-limit [num] option which can be set in build.zig by setting the .error_limit field on a Step.Compile:

const exe = b.addExecutable(.{
    .name = "example",
    .root_module = b.createModule(.{
        .root_source_file = b.path("build/example.zig"),
        .target = b.graph.host,
        .optimize = optimize,
    }),
});
exe.error_limit = 1

I don’t think there’s a way to set it globally in the build system except by vendoring std.Build. It defaults to a practically infinite value of std.math.maxInt(u16).

(edits: damn I should proofread more, excuse me)

I’m sorry that you’re getting so many unhelpful replies. The truth is that there simply isn’t any built-in way to limit the number of compile errors. The easiest solution is probably to use something like sed to extract the first foo.zig:1:1: error: message:

# print everything between and including the first two
# lines containing ': error:', but omit the last line
zig build run --prominent-compile-errors 2>&1 | sed -n '/: error:/,/: error:/p' | sed '$d'

A more complete solution would be to make a copy of the stock build_runner.zig, adjust the logic for printing compile errors (specifically the lines that use result_error_bundle.render*()) and then passing it to zig build --build-runner my_runner.zig. However, this implies messing around with std.zig.ErrorBundle which is a bit more complex than a simple [][]const u8. Plus, the stock build runner changes all the time so you will need to repeat this process and reapply your local fixes every time you update Zig.

3 Likes

--error-limit n is unrelated to compile error messages, it’s for limiting the number of unique error values in a Zig compilation unit (which affects @sizeOf(anyerror)).

error: ZCU used more errors than possible: used 95, max 1
    note: use '--error-limit 95' to increase limit
1 Like

Ahm, damn. That’s an embarrasing misunderstanding. :sweat_smile:

Sorry @fleimgruber.

It’s an easy mistake to make and a confusing option name, especially since -ferror-limit in clang is for error messages :grinning_face: It would probably improve clarity if it was renamed to --max-error-values or something similar.

1 Like