Skip to content

core: make the user's main.zig the executable root#937

Open
mattnite wants to merge 5 commits intomainfrom
app-root
Open

core: make the user's main.zig the executable root#937
mattnite wants to merge 5 commits intomainfrom
app-root

Conversation

@mattnite
Copy link
Copy Markdown
Contributor

The firmware executable's root module is now the user's application source, not microzig's start.zig shim. This aligns microzig with the standard Zig build idiom: @import("root") from any module resolves to user code, pub const panic / pub const std_options live where Zig expects to find them, and tooling that assumes root-is-the-app now works naturally.

Core changes:

  • microzig.zig reads microzig_options via @import("root") instead of the injected app module, and drops the pub const app alias.
  • utilities.install_startup / core/src/start.zig are replaced by a single user-facing primitive, microzig.export_startup(), which the application opts into from a comptime block. It emits the CPU startup symbols and the microzig_main wrapper that the CPU _start calls once .data/.bss are initialized.
  • Startup logic (HAL init / root init / error-returning main / panic wrapping) moves out of start.zig into microzig_main, with identical semantics.
  • A new microzig.std_options() helper returns a std.Options with microzig's freestanding-safe defaults (the critical one being a no-op logFn that replaces stdlib's stderr-writing default, which fails to link on freestanding). The accompanying StdOptions struct documents which std.Options fields are exposed and which are intentionally excluded as hosted-only.
  • The log-related fields (log_level, log_scope_levels, logFn) are removed from microzig.Options; they now live exclusively in std.Options via the helper.

Build system:

  • add_firmware sets exe.root_module = app_mod directly. The separate start.zig root module and the "app"-import plumbing on core_mod / cpu_mod / chip_mod / hal_mod / board_mod are all gone.

Example boilerplate (now two re-exports and one comptime line):

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

comptime {
    _ = microzig.export_startup();
}

All 131 example main.zig files have been migrated. Examples that previously declared pub const microzig_options with log-related fields have had those fields moved into microzig.std_options(...), with any remaining microzig-specific fields (interrupts, hal, cpu, etc.) kept in a trimmed pub const microzig_options.

The website getting-started snippet is updated to match.

This commit only performs the structural move. It is NOT expected to build against 0.15.x or current 0.16.x compilers as-is; the separate 0.16 migration work comes next.

mattnite and others added 4 commits April 24, 2026 13:12
The firmware executable's root module is now the user's application
source, not microzig's start.zig shim. This aligns microzig with the
standard Zig build idiom: `@import("root")` from any module resolves to
user code, `pub const panic` / `pub const std_options` live where Zig
expects to find them, and tooling that assumes root-is-the-app now
works naturally.

Core changes:
- microzig.zig reads `microzig_options` via `@import("root")` instead of
  the injected `app` module, and drops the `pub const app` alias.
- utilities.install_startup / core/src/start.zig are replaced by a
  single user-facing primitive, `microzig.export_startup()`, which the
  application opts into from a comptime block. It emits the CPU
  startup symbols and the `microzig_main` wrapper that the CPU `_start`
  calls once `.data`/`.bss` are initialized.
- Startup logic (HAL init / root init / error-returning main / panic
  wrapping) moves out of start.zig into microzig_main, with identical
  semantics.
- A new `microzig.std_options()` helper returns a `std.Options` with
  microzig's freestanding-safe defaults (the critical one being a no-op
  `logFn` that replaces stdlib's stderr-writing default, which fails to
  link on freestanding). The accompanying `StdOptions` struct documents
  which std.Options fields are exposed and which are intentionally
  excluded as hosted-only.
- The log-related fields (`log_level`, `log_scope_levels`, `logFn`) are
  removed from `microzig.Options`; they now live exclusively in
  `std.Options` via the helper.

Build system:
- `add_firmware` sets `exe.root_module = app_mod` directly. The
  separate start.zig root module and the "app"-import plumbing on
  `core_mod` / `cpu_mod` / `chip_mod` / `hal_mod` / `board_mod` are
  all gone.

Example boilerplate (now two re-exports and one comptime line):

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

    comptime {
        _ = microzig.export_startup();
    }

All 131 example main.zig files have been migrated. Examples that
previously declared `pub const microzig_options` with log-related
fields have had those fields moved into `microzig.std_options(...)`,
with any remaining microzig-specific fields (interrupts, hal, cpu,
etc.) kept in a trimmed `pub const microzig_options`.

The website getting-started snippet is updated to match.

This commit only performs the structural move. It is NOT expected to
build against 0.15.x or current 0.16.x compilers as-is; the separate
0.16 migration work comes next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Grazfather
Copy link
Copy Markdown
Collaborator

hah whoa. Maybe we run the zig imports fix as a separate cleanup PR to cut down on the noise?

@mattnite
Copy link
Copy Markdown
Contributor Author

@Grazfather nah, too easy to fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants