Why
sol2 is deeply woven into the Lua binding layer of this project. It works, but it carries real overhead — compile times are brutal, the header is massive, and runtime performance leaves headroom on the table.
LuaBridge3 is a serious alternative worth evaluating. It's header-only, dependency-free, MIT-licensed, and actively maintained. Per official docs:
"LuaBridge3 has been heavily optimized and now competes directly with sol2 — one of the fastest C++/Lua binding libraries — across most workloads. In fact, LuaBridge3 outperforms sol2 in certain scenarios such as member function calls from Lua and global table writes, while remaining more compact and faster to compile."
Benchmarks
| Operation |
sol2 |
LuaBridge3 |
Winner |
| Increment (Lua→C++) |
225 ms |
85 ms |
LuaBridge3 (2.6× faster) |
| String Argument |
188 ms |
188 ms |
Tie |
| String View Argument |
149 ms |
149 ms |
Tie |
| String Iterator |
255 ms |
256 ms |
Tie |
The Lua→C++ call path — the hot path in any modding/scripting integration — is where LuaBridge3 pulls ahead significantly.
LuaBridge3 ships its own benchmark suite (benchmark_luabridge3.cpp vs benchmark_sol3.cpp) covering:
- Table read/write access
- Member function calls from Lua
- Global table writes
- Chained table access (sol2 still holds an edge here)
Per the LuaBridge3 Manual, the performance gap is "negligible for most use cases" — but compile times and binary size favor LuaBridge3 meaningfully.
With -O3: sol2 Increment drops to 32ms / C++ calls to 56ms. Without aggressive optimization, sol2 is significantly slower. LuaBridge3 performs well even at -O2.
What LuaBridge3 Brings
| Feature |
Detail |
| License |
MIT — no usage restrictions |
| Integration |
Header-only, single #include, zero dependencies |
| Lua compatibility |
PUC-Lua 5.1–5.5, LuaJIT 2.1, Luau, Ravi |
| C++ standard |
C++17 required, C++20/23 features supported |
| C++20 coroutines |
Native coroutine integration — CppCoroutine<R> |
| Type support |
Containers, smart pointers, std::optional, std::variant, std::string_view |
| Compile times |
Scales linearly with binding surface — sol2 is known for brutal compile times |
| Package managers |
Available on vcpkg |
| Class binding |
Multiple inheritance, property/function proxies, constructor factories, extensible classes |
The Problem
sol2 is not a drop-in swap target. The binding layer relies on sol2's API surface throughout — type mapping, stack manipulation, state management, error handling, lifetime semantics. A naive replacement would produce a tangled mess.
This needs a proper architecture refactor:
- Abstract the binding layer behind a thin internal interface so the underlying library becomes an implementation detail
- Define clear ownership semantics — sol2's
sol::object / sol::table / sol::reference patterns differ from LuaBridge3's luabridge::LuaRef
- Re-evaluate error handling — sol2 uses exceptions heavily; LuaBridge3 supports both exception and noexcept modes
- Audit compile-time cost — sol2's template metaprogramming is heavy; LuaBridge3 is leaner but the migration itself must not regress build times
Prior Art
Worth studying how other RE/modding projects structure their Lua integrations:
Proposed Approach
- Profile current sol2 integration — identify hot paths, measure compile times, catalog all sol2 API surface in use
- Build an abstraction layer —
ILuaBridge interface wrapping calls, table access, type conversion, error handling
- Implement LuaBridge3 backend behind that interface — compare perf, compile time, binary size
- Gradual migration — module-by-module, keeping sol2 as fallback until parity is verified
- Benchmark parity — run the same workload suite against both backends before cutting over
Acceptance Criteria
Labels
enhancement (applied) — requesting creation of: lua, refactoring, performance
Milestone: Architecture Improvements (if/when created)
Why
sol2 is deeply woven into the Lua binding layer of this project. It works, but it carries real overhead — compile times are brutal, the header is massive, and runtime performance leaves headroom on the table.
LuaBridge3 is a serious alternative worth evaluating. It's header-only, dependency-free, MIT-licensed, and actively maintained. Per official docs:
Benchmarks
Alterise/lua-benchmarks — sol2 vs LuaBridge3 head-to-head
The Lua→C++ call path — the hot path in any modding/scripting integration — is where LuaBridge3 pulls ahead significantly.
Official LuaBridge3 benchmarks (in-repo, commit
0ca8ef4)LuaBridge3 ships its own benchmark suite (
benchmark_luabridge3.cppvsbenchmark_sol3.cpp) covering:Per the LuaBridge3 Manual, the performance gap is "negligible for most use cases" — but compile times and binary size favor LuaBridge3 meaningfully.
StackOverflow discussion — real-world observations
With
-O3: sol2 Increment drops to 32ms / C++ calls to 56ms. Without aggressive optimization, sol2 is significantly slower. LuaBridge3 performs well even at-O2.What LuaBridge3 Brings
#include, zero dependenciesCppCoroutine<R>std::optional,std::variant,std::string_viewThe Problem
sol2 is not a drop-in swap target. The binding layer relies on sol2's API surface throughout — type mapping, stack manipulation, state management, error handling, lifetime semantics. A naive replacement would produce a tangled mess.
This needs a proper architecture refactor:
sol::object/sol::table/sol::referencepatterns differ from LuaBridge3'sluabridge::LuaRefPrior Art
Worth studying how other RE/modding projects structure their Lua integrations:
Proposed Approach
ILuaBridgeinterface wrapping calls, table access, type conversion, error handlingAcceptance Criteria
Labels
enhancement(applied) — requesting creation of:lua,refactoring,performanceMilestone: Architecture Improvements (if/when created)