| Crates.io | dear-imgui-sys |
| lib.rs | dear-imgui-sys |
| version | 0.1.0 |
| created_at | 2025-09-13 17:16:34.156647+00 |
| updated_at | 2025-09-13 17:16:34.156647+00 |
| description | Low level FFI bindings for Dear ImGui with docking support |
| homepage | https://github.com/Latias94/dear-imgui |
| repository | https://github.com/Latias94/dear-imgui |
| max_upload_size | |
| id | 1837934 |
| size | 4,659,547 |
Low-level Rust bindings for Dear ImGui C++ library using bindgen.
This crate provides unsafe Rust bindings to the Dear ImGui C++ library. It uses bindgen to automatically generate FFI bindings from the C++ headers, enabling direct access to the Dear ImGui API from Rust.
When using bindgen to generate bindings for C++ libraries, there are known ABI (Application Binary Interface) compatibility issues, particularly with functions that return small C++ class types. This affects multiple platforms:
We implement the solution pioneered by easy-imgui-rs, which provides a robust fix for MSVC ABI issues:
// FFI-safe POD type equivalent to ImVec2
struct ImVec2_rr {
float x, y;
};
extern "C" {
ImVec2_rr ImGui_GetContentRegionAvail() {
return _rr(ImGui::GetContentRegionAvail());
}
}
# msvc_blocklist.txt - Functions that need MSVC ABI fixes
ImGui::GetContentRegionAvail
ImGui::GetCursorScreenPos
ImGui::GetItemRectMin
# ... other problematic functions
pub fn content_region_avail(&self) -> [f32; 2] {
unsafe {
#[cfg(target_env = "msvc")]
{
let size_rr = sys::ImGui_GetContentRegionAvail();
let size: sys::ImVec2 = size_rr.into();
[size.x, size.y]
}
#[cfg(not(target_env = "msvc"))]
{
let size = sys::ImGui_GetContentRegionAvail();
[size.x, size.y]
}
}
}
The build system automatically detects the target environment and applies appropriate fixes:
// build.rs
if target_env == "msvc" {
// Apply MSVC ABI fixes
builder = builder
.header("hack_msvc.cpp")
.allowlist_file("hack_msvc.cpp");
// Block problematic functions
for line in blocklist_content.lines() {
builder = builder.blocklist_function(line.trim());
}
}
Our MSVC ABI fix implementation is based on the excellent work by rodrigorc/easy-imgui-rs. This solution provides a robust and maintainable approach to handling C++ ABI compatibility issues in Rust FFI bindings.
This crate provides comprehensive WebAssembly (WASM) support through the wasm feature flag. The implementation automatically handles the complexities of cross-compilation and provides a seamless experience for WASM development.
Our WASM support includes several key innovations:
ImGui_* function naming for both native and WASM targetsrustup target add wasm32-unknown-unknown
# Basic WASM build
cargo build --target wasm32-unknown-unknown --features wasm
# With additional features
cargo build --target wasm32-unknown-unknown --features "wasm,docking"
# Check compilation (faster)
cargo check --target wasm32-unknown-unknown --features wasm
# Build WASM example
cargo check --target wasm32-unknown-unknown --features wasm --example wasm_test
# Use the provided build script for automation
./build-wasm.sh
[dependencies]
dear-imgui-sys = { version = "0.1.0", features = ["wasm"] }
# Or with additional features
dear-imgui-sys = { version = "0.1.0", features = ["wasm", "docking"] }
The generated WASM binaries are compatible with wasm-bindgen:
# Generate JavaScript bindings
wasm-bindgen --out-dir wasm --web target/wasm32-unknown-unknown/debug/your_app.wasm
use dear_imgui_sys::*;
unsafe {
// Create ImGui context
let ctx = ImGui_CreateContext(std::ptr::null_mut());
ImGui_SetCurrentContext(ctx);
// Verify context is working
let current_ctx = ImGui_GetCurrentContext();
assert!(!current_ctx.is_null());
// Your ImGui code here...
// Note: You'll need to provide rendering through JavaScript/Canvas
// Cleanup
ImGui_DestroyContext(ctx);
}
Since WASM doesn't have direct access to graphics APIs, you'll need to:
ImGui_* naming convention for both native and WASM targetsThis is a low-level sys crate. Most users should use the higher-level dear-imgui crate instead, which provides safe Rust wrappers around these bindings.
[dependencies]
dear-imgui-sys = "0.1.0"
# For WASM targets
dear-imgui-sys = { version = "0.1.0", features = ["wasm"] }
While our current solution works well, there are several areas where we could enhance the approach:
// Future: Automatically detect problematic functions
fn needs_abi_fix(function: &Function) -> bool {
function.returns_small_cpp_class() &&
function.has_non_trivial_members() &&
target_env == "msvc"
}
// Future: Provide clear guidance when ABI issues are detected
#[cfg(target_env = "msvc")]
compile_error!(
"Function {} requires ABI fix. Add to msvc_blocklist.txt and create wrapper.",
function_name
);
Currently we only handle MSVC, but Linux and other platforms have similar issues. A comprehensive solution would:
The ideal long-term solution would be improvements to bindgen itself:
// Make all ImVec2-returning functions opaque
.opaque_type("ImVec2")
.blocklist_function(".*GetContentRegionAvail.*")
// Hypothetical: Explicit ABI annotations
extern "C" __attribute__((sysv_abi)) ImVec2_pod GetContentRegionAvail_pod();
// Reimplement problematic functions in pure Rust
pub fn get_content_region_avail() -> [f32; 2] {
// Direct implementation using ImGui internals
}
| Approach | Pros | Cons | Maintenance |
|---|---|---|---|
| Our Solution | ✅ Precise, Type-safe | ⚠️ Manual setup | 🟡 Medium |
| Full Opaque | ✅ Simple, Universal | ❌ Loses type info | 🟢 Low |
| Phantom Data | ✅ Forces stack return | ❌ Affects all types | 🟡 Medium |
| Pure Rust | ✅ No ABI issues | ❌ Reimplementation work | 🔴 High |
Instead of manually maintaining hack_msvc.cpp, we could generate it automatically:
// build.rs enhancement
fn generate_msvc_wrappers(functions: &[&str]) -> String {
let mut code = String::new();
for func in functions {
if returns_imvec2(func) {
code.push_str(&format!(
"ImVec2_rr ImGui_{}() {{ return _rr(ImGui::{}()); }}\n",
func, func
));
}
}
code
}
We could automatically detect which functions need fixes by parsing Dear ImGui headers:
// Automatically find ImVec2-returning functions
fn find_problematic_functions() -> Vec<String> {
// Parse imgui.h and find all functions returning ImVec2
// This would eliminate the need for manual blocklist maintenance
}
Add runtime checks to ensure our fixes work correctly:
#[cfg(all(test, target_env = "msvc"))]
mod abi_tests {
#[test]
fn test_content_region_avail_abi() {
// Verify that our wrapper returns the same values as direct calls
// This would catch ABI regressions
}
}
Extend the solution to handle Linux ABI issues:
// Linux-specific wrappers for non-trivial types
#ifdef __linux__
extern "C" {
void ImGui_GetContentRegionAvail_linux(ImVec2* out) {
*out = ImGui::GetContentRegionAvail();
}
}
#endif
Our implementation represents a best-practice solution for handling C++ ABI compatibility issues in Rust FFI bindings:
C++ ABI compatibility is a fundamental challenge when creating Rust bindings for C++ libraries. Our solution provides:
This approach can serve as a template for other Rust projects facing similar C++ FFI challenges.
This project follows the same license as Dear ImGui itself. See the Dear ImGui repository for license details.