我有一个使用Lua 5.2.1的Visual Studio 2008 C ++ 03应用程序。我想用一个名为" foo"的模块扩展Lua,但是当我在Lua脚本中调用require("foo")
时,我收到错误:
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\
我的Lua脚本:
foo.bar()
我的lua_foo.h文件:
#include <lua.h>
extern "C" int luaopen_foo( lua_State* L );
我的lua_foo.cpp文件:
#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;
}
这些被编译到静态库&#34; lua_foo.lib&#34;它与我的主要Lua可执行文件静态链接。
有人可以帮我理解我哪里出错吗?谢谢。我宁愿避免使用c ++包装器(现在),我不想将这个库打包为主Lua引擎的单独DLL。
修改
问题出在lua引擎代码中。我根据@NicolBolas的建议添加了luaL_requiref
。
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 );
}
答案 0 :(得分:6)
了解require
机器的工作原理以及代码没有的原因非常重要。
require
旨在查找文件系统中的Lua脚本和 DLL 。静态库不是DLL;实际上,就C / C ++而言,一旦完成链接,静态库与直接将.c / .cpp文件编译到应用程序中没有什么不同。
当require
找到具有适当名称的DLL时,它会加载它并尝试查找名为luaopen_<modname>
的函数,其中<modname>
是模块的名称。如果是这样,它将执行此函数并将其返回的值存储在已加载模块的内部数据库中。
为模块调用require
将返回此函数返回的内容;如果模块已经加载,则从数据库中提取返回值并直接返回。
只需致电luaopen_foo
,就不会执行任何此类。实际上,简单地调用这个函数是个坏主意;它是一个Lua函数,需要被称为作为Lua函数(即:你需要用lua_pushcfunction
将它推到Lua堆栈上并用lua_call
调用它等等等)。
如果要创建本地模块(一个不在Lua脚本或DLL中,但从代码中公开),那么您需要使用Lua工具来执行此操作。具体来说,请使用luaL_requiref
:
luaL_requiref(L, "foo", luaopen_foo, 0);
请拨打此电话,而不是直接拨打luaopen_foo
。这将自动注册luaopen_foo
的返回值和require
的已加载模块的内部数据库。因此,对require "foo"
的后续调用将返回此表。
还有一件事:do
是Lua中的关键字;您不应该为Lua表键名使用关键字。你可以,但你总是要引用它们(即:你的脚本必须foo["do"](...)
来调用它。)
答案 1 :(得分:2)
luaopen_foo
创建一个包含一个函数的表,但它不会以任何方式将它暴露给Lua。如果要访问脚本,则需要将其分配给脚本可以访问的内容。您可以使用包机制执行此操作,或者只将其分配给全局(这是Lua的内置库所执行的操作)。do
的字段,如果您想使用foo.do
语法,则会出现问题,因为do
是关键字。l_do
函数位于其返回值。luaopen_foo
的情况下,由于您直接调用它并忽略它的返回值,因此根本不需要它返回任何内容。将您的代码更改为:
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`
}
将脚本更改为:
foo.bar()