I can implement a Lua C module in pure C by exporting a function luaopen_mymodule
that calls luaL_newlib
.
How can I do the equivalent in C++, using the sol2 (sol 3) library?
Lua expects the luaopen_mymodule
function to follow the lua_CFunction
protocol, which means:
int(lua_State *) noexcept
,local foo, bar = baz()
), and the actual Lua values to be returned must be on the top of the Lua stack.Additionally, the function must be extern "C"
so that its name is not mangled.
Specifically, the luaopen_mymodule
function will be called with two arguments that can usually be ignored, and will usually return a single value (typically a table) which will be passed back by the require
function. This means:
luaopen_mymodule
should return 1.Equipped with the necessary knowledge, we know how to implement luaopen_mymodule
:
sol::state_view
from the lua_State *
.sol::state_view
in the same way you'd use a sol::state
: call new_usertype()
, create_table()
, etc.luaopen_mymodule
, manually push onto the Lua stack the value you want to return (this means the stack will have one more value on it compared to when the function was called).sol allows you to manually push a value onto the Lua stack with the push
method on the sol::reference
class, which is also available on concrete "value" types such as sol::table
since they inherit publicly from sol::reference
.
Here's an example that implements the foo
module illustrated in /a/65660774, rewritten in C++ using sol:
#include <exception>
#include <sol/sol.hpp>
extern "C" {
// Define `FOO_LIB` as `__attribute__((visibility("default")))`,
// `__declspec(dllexport)`, etc.
FOO_LIB int luaopen_foo(lua_State *L) noexcept try {
sol::state_view lua(L);
auto result = lua.create_table();
result["foo"] =
sol::as_function([](lua_Integer a, lua_Integer b) { return a + b; });
result.push();
return 1;
// `sol::reference::push` itself returns 1,
// so the two lines above can be rewritten as:
// return result.push();
} catch (const std::exception &e) {
return luaL_error(L, "%s", e.what());
}
}