Add C++20 named module 'imgui'

imgui.cppm builds Dear ImGui as a named module that exports the same
API as imgui.h. The global module fragment includes imgui_macros.h and
the C system headers, then the purview imports std.compat and #includes
imgui.h. The .cpp files and imgui_internal.h go in 'module :private;',
so internals stay hidden and the whole library is one translation unit.

Exports are marked in imgui.h rather than listed separately, so they
can't drift from the header:
- IMGUI_EXPORT prefixes the ImGui namespace.
- IMGUI_EXPORT_BEGIN/END wrap runs of global declarations, leaving out
  the out-of-line member definitions, which can't be exported.
All three expand to nothing outside the module. ImHashData() and the
GetIO(ImGuiContext*) overload live in imgui_internal.h but backends
need them, so imgui.cppm exports them explicitly.

NavUpdateAnyRequestFlag() loses its 'inline' forward declaration. Clang
rejects a static inline function that is declared before its definition
inside 'module :private;'. The definition is unchanged, so the
optimiser can still inline it.
This commit is contained in:
Sharadh Rajaraman 2026-09-28 16:27:46 +01:00
parent da548b83e7
commit 6e99a5c717
4 changed files with 196 additions and 7 deletions

View File

@ -1417,7 +1417,7 @@ static void NavUpdateContextMenuRequest();
static void NavUpdateCreateMoveRequest();
static void NavUpdateCreateTabbingRequest();
static float NavUpdatePageUpPageDown();
static inline void NavUpdateAnyRequestFlag();
static void NavUpdateAnyRequestFlag();
static void NavUpdateCreateWrappingRequest();
static void NavEndFrame();
static bool NavScoreItem(ImGuiNavItemData* result, const ImRect& nav_bb);

154
imgui.cppm Normal file
View File

@ -0,0 +1,154 @@
// dear imgui
// (C++20 named module interface: 'import imgui;')
// Usage:
// - Compile this file as the (primary) module interface unit of module 'imgui', e.g. with CMake (see misc/cxx_module/CMakeLists.txt):
// add_library(imgui)
// target_sources(imgui PUBLIC FILE_SET CXX_MODULES FILES imgui.cppm)
// set_target_properties(imgui PROPERTIES CXX_SCAN_FOR_MODULES ON CXX_MODULE_STD ON)
// Do NOT additionally compile imgui.cpp, imgui_demo.cpp, imgui_draw.cpp, imgui_tables.cpp, imgui_widgets.cpp:
// they are compiled as part of this unit (see the private module fragment at the bottom of this file).
// - Requires C++20 modules + the C++23 standard library modules ('import std.compat;', usable as an extension in C++20 by Clang/MSVC/GCC).
// - Then, in your code:
// import imgui;
// ImGui::CreateContext();
// ImGui::NewFrame(); ...
// - Compile-time configuration (IMGUI_USER_CONFIG, imconfig.h, IMGUI_DISABLE_XXX, ImTextureID etc.) applies when compiling
// THIS file. Every consumer of the module sees the configuration the module was built with.
// Design:
// - This follows the "ABI-breaking style" described in https://clang.llvm.org/docs/StandardCPlusPlusModules.html#abi-breaking-style
// (as opposed to an "export-using style" wrapper that would list 'export using ::ImGui::Xxx;' for every symbol):
// imgui.h is included in the module purview, so its declarations are attached to module 'imgui'.
// Symbols are mangled differently from a regular (non-module) build of Dear ImGui: don't link both into the same program.
// - IMGUI_CXX_MODULE is defined below, before anything else. It is used by imgui.h and the .cpp files to:
// - define IMGUI_EXPORT as 'export' and IMGUI_EXPORT_BEGIN/IMGUI_EXPORT_END as 'export {' / '}' (they expand to nothing in regular builds).
// Namespaces of imgui.h are prefixed by IMGUI_EXPORT; declarations of the global namespace are enclosed in IMGUI_EXPORT_BEGIN/END blocks.
// - skip including system/standard headers. The C library comes from 'import std.compat;'; the few headers still needed
// for their macros (and OS headers) are included here in the global module fragment, so they remain attached to the global module.
// - imgui_internal.h is NOT part of the exported interface: it is only included by the .cpp files in the private module fragment.
// Types that are opaque in imgui.h (e.g. ImGuiContext, ImDrawListSharedData) remain incomplete for importers.
// - Maths operators for ImVec2/ImVec4 (IMGUI_DEFINE_MATH_OPERATORS) are always enabled and exported,
// since the implementation requires them. (Being found by ADL, they couldn't be hidden from importers anyway.)
// - Macros are not exported by C++20 modules: IMGUI_VERSION, IMGUI_CHECKVERSION(), IM_ASSERT(), IM_COL32(), IM_COUNTOF() etc.
// are provided by imgui_macros.h, which importers may include (before or after 'import imgui;').
// Some have exported constexpr alternatives, e.g. ImCol32(), ImCol32_White, ImCountOf(), ImGui::CheckVersion() (see imgui.h).
// Limitations (for now):
// - The private module fragment requires this file to be the only unit of module 'imgui'.
// Backends are expected to be provided as separate modules that 'import imgui;'.
// - Not supported yet: IMGUI_ENABLE_FREETYPE, IMGUI_ENABLE_TEST_ENGINE, and linking stb_truetype/stb_rect_pack/stb_sprintf
// implementations from another translation unit (IMGUI_DISABLE_STB_XXX_IMPLEMENTATION, IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION),
// since the corresponding declarations would be attached to module 'imgui' while their definitions are not.
//-----------------------------------------------------------------------------
// [SECTION] Global module fragment
//-----------------------------------------------------------------------------
module;
#define IMGUI_CXX_MODULE 1
// Version, configuration file with compile-time options (imconfig.h) and macros
// (included here rather than from imgui.h, so any user declarations stay attached to the global module)
#include "imgui_macros.h"
#if defined(IMGUI_ENABLE_FREETYPE)
#error "The 'imgui' C++20 module doesn't support IMGUI_ENABLE_FREETYPE yet."
#endif
#if defined(IMGUI_ENABLE_TEST_ENGINE)
#error "The 'imgui' C++20 module doesn't support IMGUI_ENABLE_TEST_ENGINE yet."
#endif
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
// C library functions and types come from 'import std.compat;' below. Modules don't export macros, so we still need:
#include <float.h> // FLT_MAX, FLT_MIN, DBL_MAX
#include <limits.h> // INT_MAX, INT_MIN, UINT_MAX
#include <stdarg.h> // va_start, va_end, va_copy
#include <stddef.h> // offsetof
#include <stdio.h> // stdout
#ifndef IMGUI_DISABLE_TIME_FUNCTIONS
#include <time.h> // localtime_r (POSIX)
#endif
// SSE intrinsics (same condition as in imgui_internal.h)
#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) && !defined(_M_ARM64) && !defined(_M_ARM64EC)
#include <immintrin.h>
#if (defined __AVX__ || defined __SSE4_2__)
#include <nmmintrin.h>
#endif
#endif
// [Windows] OS specific includes (see imgui.cpp)
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
#include <shellapi.h> // ShellExecuteW()
#endif
#include <imm.h> // ImmGetContext() etc.
#endif
// [Apple] OS specific includes (see imgui.cpp)
#if defined(__APPLE__)
#include <TargetConditionals.h>
#if defined(TARGET_OS_OSX) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
#include <Carbon/Carbon.h>
#endif
#endif
// [POSIX] Default shell functions (see imgui.cpp)
#if !defined(_WIN32) && !defined(IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS) && defined(__has_include)
#if __has_include(<sys/wait.h>) && __has_include(<unistd.h>)
#include <sys/wait.h>
#include <unistd.h>
#endif
#endif
// [Emscripten] (see imgui_demo.cpp)
#ifdef __EMSCRIPTEN__
#include <emscripten/version.h>
#endif
//-----------------------------------------------------------------------------
// [SECTION] Module interface
//-----------------------------------------------------------------------------
export module imgui;
import std.compat;
// Always enable maths operators: the implementation requires them, and imgui.h won't be included again by the .cpp files.
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include "imgui.h"
// Internal functions used by backends (declared in imgui_internal.h)
#ifndef IMGUI_DISABLE
export namespace ImGui { IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx); } // imgui_impl_glfw.cpp
export IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed); // imgui_impl_wgpu.cpp
#endif
//-----------------------------------------------------------------------------
// [SECTION] Private module fragment (implementation)
//-----------------------------------------------------------------------------
// Nothing below is reachable from importers: this includes imgui_internal.h and all file-local (static) helpers.
// (same order as misc/single_file/imgui_single_file.h)
module :private;
#include "imgui.cpp"
#include "imgui_demo.cpp"
#include "imgui_draw.cpp"
#include "imgui_tables.cpp"
#include "imgui_widgets.cpp"

24
imgui.h
View File

@ -95,6 +95,8 @@ Index of this file:
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
IMGUI_EXPORT_BEGIN
//-----------------------------------------------------------------------------
// [SECTION] Forward declarations and basic types
//-----------------------------------------------------------------------------
@ -316,12 +318,14 @@ struct ImTextureRef
};
IM_MSVC_RUNTIME_CHECKS_RESTORE
IMGUI_EXPORT_END
//-----------------------------------------------------------------------------
// [SECTION] Dear ImGui end-user API functions
// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!)
//-----------------------------------------------------------------------------
namespace ImGui
IMGUI_EXPORT namespace ImGui
{
// Context creation and access
// - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts.
@ -1098,6 +1102,8 @@ namespace ImGui
} // namespace ImGui
IMGUI_EXPORT_BEGIN
//-----------------------------------------------------------------------------
// [SECTION] Flags & Enumerations
//-----------------------------------------------------------------------------
@ -3868,6 +3874,8 @@ struct ImFont
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
};
IMGUI_EXPORT_END
// This is provided for consistency (but we don't actually use this)
inline ImTextureID ImTextureRef::GetTexID() const
{
@ -3888,6 +3896,8 @@ inline ImTextureID ImDrawCmd::GetTexID() const
return tex_id;
}
IMGUI_EXPORT_BEGIN
//-----------------------------------------------------------------------------
// [SECTION] Viewports
//-----------------------------------------------------------------------------
@ -4013,12 +4023,15 @@ struct ImGuiPlatformImeData
ImGuiPlatformImeData() { memset((void*)this, 0, sizeof(*this)); }
};
IMGUI_EXPORT_END
//-----------------------------------------------------------------------------
// [SECTION] Constexpr alternatives to macros
// (requires C++17: see IMGUI_HAS_CONSTEXPR in imgui_macros.h)
// (requires C++17: see IMGUI_HAS_CONSTEXPR in imgui_macros.h. Exported by the C++20 module, which doesn't export macros)
//-----------------------------------------------------------------------------
#ifdef IMGUI_HAS_CONSTEXPR
IMGUI_EXPORT_BEGIN
// Version (= IMGUI_VERSION, IMGUI_VERSION_NUM)
inline constexpr char ImGuiVersion[] = IMGUI_VERSION;
inline constexpr int ImGuiVersionNum = IMGUI_VERSION_NUM;
@ -4044,9 +4057,10 @@ inline constexpr ImU32 ImCol32_AMask = IM_COL32_A_MASK;
// Size of a static C-style array (= IM_COUNTOF(), but won't compile with pointers)
template<typename T, size_t N> constexpr int ImCountOf(const T (&arr)[N]) { return IM_COUNTOF(arr); }
IMGUI_EXPORT_END
// Check that version and structures layouts are matching between compiled imgui code and caller (= IMGUI_CHECKVERSION())
namespace ImGui
IMGUI_EXPORT namespace ImGui
{
inline bool CheckVersion() { return IMGUI_CHECKVERSION(); }
}
@ -4059,7 +4073,7 @@ namespace ImGui
//-----------------------------------------------------------------------------
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
namespace ImGui
IMGUI_EXPORT namespace ImGui
{
// OBSOLETED in 1.92.9 (from July 2026)
IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // set current options for if you want to select a default format, picker type, etc. User will be able to change those settings, unless you pass the _NoOptions flag to your calls.
@ -4154,12 +4168,14 @@ namespace ImGui
//static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42
}
IMGUI_EXPORT_BEGIN
//-- OBSOLETED in 1.92.0: ImFontAtlasCustomRect becomes ImTextureRect
// - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y
// - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h
// - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph()
// We could make ImTextureRect an union to use old names, but 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api.
typedef ImFontAtlasRect ImFontAtlasCustomRect;
IMGUI_EXPORT_END
/*struct ImFontAtlasCustomRect
{
unsigned short X, Y; // Output // Packed position in Atlas

View File

@ -3,6 +3,10 @@
// Version, compile-time configuration and all preprocessor macros of the public API.
// - This is included by imgui.h: you don't need to include it yourself when using imgui.h.
// - Macros are not exported by C++20 modules: when using 'import imgui;' (see imgui.cppm), include this file to access them:
// #include "imgui_macros.h"
// import imgui;
// Use the same compile-time configuration (IMGUI_USER_CONFIG, imconfig.h, defines) as the one the module was built with.
#pragma once
@ -36,9 +40,24 @@
#define IMGUI_IMPL_API IMGUI_API
#endif
// Export declarations from the C++20 named module 'imgui' (see imgui.cppm):
// - IMGUI_EXPORT namespace ImGui { ... } exports a namespace and everything in it.
// - Declarations of the global namespace are exported by enclosing them in IMGUI_EXPORT_BEGIN / IMGUI_EXPORT_END.
// (out-of-line definitions of member functions can't be exported: keep them outside of those blocks)
// IMGUI_CXX_MODULE is defined by imgui.cppm only: don't define it yourself. In regular (header) builds, those expand to nothing.
#ifdef IMGUI_CXX_MODULE
#define IMGUI_EXPORT export
#define IMGUI_EXPORT_BEGIN export {
#define IMGUI_EXPORT_END }
#else
#define IMGUI_EXPORT
#define IMGUI_EXPORT_BEGIN
#define IMGUI_EXPORT_END
#endif
// Constexpr alternatives to some of the macros below (e.g. ImCol32() for IM_COL32()) are declared in imgui.h ('Constexpr alternatives to macros' section) when compiling as C++17 or later.
// (C++17 is required for 'inline' variables)
#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L
// (always the case for the C++20 module; C++17 is required for 'inline' variables)
#if defined(IMGUI_CXX_MODULE) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L
#define IMGUI_HAS_CONSTEXPR
#endif