How does std_options work?

Questions

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 .{};
  1. This suggests there’s some sort of circular dependency. My code invokes std, but std invokes my code. How is this resolved?
  2. 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.

Zig allows circular dependencies between modules.

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:

const builtin = @import("builtin");

pub const std_options: std.Options = .{
    .log_level = if (builtin.mode == .Debug) .debug else .info,
    .log_scope_levels = &.{
        .{ .scope = .decimal, .level = .info },
        .{ .scope = .proper, .level = .info },
    },
    .logFn = log,
};


@mcdow welcome to ziggit :slight_smile:

7 Likes

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.