Skip to content

feat(sokol+imgui): wire sokol-imgui bridge through gui.labelle - #33

Closed
apotema wants to merge 2 commits into
mainfrom
feat/sokol-imgui-bridge
Closed

apotema wants to merge 2 commits into
mainfrom
feat/sokol-imgui-bridge

Conversation

@apotema

@apotema apotema commented Apr 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds the assembler-side plumbing for GUI plugins that need sokol_imgui. Until now there was no way for a labelle-imgui-style GUI plugin to make sokol_imgui work, because sokol_imgui is part of sokol_clib (gated by with_sokol_imgui = true at the sokol-zig dep declaration), and the backend's build.zig hardcoded with_sokol_imgui = false. The bridge artifact itself can be tiny — it just needs a way to ask the backend to build sokol with imgui support.

What changes

  • backends/sokol/build.zig learns a -Dwith_sokol_imgui build option. When true it forwards to sokol-zig and lazily fetches cimgui (matching hash with labelle-imgui's pin) just to expose its include path to sokol_clib so sokol_imgui.h's IMPL section can resolve cimgui types. The cimgui artifact itself is provided by the GUI plugin and linked at the final exe step — there is only ever one cimgui_clib in the binary.
  • gui.labelle bridges learn a needs_sokol_imgui: bool = false field (parsed in gui_resolve.zig, propagated to ResolvedGui in config.zig). The flag is the contract by which a GUI plugin tells the assembler "I want with_sokol_imgui = true on the backend dep".
  • build_files.zig checks resolved_gui.needs_sokol_imgui when emitting the sokol backend dep and renders a new backend_sokol_imgui template section that passes .with_sokol_imgui = true. The non-imgui path is unchanged.
  • gui_resolve.zig parses gui.labelle with .ignore_unknown_fields = true. This is forward-compat insurance: every new bridge hint flag added here would otherwise require a lockstep CLI bump, since the CLI's pinned generator parses the same manifest.

Companion PR

The C wrapper that re-exports imgui_bridge_setup/begin/end/shutdown against simgui_* lives in labelle-imgui — see labelle-toolkit/labelle-imgui#3.

Architecture note

There is exactly one sokol_clib in the final exe. The bridge artifact does not declare its own sokol — it only needs sokol's header path at compile time (for simgui_desc_t and friends), and at the final link step simgui_* symbols resolve from the backend's sokol_clib. This avoids the duplicate-state problem that would happen if the GUI plugin shipped its own sokol artifact.

Test plan

  • zig build - backend compiles with and without -Dwith_sokol_imgui
  • Downstream: flying-platform-labelle (sokol backend + imgui GUI via labelle-imgui bridge) builds clean and runs end-to-end
  • CI: verify lazy cimgui dep is not fetched when -Dwith_sokol_imgui is unset

Adds the assembler-side plumbing for GUI plugins that need sokol_imgui.
Until now there was no way for a labelle-imgui-style GUI plugin to make
sokol_imgui work, because sokol_imgui is part of sokol_clib (gated by
`with_sokol_imgui = true` at the sokol-zig dep declaration), and the
backend's build.zig hardcoded with_sokol_imgui=false. The bridge artifact
itself can be tiny — it just needs a way to ask the backend to build sokol
with imgui support.

This PR introduces:

- `backends/sokol/build.zig` learns a `-Dwith_sokol_imgui` build option.
  When true it forwards to sokol-zig, and lazily fetches cimgui (matching
  hash with labelle-imgui's pin) just to expose its include path to
  `sokol_clib` so sokol_imgui.h's IMPL section can resolve cimgui types.
  The cimgui artifact itself is provided by the GUI plugin and linked at
  the final exe step — there is only ever one cimgui_clib in the binary.

- `gui.labelle` bridges learn a `needs_sokol_imgui: bool = false` field
  (parsed in `gui_resolve.zig`, propagated to `ResolvedGui` in
  `config.zig`). The flag is the contract by which a GUI plugin tells the
  assembler "I want with_sokol_imgui=true on the backend dep".

- `build_files.zig` checks `resolved_gui.needs_sokol_imgui` when emitting
  the sokol backend dep and renders a new `backend_sokol_imgui` template
  section that passes `.with_sokol_imgui = true`. The non-imgui path is
  unchanged.

- `gui_resolve.zig` parses `gui.labelle` with `.ignore_unknown_fields =
  true`. This is forward-compat insurance: every new bridge hint flag
  added here would otherwise require a lockstep CLI bump, since the
  CLI's pinned generator parses the same manifest.

The companion bridge artifact (the C wrapper that re-exports
imgui_bridge_setup/begin/end/shutdown against simgui_*) lives in
labelle-imgui — see labelle-toolkit/labelle-imgui#TBD.

Verified end-to-end: with this PR + the labelle-imgui bridge PR, the
flying-platform-labelle project (sokol backend + imgui GUI) builds clean,
links cimgui through the GUI plugin, and the sokol-imgui shaders compile
and run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
apotema added a commit to labelle-toolkit/labelle-imgui that referenced this pull request Apr 14, 2026
Adds a sokol-side bridge that wires Dear ImGui to sokol via sokol_imgui,
mirroring the existing rlImGui bridge for raylib. The bridge re-exports
simgui_setup/new_frame/render/shutdown under the imgui_bridge_* symbol
contract that labelle-imgui's adapter.zig calls.

Architecture differs from the raylib bridge:

- The raylib bridge compiles rlImGui.cpp into a separate static library
  that links against raylib + cimgui at the bridge level.

- sokol_imgui is *part of sokol itself* — gated by `with_sokol_imgui =
  true` at the sokol-zig dep declaration. Two sokol_clib artifacts in
  the same exe would be undefined behavior (sokol owns global state),
  so the bridge here does NOT compile or link sokol. It only emits a
  thin C wrapper that calls simgui_*. Those symbols are unresolved at
  bridge-build time and resolve at the final exe link step from the
  backend's sokol_clib (which, when this bridge is selected, is built
  with `-Dwith_sokol_imgui=true`).

- The sokol dep declared in build.zig.zon is *only* for headers — the
  bridge addIncludePath()'s sokol/src/sokol/c so bridge.c can see
  simgui_desc_t and friends. The pin must match labelle-assembler's
  backends/sokol/build.zig.zon so struct layouts agree at link time;
  drift between the two would silently corrupt simgui state.

The new gui.labelle entry sets `needs_sokol_imgui = true` on the sokol
bridge, which the assembler reads to enable `-Dwith_sokol_imgui=true`
on the sokol backend dep — see labelle-toolkit/labelle-assembler#33.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for sokol-imgui by adding a with_sokol_imgui build option to the Sokol backend, which lazily fetches cimgui headers when enabled. The project configuration and GUI resolution logic have been updated to propagate the needs_sokol_imgui flag from GUI manifests. However, the current implementation in src/build_files.zig only applies the ImGui-enabled template for desktop platforms; targeting WASM, iOS, or Android with a GUI requiring Sokol ImGui will likely result in link errors as those platform-specific sections do not yet pass the necessary build flag.

Comment thread src/build_files.zig Outdated
Comment on lines 63 to 73
if (cfg.platform == .wasm) {
try tpl.writeSection(build_zig_tmpl, "backend_sokol_wasm", w);
} else if (cfg.platform == .ios) {
try tpl.writeSection(build_zig_tmpl, "backend_sokol_ios", w);
} else if (cfg.platform == .android) {
try tpl.writeSection(build_zig_tmpl, "backend_sokol_android", w);
} else if (want_imgui) {
try tpl.writeSection(build_zig_tmpl, "backend_sokol_imgui", w);
} else {
try tpl.writeSection(build_zig_tmpl, "backend_sokol", w);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ImGui support for the Sokol backend is currently only implemented for the desktop platform. The logic in the switch (cfg.backend) block prioritizes platform-specific checks (wasm, ios, android) and uses their respective template sections (e.g., backend_sokol_wasm), which do not pass the .with_sokol_imgui = true flag to the backend dependency.

As a result, if a user targets WASM or mobile with a GUI that requires Sokol ImGui, the build will likely fail at the link stage due to missing symbols. Consider adding ImGui-enabled variants for these platform templates or refactoring the template sections to accept the with_sokol_imgui flag as a parameter via renderSection.

@cursor

cursor Bot commented Apr 14, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Moderate risk because it changes generated build logic and dependency resolution for the sokol backend (including a new lazy external dep), which could affect cross-platform builds if mis-propagated.

Overview
GUI plugins can now request that the sokol backend be built with sokol_imgui support by setting needs_sokol_imgui in their gui.labelle bridge definition.

This wires a new -Dwith_sokol_imgui option through the sokol backend build (including a lazily-fetched, pinned cimgui include path), extends manifest parsing to ignore unknown fields for forward compatibility, and updates the build.zig generator/templates to select platform-specific backend_sokol_*_imgui sections that pass .with_sokol_imgui = true when required.

Reviewed by Cursor Bugbot for commit dd2327d. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 00583b9. Configure here.

Comment thread src/build_files.zig Outdated
… branches

Bugbot caught that the `want_imgui` branch in the sokol backend dispatch
was unreachable for non-desktop platforms — the wasm/ios/android arms
ran first and silently dropped the imgui flag, so a project targeting
Android with `needs_sokol_imgui = true` would generate a build.zig
without `.with_sokol_imgui = true` and fail at link time with unresolved
`simgui_*` symbols.

Refactor the sokol arm of the backend switch in build_files.zig to a
single nested switch over platform x want_imgui, and add three new
template sections — backend_sokol_wasm_imgui, backend_sokol_ios_imgui,
backend_sokol_android_imgui — that mirror their non-imgui counterparts
but pass `.with_sokol_imgui = true` to the sokol dep declaration. Each
keeps the platform-specific knobs (dont_link_system_libs, NDK include
paths, SDK paths) so the imgui-enabled build still links correctly
against the platform's framework / sysroot.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apotema

apotema commented Apr 14, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in dd2327d. The sokol arm of the backend dispatch in build_files.zig is now a single nested switch over platform × want_imgui, and there are three new template sections (backend_sokol_wasm_imgui, backend_sokol_ios_imgui, backend_sokol_android_imgui) that mirror the existing platform-specific sections but pass .with_sokol_imgui = true on the dep. Each one keeps the platform-specific knobs (dont_link_system_libs, NDK include paths, SDK paths) intact.

@apotema

apotema commented Apr 14, 2026

Copy link
Copy Markdown
Contributor Author

Closing this in favor of the labelle-imgui sokol bridge approach that's now in main (labelle-toolkit/labelle-imgui PRs #1 and #2, merged externally during today's work). Their bridge owns its own `sokol-with-imgui` dep at the bridge level rather than threading a build option through the backend, and #38 + #39 in this repo verified the end-to-end path works without needing the `needs_sokol_imgui` flag this PR added.

The one piece of this PR that's arguably still useful — `ignore_unknown_fields = true` on the gui.labelle parser, for forward compat — could be split into a 3-line standalone PR if we hit a real case where it matters. Not worth keeping this PR open just for that.

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.

1 participant