sol2 C++ Lua Bindings

repository·develop·Indexed 25 days ago

https://github.com/thephd/sol2

A high-performance, header-only C++17 library for binding to Lua (5.1+ and LuaJIT). sol2 abstracts the Lua C API to support complex types including containers, smart pointers, and user-defined types with minimal overhead. It provides utilities for registering usertypes, managing coroutines, script sandboxing via sol::environment, and converting C++ iterables into Lua tables or return values.

Tokens
39.7K
Snippets
76
Records
277
Agent score
89%

What's inside sol2

  1. Use `sol::environment` for script sandboxing

    develop

    sol::environment is a specialized sol::table used to provide a specific scope for local variables during script execution. It allows you to encapsulate variables so they are not stored in the global environment.

    Because sol::environment inherits from sol::table, it supports all standard table operations. You can also manipulate its metatable (e.g., using sol::metatable_key) to set an __index that points to a fallback table (like the global table), allowing the environment to read from globals while keeping its own writes local.

    Note on Copying: Copying a sol::environment object does not perform a deep copy of the Lua table; it creates a new reference to the same Lua object.

  2. Understand sol2 feature capabilities

    develop

    sol2 provides a wide range of features for Lua/C++ integration, including support for user-defined types (UDTs), table manipulation, and advanced Lua control flow. Key capabilities include:

    • Tables & Chaining: Full abstraction for Lua tables (e.g., mytable["key"] = value) and deep querying (e.g., mytable["key1"]["key2"]). sol2 specifically avoids crashing during chaining if a key is missing when using sol::optional.
    • User-Defined Types (UDTs): Bind C++ types to Lua, including member functions (my_object:foo()) and table variables (my_object.var = 24).
    • Function Binding: Support for lambdas, member functions, and free functions, including overloading based on arity or type.
    • Advanced Lua Control: Support for Lua threads, coroutines, and yielding C++ functions back to Lua.
    • Error Handling: Protected function calls using lua_pcall for error handling and trampolining.
    • Data Handling: Support for multi-return values (via std::tuple), variadic/variant arguments, and arbitrary keys (using userdata or other tables as keys).
    • Environment Management: Abstractions for manipulating Lua environments, useful for sandboxing.
    • Compatibility: Supports Lua 5.1, 5.2, 5.3, and LuaJIT, with support for no-RTTI and no-exception environments.
  3. Understand sol2 Usertypes

    develop

    Usertypes are the mechanism sol2 uses to communicate C++ classes to the Lua runtime. They allow you to bind C++ classes to Lua tables and specific blocks of C++ memory, enabling Lua to treat userdata as native classes.

    Key Characteristics:

    • Runtime Extensibility: Usertypes are extensible in both Lua and C++. For dynamic callbacks or overridable functions, use a std::function member variable within your C++ class and provide getters/setters via sol::property.
    • Smart Pointer Support: Works with std::unique_ptr<T>, std::shared_ptr<T>, and others by default. You can extend this to custom smart pointers using sol::unique_usertype<T> traits.
    • Automatic Operator Binding: Certain operators are detected and bound automatically.
    • Memory Layout: The first sizeof(void*) bytes of a usertype always contain a pointer to the typed C++ memory, ensuring compatibility with other Lua systems.
    • Late Registration: You can push userdata to Lua before registering the usertype. Once the usertype is registered, all existing userdata of that type will be updated with the newly defined methods and properties.
  4. Understand sol2 performance benchmarks

    develop

    sol2 performance measurements focus on the overhead imposed by the library when abstracting the Lua C API. These benchmarks compare the cost of various operations against other Lua binding libraries.

    Key performance considerations:

    • High-performance variants: sol2 achieves its top-tier performance by utilizing specific high-performance API variants, such as c_call.
    • Benchmark Methodology: Measurements are typically performed using nonius and, in some cases, involve compiling against a DLL version of Lua to ensure consistent overhead across different libraries by avoiding Link Time Optimizations (LTO).
    • Interpreting Results: In the provided benchmark graphs, lower bars indicate better performance (lower average execution time). Error bars indicate potential variance; if error bars are similar in size and execution times are close, the difference in speed is likely not significant despite different abstraction techniques.
  5. Review sol2 licensing for commercial use

    develop
    The sol2 library and its dependencies are licensed under the MIT License or CC0 1.0 Universal. This makes the project safe for use in commercial software. You may copy the license text provided in the repository directly into your own attributions or licenses file.
  6. Handle pointer ownership and smart pointers

    develop

    sol does not take ownership of raw pointers. It will not call delete on them because raw pointers do not imply ownership. To manage memory correctly when passing pointers to or from Lua, use one of the following patterns:

    1. Smart Pointers: Use std::unique_ptr or std::shared_ptr to allow sol to manage the lifecycle.
    2. Value Returns: Simply return the value instead of a pointer.
    3. Static References: If the object is guaranteed to outlive the Lua state, you can pass a raw pointer as a reference.
    4. Handling Nil: sol can detect nullptr and push sol::lua_nil. However, if you know a value is nil, it is better to explicitly return std::nullptr_t or sol::lua_nil.
  7. Customize container support with container traits

    develop
    If you encounter compiler errors when attempting to serialize or iterate over a type that possesses begin and end functions but is not recognized as a standard container, you can use container customization traits. These traits allow you to define how sol2 interacts with your custom container types and which operations are permitted on them.
  8. Implement Lua iteration for custom containers

    develop

    To support Lua iteration (pairs and ipairs), you can implement specific extension points.

    Recommended Approach: Instead of implementing pairs or ipairs directly, override begin(lua_State*, T&) and end(lua_State*, T&). The default implementation will handle the rest.

    Advanced/Manual Implementation:

    • static int next(lua_State*): Implement this if you need to define a custom iteration function for pairs() calls.
    • static int pairs(lua_State*): Works in Lua 5.2+. For Lua 5.1/LuaJIT, calling pairs(c) may crash because Lua expects a table; use c:pairs() instead.
    • static int ipairs(lua_State*): Works in Lua 5.2, deprecated in 5.3. For Lua 5.1/LuaJIT, use c:ipairs() to avoid crashes.