我有一个使用Lua 5.2.1的Visual Studio 2008 C++ 03应用程序.我想用一个名为"foo"的模块扩展Lua,但是当我调用require("foo")我的Lua脚本时,我得到错误:
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\
Run Code Online (Sandbox Code Playgroud)
我的Lua脚本:
foo.bar()
Run Code Online (Sandbox Code Playgroud)
我的lua_foo.h文件:
#include <lua.h>
extern "C" int luaopen_foo( lua_State* L );
Run Code Online (Sandbox Code Playgroud)
我的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;
}
Run Code Online (Sandbox Code Playgroud)
这些编译成静态库"lua_foo.lib",它静态链接到我的主Lua可执行文件.
任何人都可以帮我理解我哪里出错了吗?谢谢.我宁愿避免使用c ++包装器(现在),我不想将这个库打包为主Lua引擎的单独DLL.
编辑
问题出在lua引擎代码中.我添加了luaL_requiref@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 );
}
Run Code Online (Sandbox Code Playgroud)
了解require机器的工作原理以及代码没有的原因非常重要.
require旨在查找文件系统和DLL中的Lua脚本.静态库不是DLL; 实际上,就C/C++而言,一旦完成链接,静态库与直接将这些.c/.cpp文件编译到应用程序中没有什么不同.
当require找到具有适当名称的DLL时,它会加载它并尝试查找名为的函数luaopen_<modname>,其中<modname>是模块的名称.如果是这样,它将执行此函数并将其返回的值存储在已加载模块的内部数据库中.
调用require模块将返回此函数返回的内容; 如果模块已经加载,则从数据库中提取返回值并直接返回.
简单的调用luaopen_foo将不会做任何的这个.实际上,简单地调用这个函数是个坏主意; 它是一个Lua函数,需要被称为Lua函数(即:你需要将它推到Lua堆栈上lua_pushcfunction并用它来调用它lua_call等等).
如果要创建本地模块(一个不在Lua脚本或DLL中,但从代码中公开),那么您需要使用Lua工具来完成此操作.具体来说,使用luaL_requiref:
luaL_requiref(L, "foo", luaopen_foo, 0);
Run Code Online (Sandbox Code Playgroud)
调用此而不是luaopen_foo直接调用.这将自动地从寄存器返回值luaopen_foo用require的加载的模块的内部数据库.因此,后续调用require "foo"将返回此表.
还有一件事:do是Lua中的关键字 ; 您不应该为Lua表键名使用关键字.你可以,但你总是要引用它们(即:你的脚本必须foo["do"](...)要调用它).