dear-imgui-sys
Low-level Rust bindings for Dear ImGui C++ library using bindgen.
Overview
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.
Key Features
- Direct C++ Bindings: Uses bindgen to generate bindings directly from Dear ImGui C++ headers
- MSVC ABI Compatibility: Includes fixes for MSVC compiler ABI issues with small C++ return types
- Docking Support: Built with Dear ImGui's docking branch for advanced window management
- WebAssembly Support: Full WASM compatibility with proper configuration for web targets
- Cross-Platform: Supports Windows, Linux, macOS, and WebAssembly
ABI Compatibility Issues and Solutions
The Problem
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:
- Linux: System V AMD64 ABI requires non-trivial C++ objects to be returned by pointer (bindgen#778)
- MSVC: Special handling for small non-POD types causes crashes (bindgen#2865)
- General: bindgen assumes register return for small classes (bindgen#2992)
Our Solution
We implement the solution pioneered by easy-imgui-rs, which provides a robust fix for MSVC ABI issues:
1. FFI-Safe Wrapper Types
// FFI-safe POD type equivalent to ImVec2
;
2. C Wrapper Functions
extern "C"
3. Selective Function Blocking
# msvc_blocklist.txt - Functions that need MSVC ABI fixes
ImGui::GetContentRegionAvail
ImGui::GetCursorScreenPos
ImGui::GetItemRectMin
# ... other problematic functions
4. Conditional Compilation
Why This Solution Works
- Platform-Specific: Only applies fixes where needed (MSVC targets)
- Type-Safe: Maintains Rust's type safety through proper conversions
- Minimal Impact: Only affects problematic functions, not the entire API
- Proven: Successfully used by multiple Dear ImGui Rust bindings
Build Configuration
The build system automatically detects the target environment and applies appropriate fixes:
// build.rs
if target_env == "msvc"
Related Issues
- rust-lang/rust-bindgen#778 - Wrong ABI used for small C++ classes on Linux
- rust-lang/rust-bindgen#2865 - C++ ABI in MSVC and function returning non-POD type
- rust-lang/rust-bindgen#2992 - bindgen wrongly assumes return by register for tiny C++ classes
Acknowledgments
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.
WebAssembly Support
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.
WASM Implementation Details
Our WASM support includes several key innovations:
- No C++ Cross-Compilation: Skips C++ compilation for WASM targets to avoid toolchain complexity
- Pre-generated Bindings: Uses reference bindings from native builds to ensure API compatibility
- Consistent API: Uses the same
ImGui_*function naming for both native and WASM targets - Platform Abstraction: Disables platform-specific functions that aren't available in WASM environments
- Thread-Local Storage: Properly handles TLS limitations in WASM environments
Building for WASM
- Install WASM target:
- Build for WASM:
# Basic WASM build
# With additional features
# Check compilation (faster)
# Build WASM example
- Use the build script (optional):
# Use the provided build script for automation
WASM Feature Flags
[]
= { = "0.1.0", = ["wasm"] }
# Or with additional features
= { = "0.1.0", = ["wasm", "docking"] }
Integration with wasm-bindgen
The generated WASM binaries are compatible with wasm-bindgen:
# Generate JavaScript bindings
WASM Usage Example
use *;
unsafe
Rendering in WASM
Since WASM doesn't have direct access to graphics APIs, you'll need to:
- Canvas API: Render ImGui draw data to HTML5 Canvas through JavaScript
- WebGL Backend: Implement a WebGL-based renderer for ImGui
- Existing Solutions: Use existing WASM ImGui renderers or JavaScript bindings
WASM-Specific Considerations
- No File System: File operations are disabled by default in WASM builds
- No Threading: Uses global context instead of thread-local storage
- Memory Management: Ensure proper cleanup of ImGui contexts in WASM environment
- Performance: WASM builds may have different performance characteristics
- Consistent API: Uses the same
ImGui_*naming convention for both native and WASM targets
Usage
This 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.
[]
= "0.1.0"
# For WASM targets
= { = "0.1.0", = ["wasm"] }
Potential Improvements
While our current solution works well, there are several areas where we could enhance the approach:
1. Automated Detection
// Future: Automatically detect problematic functions
2. Better Error Messages
// Future: Provide clear guidance when ABI issues are detected
compile_error!;
3. Cross-Platform ABI Fixes
Currently we only handle MSVC, but Linux and other platforms have similar issues. A comprehensive solution would:
- Detect non-trivial C++ types on all platforms
- Generate appropriate wrapper functions automatically
- Provide consistent behavior across all targets
4. Upstream Contributions
The ideal long-term solution would be improvements to bindgen itself:
- Better C++ ABI detection
- Automatic wrapper generation for problematic functions
- Platform-specific ABI handling
5. Alternative Approaches
Option A: Full Opaque Types
// Make all ImVec2-returning functions opaque
.opaque_type
.blocklist_function
Option B: Custom ABI Annotations
// Hypothetical: Explicit ABI annotations
extern "C" ImVec2_pod ;
Option C: Rust-Native Implementations
// Reimplement problematic functions in pure Rust
Comparison with Other Solutions
| 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 |
Specific Improvements We Could Make
1. Automated Wrapper Generation
Instead of manually maintaining hack_msvc.cpp, we could generate it automatically:
// build.rs enhancement
2. Better Function Detection
We could automatically detect which functions need fixes by parsing Dear ImGui headers:
// Automatically find ImVec2-returning functions
3. Runtime ABI Validation
Add runtime checks to ensure our fixes work correctly:
4. Cross-Platform Extension
Extend the solution to handle Linux ABI issues:
// Linux-specific wrappers for non-trivial types
extern "C"
Summary
Our implementation represents a best-practice solution for handling C++ ABI compatibility issues in Rust FFI bindings:
✅ What We Do Well
- Surgical Precision: Only fixes problematic functions, leaving the rest of the API untouched
- Type Safety: Maintains Rust's type system guarantees through proper conversions
- Platform Awareness: Conditional compilation ensures fixes only apply where needed
- Proven Approach: Based on the successful easy-imgui-rs implementation
- Clear Documentation: Comprehensive explanation of the problem and solution
🚀 Future Enhancements
- Automated Detection: Generate wrapper functions automatically from header analysis
- Cross-Platform Support: Extend fixes to Linux and other platforms with similar issues
- Runtime Validation: Add tests to ensure ABI compatibility across different environments
- Upstream Integration: Contribute improvements back to the bindgen project
🎯 Why This Matters
C++ ABI compatibility is a fundamental challenge when creating Rust bindings for C++ libraries. Our solution provides:
- Reliability: Eliminates crashes and memory corruption
- Maintainability: Clear structure that's easy to understand and extend
- Performance: No runtime overhead, compile-time solution
- Compatibility: Works across different MSVC versions and configurations
This approach can serve as a template for other Rust projects facing similar C++ FFI challenges.
License
This project follows the same license as Dear ImGui itself. See the Dear ImGui repository for license details.