Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Managing external libraries and forks

Direct vs. forked libraries

ImGui Bundle includes ~24 external C++ libraries. Each lives under external/<LibName>/ and is typically a git submodule.

Some libraries can be used as-is from their upstream repository. Others need modifications to work with Python bindings — for example, replacing pointer + count C APIs with std::vector, or swapping C function pointers for std::function. In those cases, a fork is maintained on GitHub under github.com/pthom.

Run just libs_info to see the full picture:

NAME                      FORK                                                  OFFICIAL                                              PATH
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
imgui                     https://github.com/pthom/imgui.git                    https://github.com/ocornut/imgui.git                  external/imgui/imgui
imgui_test_engine         https://github.com/pthom/imgui_test_engine.git        https://github.com/ocornut/imgui_test_engine.git      external/imgui_test_engine/imgui_test_engine
glfw                                                                            https://github.com/glfw/glfw.git                      external/glfw/glfw
hello_imgui                                                                     https://github.com/pthom/hello_imgui.git              external/hello_imgui/hello_imgui
im_cool_bar               https://github.com/pthom/ImCoolBar.git                https://github.com/aiekick/ImCoolBar.git              external/ImCoolBar/ImCoolBar
im_file_dialog            https://github.com/pthom/ImFileDialog.git             https://github.com/dfranx/ImFileDialog.git            external/ImFileDialog/ImFileDialog
imgui_command_palette     https://github.com/pthom/imgui-command-palette.git    https://github.com/hnOsmium0001/imgui-command-palette.git external/imgui-command-palette/imgui-command-palette
imgui_knobs               https://github.com/pthom/imgui-knobs.git              https://github.com/altschuler/imgui-knobs             external/imgui-knobs/imgui-knobs
imgui_node_editor         https://github.com/pthom/imgui-node-editor.git        https://github.com/thedmd/imgui-node-editor.git       external/imgui-node-editor/imgui-node-editor
imgui_rich_md             https://github.com/pthom/imgui_rich_md.git            (renderer by mekhontsev/imgui_md, rewritten)          external/imgui_rich_md/imgui_rich_md
imgui_microtex            https://github.com/pthom/MicroTeX.git                 https://github.com/NanoMichael/MicroTeX.git           external/imgui_microtex/MicroTeX
imgui_tex_inspect         https://github.com/pthom/imgui_tex_inspect.git        https://github.com/andyborrell/imgui_tex_inspect.git  external/imgui_tex_inspect/imgui_tex_inspect
imgui_toggle              https://github.com/pthom/imgui_toggle.git             https://github.com/cmdwtf/imgui_toggle.git            external/imgui_toggle/imgui_toggle
imgui_color_text_edit     https://github.com/pthom/ImGuiColorTextEdit.git       https://github.com/goossens/ImGuiColorTextEdit.git    external/ImGuiColorTextEdit/ImGuiColorTextEdit
imguizmo                  https://github.com/pthom/ImGuizmo.git                 https://github.com/CedricGuillemet/ImGuizmo.git       external/ImGuizmo/ImGuizmo
immvision                                                                       https://github.com/pthom/immvision.git                external/immvision/immvision
implot                    https://github.com/pthom/implot.git                   https://github.com/epezent/implot.git                 external/implot/implot
implot3d                  https://github.com/pthom/implot3d.git                 https://github.com/brenocq/implot3d.git               external/implot3d/implot3d
nanovg                    https://github.com/pthom/nanovg.git                   https://github.com/memononen/nanovg.git               external/nanovg/nanovg
im_anim                   https://github.com/pthom/ImAnim.git                   https://github.com/soufianekhiat/ImAnim.git           external/ImAnim/ImAnim

When is a fork created?

A fork is created when a library needs C++ source modifications that cannot be achieved through the binding generator alone. Typical reasons:

If a library can be bound without source modifications, it is used directly from upstream (no fork needed).

Adapting an API for Python: where does the change go?

A patch in a fork is the most expensive place for a Python adaptation: it must survive every rebase on upstream, and it changes the C++ library for everybody. Try the following mechanisms in this order, and stop at the first one that does the job:

#MechanismWhere it livesUse it when
1litgen optionexternal/<lib>/bindings/ (generator script or options file)Excluding, renaming, turning output parameters into return values, buffers into numpy arrays, etc.
2Wrapper header (“pywrappers”)e.g. external/imgui/imgui_pywrappers/The Python version is plain C++ that litgen can bind: a new struct, std::string, std::optional, a tuple.
3Custom bindingoptions.custom_bindings.add_custom_bindings_to_main_module / _to_class / _to_submoduleThe binding needs nanobind types (nb::ndarray, nb::object), access to members from outside the class, or control over a whole set of overloads.
4Fork patchthe library itselfThe behavior of the library must change (bug fix, feature), or a type must differ in the Python build.

Why this order:

Examples in the Dear ImGui bindings (external/imgui/bindings/litgen_options_imgui.py):

MechanismExample
litgen optionfn_exclude_by_name_and_signature hides the pointer + count overloads of ImDrawList
Wrapper headerDockBuilderSplitNode() returning a struct instead of two output parameters; drag and drop payloads carrying a Python id
Custom bindingImTextureData.get_pixels_array() (numpy view), imgui.set_window_focus() (owns its overload set), the clipboard callbacks of ImGuiPlatformIO (static trampolines)
Fork patchImGuiInputTextCallback is a std::function in the Python build

The fork branch model

Branches and remotes

Each forked library has two git remotes:

RemotePoints toBranch tracked
officialUpstream author’s repo (e.g. ocornut/imgui)The upstream branch (e.g. docking, master, main)
forkpthom’s fork (e.g. pthom/imgui)imgui_bundle

The fork branch is always named imgui_bundle. All bundle-specific changes live on this branch.

Non-forked libraries have a single official remote pointing to their upstream repo.

Rebase, not merge

When updating a fork to incorporate new upstream changes, we rebase the imgui_bundle branch on top of the latest upstream — we do not merge. This keeps the bundle-specific diff small, self-contained, and easy to review. It also makes future rebases easier since there are no merge commits to carry forward.

The typical update sequence is:

  1. Tag the current fork state (safety snapshot): just libs_tag <name>

  2. Rebase the fork branch on upstream: just libs_rebase <name>

  3. Force-push the rebased branch to the fork remote (if the rebase changed anything)

See Update existing bindings for the full step-by-step workflow.

Marking bundle-specific changes

In code: [ADAPT_IMGUI_BUNDLE] markers

All bundle-specific modifications in forked library source code are bracketed with comment markers:

// [ADAPT_IMGUI_BUNDLE]
// ... bundle-specific code ...
// [/ADAPT_IMGUI_BUNDLE]

This makes it easy to find all bundle adaptations by searching for ADAPT_IMGUI_BUNDLE, and to review the diff against upstream.

Example from imgui.h: a function added for the ImGui Explorer:

//[ADAPT_IMGUI_BUNDLE]
IMGUI_API void ShowDemoWindow_MaybeDocked(
    bool create_window, bool* p_open = NULL,
    ImGuiWindowFlags initial_extra_flags = 0,
    ImVec2 window_pos = ImVec2(0, 0), ImVec2 window_size = ImVec2(0, 0));
//[/ADAPT_IMGUI_BUNDLE]

In commits: [Bundle] prefix

Bundle-specific commits use a [Bundle] prefix in the commit message. This clearly distinguishes them from upstream commits when reading the git log. Commits that are proposed upstream as they are (see “Contributing fixes upstream” below) do not carry the prefix.

Some older commits may use [ADAPT_IMGUI_BUNDLE] as the prefix: this is equivalent.

The Dear ImGui fork: one commit per theme

The Dear ImGui fork is kept as a short list of thematic commits on top of upstream’s docking branch, so that each of them can be reviewed, rebased or dropped on its own:

$ git log --oneline official/docking..imgui_bundle
[Bundle] imgui_demo.cpp: ShowDemoWindow_MenuSectionWindow(), the window of a section of the demo's menus
[Bundle] Move the docking internal types from imgui.cpp to imgui_internal.h
[Bundle] imgui_freetype: PlutoSVG's FreeType hooks are in <plutosvg-ft.h>
[Bundle] Python build: throwing IM_ASSERT support and std::function callback typedefs
[Bundle] imgui_demo.cpp adaptations for the ImGui Explorer
[Bundle] Emscripten / Pyodide: SDL2 backend fixes
[Bundle] ImGuiContext::InputTextMultilineOverride
[Bundle] ImGuiContext::BeginWindowCallback / EndWindowCallback, called by Begin() and End()
Widgets: Sliders & Drags display the value in a tooltip on touchscreens.
Stack Layout implementation v2.2
Internals: CallContextHooks(): fixed iterating a reallocated array when a hook callback adds a hook.
Tables: fixed items in a cell being laid out on one line when the table is submitted in a horizontal layout (e.g. a menu bar).

The imgui-node-editor fork

The fork of imgui-node-editor is organised in the same way, on top of upstream’s master branch: generic commits first (fixes, the canvas, widgets inside nodes, node width, angled links), then the tests and the documentation. Its first commits, each with tests in upstream’s headless suite, are also on branches of their own, for upstream. What it adds is described in its own docs/fork_imgui_bundle.md.

Preprocessor macros

Two preprocessor macros control conditional compilation in forked code:

These are often used together to swap an unwrappable API for a Python-friendly one (try the mechanisms 1 to 3 above first: a function that fills an array, for example, is better served by a wrapper header that returns a std::vector):

// From imgui.h — replacing function pointer with std::function
#ifdef IMGUI_BUNDLE_PYTHON_API
using ImGuiInputTextCallback = std::function<int(ImGuiInputTextCallbackData*)>;
#else
#ifdef IMGUI_BUNDLE_PYTHON_UNSUPPORTED_API
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data);
#endif
#endif

See Adding a new library (Step 3) for more adaptation patterns.

Contributing fixes upstream

If a fix or improvement is not specific to ImGui Bundle (e.g. a genuine bug fix, a useful feature), it should be contributed upstream:

Tooling

Python module: bundle_libs_tooling

The library management logic lives in external/bindings_generation/bundle_libs_tooling/:

FilePurpose
all_external_libraries.pyCentral registry — defines all ~24 libraries as ExternalLibrary instances in the ALL_LIBS list. Contains functions for bulk operations (reattach, fetch, pull, check upstream).
external_library.pyExternalLibrary dataclass — holds name, git URLs, branches, remote names, and provides methods for git operations (add remotes, fetch, rebase, tag, etc.).
shell_commands.pyShellCommands helper — runs multiline shell commands with echo and error handling.

The ExternalLibrary dataclass fields:

@dataclass
class ExternalLibrary:
    name: str                          # Library name (e.g. "ImCoolBar")
    official_git_url: Optional[str]    # Upstream repo URL
    official_branch: str = "master"    # Upstream branch to track
    fork_git_url: Optional[str]        # Fork repo URL (None if not forked)
    fork_branch: str = "imgui_bundle"  # Fork branch (always "imgui_bundle")
    is_published_in_python: bool       # Whether this lib gets Python bindings
    is_sub_library: bool               # Sub-library (e.g. MicroTeX inside imgui_microtex)

Justfile recipes: just libs_*

The justfile at the repo root wraps the Python tooling into convenient commands:

CommandDescription
just libs_infoShow all libraries with their remotes and paths
just libs_reattachReattach all submodules to their correct branches and remotes
just libs_fetchFetch all remotes for all submodules
just libs_pullPull all submodules
just libs_check_upstreamCheck which forked libraries have new upstream changes
just libs_log <name>Show new upstream commits not yet in a fork
just libs_tag <name>Push a dated tag (bundle_YYYYMMDD) to a fork
just libs_check_pushedCheck that every submodule commit the bundle points to is on a remote branch (before pushing the bundle)
just bundle_pushPush the bundle, once libs_check_pushed passes
just libs_rebase <name>Tag current state, then rebase fork branch on upstream
just libs_bindings <name>Regenerate Python bindings for one library
just libs_bindings_allRegenerate all Python bindings

Library names can be passed in snake_case or original form (e.g. just libs_log imgui or just libs_log ImGuiColorTextEdit).

Common operations

After a fresh clone: reattach submodules

By default, git submodules are in “detached HEAD” mode. To set up the correct remotes (official / fork) and attach each submodule to its tracking branch:

just libs_reattach

This is typically the first thing to do after cloning the repository when you plan to work on library updates.

Check what’s new upstream

just libs_check_upstream

Example output:

Unchanged libraries: glfw, hello_imgui, ImCoolBar, ImFileDialog, imgui-command-palette, ...
Libraries with new changes in official repo: imgui, imgui_test_engine, ImGuiColorTextEdit

Then inspect the new commits for a specific library:

just libs_log imgui

Tag a fork (safety snapshot)

Before rebasing, create a dated tag so you can recover the previous state:

just libs_tag imgui

This creates a tag named bundle_YYYYMMDD and pushes it to the fork remote.

Rebase a fork on upstream

just libs_rebase imgui

This command:

  1. Creates a dated tag (safety snapshot)

  2. Fetches both official and fork remotes

  3. Checks out the imgui_bundle branch

  4. Rebases it on top of official/<upstream_branch>

If the rebase introduces changes, you need to force-push manually:

cd external/imgui/imgui
git push fork --force-with-lease
cd -

Update a non-forked library

For libraries without a fork, simply pull:

cd external/hello_imgui/hello_imgui
git pull
cd -

A library pinned to a release tag (pinned_tag in all_external_libraries.py: glfw, the GLFW of the desktop Python wheel) has no tracking branch, and just libs_pull skips it. Its update is a deliberate step: the new tag in all_external_libraries.py, then git fetch official --tags && git checkout <tag> in the submodule.

Or pull all submodules at once:

just libs_pull