Application Boilerplate

Three pieces of boilerplate are needed to use MicroZig:

const microzig = @import("microzig");

pub const panic = microzig.panic;
pub const std_options = microzig.std_options(.{});

comptime {
    _ = microzig.export_startup();
}

MicroZig offers a freestanding-friendly panic and std_options, that don’t cause compile errors by default. At the time of writing, the standard library ends up pulling in OS-specific declarations which is the cause of these compilation errors and isn’t obvious when you’re starting out on Zig embedded programming. microzig.std_options() takes an override argument so you can customize it as you like.

The export_startup() call ensures that your hardware specific startup code is linked into the firmware image. These are the parts before main, like setting up bss and data sections.

Background

In the past, MicroZig would use its own module for the root of an embedded application. The code that the user provided was turned into an app module, and the root would call app.main().

This had the benefit of giving MicroZig control over how the application was set up, allowing an easy way for it to link the startup code. It had a downside where @import("root") did not refer to the user’s application root, it referred to MicroZig’s. Many libraries use that as an avenue for configuration at compile-time. The most notable of which, was the standard library itself.

The standard library is pervasive enough that we were fine forwarding some of its options through our own microzig_options declaration. None of the solutions for forwarding other package “options” felt right.

In addition, this setup complicated the import of external packages. Users needed to understand the module hierarchy, and that adding a package to their executable did not make it available to their program. Instead they needed to add it to their app module, or find the specific option in the firmware build interface that would do that for them.

In the end, it just wasn’t worth it. We traded a few less lines of boilerplate for an increasingly complex system, and it was hurting users’ understanding. We decided that a few extra lines of code on your end and some documentation on ours was worth the more consistent system.