I was looking into how std_options works, so I pulled up std.zig:
const root = @import("root");
/// Stdlib-wide options that can be overridden by the root file.
pub const options: Options = if (@hasDecl(root, "std_options")) root.std_options else .{};
This suggests there’s some sort of circular dependency. My code invokes std, but std invokes my code. How is this resolved?
How is root defined?
More on Q2. Let’s say I compile a zig library, and link my code against that library. Does std get compiled twice? Once for the library, and once for my top-level code? Or is std compiled once against the top level code?
Background
I’m using a 3rd party library and running tests with the zig build system (zig build test not zig test). In my tests I set it up so that the library will fail, and my code handles the failure. However, this third party library invokes std.log with an error. I don’t want it to do this during my tests, because I handle the error. For my test, I was trying to suppress log output by setting:
pub const std_options = {
// Logging function I defined which throws away the input.
.logFn = noopLog,
};
My custom logging function never gets called, which led me to suspect that std_options doesn’t change std globally as I initially thought.
root is the root_module that you build as executable or dynamic/static library.
No, it is compiled once.
For executables, zig expects the root module to declare the main function.
You always specify which is the root_module in your build.zig addExecutable, addStaticLibrary, etc.
When declaring std_options, always specify the type std.Options and initialize using .{}.
You can also set the logging level in root_module std_options.
A complex log settings example:
The naming choice is unfortunate, it takes a convenient name std_options away from the user. I think that zig_std_options or std.zig_options or even std.options would be be better.
Fwiw I think it’s fine for some names to be reserved, and I’m curious wheee you think that name is convenient. I’d probably just name my variable options.
Sorry for necro-posting, but I believe the original question was valid, and it was never answered. std_options exhibit behavior during tests that I cannot explain. Consider an example:
Put this code into a standalone file. If you run it with zig run it prints 10. However if you run it with zig test the test passes. The Options.fmt_max_depth stays 3 as if the custom initializer was ignored. What kind of black magic is this?
for the test case, while it prints the name of your file for the run case.
This happens because the test runner is the main executable that runs your tests, it uses the information from @import("builtin").test_functions to construct a program that runs the tests.
So you are testing the std_options set by the test_runner.
And you can create a custom implementation of that test runner.