How can I extend Lua with a C ++ static library?

I have a Visual Studio 2008 C ++ 03 application that uses Lua 5.2.1. I would like to extend Lua with a module called "foo", but when I call require("foo") in my Lua script, I get an error:

 foo_test.lua:1: module 'foo' not found: no field package.preload['process'] no file '!\lua\process.lua' no file '!\lua\process\init.lua' no file '!\process.lua' no file '!\process\ 

My Lua script:

 foo.bar() 

My lua_foo.h file is:

 #include <lua.h> extern "C" int luaopen_foo( lua_State* L ); 

My lua_foo.cpp file:

 #include "lua_foo.h" #include <lua.hpp> static int l_bar( lua_State *L ) { puts( "in bar()" ); return 1; } int luaopen_foo( lua_State *L ) { static const luaL_Reg foo[] = { { "bar", l_bar }, { NULL, NULL } }; luaL_newlib( L, foo ); return 1; } 

They are compiled in the static library "lua_foo.lib", which is statically linked to my main Lua executable.

Can someone help me figure out where I am going wrong? Thank you I would prefer to avoid C ++ wrappers (for now), and I don't want to pack this library as a separate DLL from the main Lua mechanism.


EDIT

The problem was in the lua engine code. I added the luaL_requiref for @NicolBolas.

 lua_State* L = luaL_newstate(); if( NULL != L ) { luaL_openlibs( L ); luaL_requiref( token.get(), "foo", luaopen_foo, 1 ); luaL_dofile( L, "foo_test.lua" ); lua_close( L ); } 
+4
source share
2 answers

It is important to understand how the require machine works, and therefore why your code does not work.

require designed to search for Lua scripts in the file system and DLL . Static libraries are not DLLs; indeed, with C / C ++, once you finish linking, static libraries are no different from compiling these .c / .cpp files into your application directly.

When require finds a DLL with the appropriate name, it loads it and tries to find a function called luaopen_<modname> , where <modname> is the name of the module. When this happens, it will execute this function and save the value returned by it in the internal database of loaded modules.

Calling require for the module will return all returned functions; if the module is already loaded, then the return value is pulled from the database and returned directly.

Just calling luaopen_foo will not do any of this. Indeed, simply calling this function is a bad idea; it is a Lua function and should be called as a Lua function (i.e. you need to push it onto the Lua stack using lua_pushcfunction and call it using lua_call , etc.).

If you want to create a local module (one of them is not in a Lua script or DLL, but presented from your code), you need to use Lua tools for this. In particular, use luaL_requiref :

 luaL_requiref(L, "foo", luaopen_foo, 0); 

Call this instead of calling luaopen_foo directly. This will automatically register the return value from luaopen_foo with require internal database of loaded modules. Thus, subsequent calls to require "foo" will return this table.

One more thing: do is a keyword in Lua; You should not use keywords for Lua table key names. You can, but you should always quote them (i.e. your script must do foo["do"](...) to call it).

+7
source
  • luaopen_foo creates a table with one function in it, but it does not expose it to Lua in any way. You need to assign it to access your scripts if you want to access it. You can do this using the package engine or simply assign it to the global one (this is what the Lua built-in libraries do).
  • You have a field called do , which is problematic if you want to use the foo.do syntax because do is the keyword.
  • The return value of the Lua function tells Lua how many values โ€‹โ€‹remain on the stack. Your l_do function has its return value.
  • In the case of luaopen_foo , since you call it directly and ignore its return value, there is no need to return it at all.

Change the code as follows:

 static int l_bar( lua_State *L ) { puts("l_bar called."); return 0; } void luaopen_foo( lua_State *L ) { static const struct luaL_Reg foo[] = { { "bar", l_bar }, { NULL, NULL } }; luaL_newlib( L, foo ); // create table containing `bar` lua_setglobal(L, "foo"); // assign that table to global `foo` } 

And change your script to this:

 foo.bar() 
+2
source

All Articles