Can I run build.zig in a debugger?

Sometimes I like to trace what’s happening in my build.zig script. I like to step into the build API functions purly out of curiosity or to figure out why my build.zig is not working as I expected.

As far as I know, ‘zig build’ command instantly create an exe file to run the build process. If I am right, isn’t it possible to launch the build process from a debugger such as gdb or vscode? Does zig compiler compiles build.zig in debug mode and leave debug infos (such as pdb files for Windows env.)?

1 Like

Add --verbose to see all the commands being invoked.

That said, I think that if your goal is debug your build script, this is not the way to go. If something doesn’t get built and you don’t understand why, the best way forward is to look at the chain of dependencies of your steps and investigate where a dependency that you would expect to exist, is actually not there.

More concretely, run the build script with --summary all, that will show you how running each step causes to run other steps as a result.

For example by default zig build runs the default install step, which in turn normally tries to install your program, which in turn requires to build your program first.

So, if you observe that the install step runs but it doesn’t cause your program to build, it means that you failed to wire that dependency (you’re missing b.installArtifact(exe) in this case).

A secondary variant of this problem is when one step should only run after another has finished but you didn’t wire that dependency in the build script. For exmple you have a step that copies a directory somewhere but another step needs to write something into that directory first.

In this case what will happen is that the build system will run the steps in parallel, causing a race condition.

You can observe this in the build summary as well. You will see that the two steps don’t reference one another in the output, and that should be your tell.

Fixing this is heavily dependent on the situation. Some build steps have an output file expressed as a lazy path, and using that lazy path as input to another step will create the link, some other times you need to explicitly add a dependency doing something like this:

copy_dir.step.dependOn(&copy_file_to_dir.step);
2 Likes

Agreed, but one of the motives given was to step through a build to satisfy curiosity and see how it works.

So far as I can determine, the --verbose flag is no longer useful. It flashes more stuff in the progress indicator, briefly, maybe, but it doesn’t actually reveal any paths or other actionable info like it used to. This is true on a maybe two-weeks-stale master build, as well as 0.13.

So I’m not actually sure how to get access to the build runner with a debugger, and find that I’m curious.

1 Like

I found I can use Step.dump() function as well. This prints out some more info strings and the stack trace. But still, I found it a little lacking to fullfil my curiosity. Even if this is not a recommended way of debugging a build script, I wish to know starting it from a debugger is possible at all.

1 Like

The build runner source code is available in your distribution lib/compiler/build_runner.zip.
You can copy this, create a new one, and use it with the zig build ... --build-runner [file] option.
There are many possibilities; for example: start the debugger from build runner, or print the process id and wait for a debugger to attach.

The easiest way–if you are on windows–is to enable Automatic Debugging and add a @breakpoint(); as first instruction in main.

The second easiest way is to print the process id (GetCurrentProcessId, std.c.getpid, std.os.linux.getpid) in main and wait for a key to be pressed. Then you can run the debugger and attach it to the process id of the build runner lldb -p <pid> or gdb --pid=<pid>.

4 Likes