http://hi.baidu.com/darkpaladin/blog/item/00468551e6b67e2542a75bb2.html
[转]C/C++中调用LUA函数
2007-04-27 11:29
1 配置工作环境
a 下载LUA安装包 sf_200472410155.zip
b 然后,解压用于WIN32下的安装包。放在一个盘的目录下如:C:/LUA50
c 打开VC++6.0,点击Project下的Setting中将include目录设为C:/LUA50。 并在LIB库中加入lua+lib.lib ,并将C:/LUA50下的Lua+lib.dll ,Lua+lib.lib拷贝到程序当前所在目录
【( 风舞影天 的说明:来自www.luachina.net
vc下使用lua都很类似(6.0,2003,2005),如果你能明白一般库的使用,那么想要使用lua很简单
如果是使用纯的lua库(指不使用第三方库,如luabind,lubplus等),一般你可能会得到三种形式的lua包
1,从www.lua.org下载的源码包
2,由别人提供的编译好的lua库包
3,由别人提供的编译好的lua动态链接库包
对于第一种包你只需要自己编译出lua库然后就可以象第2种方式一样使用了(实际上第三种包的使用方式只是多了一个步骤)
如何编译LUA源码呢?解压后打开lua目录的INSTALL文件,里面列出了三个工程
library: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c
lmem.c lobject.c lopcodes.c lp***r.c lstate.c lstring.c
ltable.c ltm.c lundump.c lvm.c lzio.c
lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c
ltablib.c lstrlib.c loadlib.c linit.c
interpreter: library, lua.c
compiler: library, luac.c print.c
library,interpreter,compiler,实际上这三个你只需要第一个library,它是让你能够将LUA嵌入你的程序的库, interpreter是解释器,也就是传说中的lua.exe,可以把它看成一个使用lua库的示例程序,第三个compiler是将lua文本编译成 lua的二进制格式,所以一般来讲,第二和第三个对你来讲都不是特别重要或者根本就不会使用到的。
要编译出这三个库,你可以打开你的IDE(指VC),然后建三个工程,把每个工程对应的文件加入你建立的对应的工程,然后编译即可生成你库文件(*.lib),lua.exe和luac.exe
INSTALL中也提到了可以使用luavs.bat来生成,看看这个批处理文件的内容cd src
cl /O2 /W3 /c /DLUA_BUILD_AS_DLL l*.c
del lua.obj luac.obj
link /DLL /out:lua51.dll l*.obj
cl /O2 /W3 /c /DLUA_BUILD_AS_DLL lua.c
link /out:lua.exe lua.obj lua51.lib
cd ..
如果你能看懂它也就知道其实和上面我说的步骤大同小异了(它生成的是动态链接库而不是静态库),至于有人说找不到cl.exe,那是因为你的环境变量里没 有设置vc的二进制文件目录而导致无法找到cl.exe(只要你安装了VC,那么是肯定会有这个文件的)(作为一个程序,如果不知道环境变量这个东东,我 觉得还是有点悲哀哈)
好了,现在你有了头文件、库文件(或是动态链接库,而动态链接库除了.dll还会提供一个.lib文件),那么剩下的事情就是如何将LUA嵌入你的程序中了。
首先是在你使用到LUA函数的地方你肯定要#include ,而实际上lua有三个头文件,lua.h, lualib.h,lauxlib.h,你可以打开这些头文件查看有那些LUA API(lua5.x改变了lua4.x的一些函数名,只不过lua5.0.2使用了一些宏来兼容以前的函数名,而5.1.1则去除掉了这些宏,你可以查 看这些头文件来看那些API函数名已经改掉了,比较常见的是lauxlib.h)
ps:使用C++的同学别忘了你链接库采用的代码生成方式是C++还是C,因为C++最终会改变其函数名(如lua_open改成 lua_open@4),一般都是选择生成C的代码生成方式,因为不同的C++编译器改变的函数名规则是很可能不同的,至于为什么会改名想想函数重载,具 体的去GOOGLE吧。而如果你编译链接库时采用的是C代码生成方式,别忘了在#include时加上extern "C"
当然你仅仅包含了头文件是肯定会出现链接错误的,因为在链接的时候无法找到对应函数的代码,而这些代码都包含在静态库文件*.lib中(或是动态链接库的*.dll中),VC中加入链接库文件有两种方式,一是工程里设置,二是使用
#pragma comment(lib,"****.lib")
)】
例一:
main.cpp
//--------------------------------------------------
#include
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* LUA接口声明*/
lua_State* L;
int main ( int argc, char *argv[] )
{
/* 初始化 Lua */
L = lua_open();
/*载入LUA库 */
lua_baselibopen(L);
/* 运行LUA脚本 */
lua_dofile(L, "test.lua");
/* 清除 Lua */
lua_close(L);
return 0;
}
脚本test.lua:
用记事本写入以下代码,改扩展名为lua即可
-- simple test
print "Hello, World!"
例2:
首先用记事本写个Lua文件。
----fun.lua--------
function add ( x, y )
return x + y
end
在前面的教程,调用lua_dofile()将执行脚本。
本章里,脚本定义为一个函数。
用lua_dofile()只简单的使这个函数在我们的程序中变为有效。
LUA的函数可以接收多个参数,并可以返回多种类型的结果,这
里使用了堆栈。
为了调用一个LUA函数,我们首先要把函数压栈。
这个函数的结果由参数决定,所以,我们要调用函数将需要
lua_call(),调用这个函数之后,返回的结果将在堆栈中存在。
整个步骤:
1.用lua_getglobal()把add函数放入堆栈
2.用lua_pushnumber()把第一个参数压入堆栈
3.用lua_pushnumber()把第二个参数压入堆栈
4.用lua_call()调用函数。
5,现在用lua_tonumber从堆栈头取出结果
6,最后用lua_pop从堆栈中移除结果值。
代码:luaadd.cpp
如果你喜欢用C代替C++,改名为luaadd.c,并且除去
extern "C"即可
#include
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* the Lua interpreter */
lua_State* L;
int luaadd ( int x, int y )
{
int sum;
/* the function name */
lua_getglobal(L, "add");
/* the first argument */
lua_pushnumber(L, x);
/* the second argument */
lua_pushnumber(L, y);
/* call the function with 2
arguments, return 1 result */
lua_call(L, 2, 1);
/* get the result */
sum = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
return sum;
}
int main ( int argc, char *argv[] )
{
int sum;
/* initialize Lua */
L = lua_open();
/* load Lua base libraries */
lua_baselibopen(L);
/* load the script */
lua_dofile(L, "add.lua");
/* call the add function */
sum = luaadd( 10, 15 );
/* print the result */
printf( "The sum is %d\n", sum );
/* cleanup Lua */
lua_close(L);
return 0;
}
二:lua中调用c函数
我们用C/C++创建一个函数并告诉Lua解释器,然后在Lua中调用这个函数并使用函数的返回值。
定义一个C/C++函数:
要想C/C++中的函数能被Lua调用,函数定义必须这样:
代码:typedef int (*lua_CFunction) (lua_State *L);
也就是说,函数必须以Lua解释器作为参数,并且返回值为int类型。既然Lua解释器作为函数的参数,那么实际上函数可以从栈中取得任意多个参数。下面 我们将看到,返回的整数值代表入栈的值的数目。如果有一个C/C++函数,你想在Lua中调用他,很容易封装一下就可以满足上述要求。
下面的C++的average函数例子中,可以清楚地看到Lua中调用C/C++函数是如何实现的。
1. lua_gettop()返回栈顶的下标索引,由于Lua中栈的下标从1开始,这个返回值实际上也就是函数参数的个数。
2. For循环计算各个参数总和。
3. Average的参数是通过调用lua_pushnumber()入栈的。
4. 然后参数之和被入栈。
5. 最后,函数返回值为2,表明有两个返回值,并且已经入栈。
函数被定义之后,我们必须告诉Lua编译器他的存在,这在main()函数中,在Lua解释器被初始化,类库加载之后完成的。
将下面的代码保存为luaavg.cpp,如果你喜欢用C而不是C++,需要保存文件为luatest.c并且把extern去掉。
#include
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* the Lua interpreter */
lua_State* L;
static int average(lua_State *L)
{
/* get number of arguments */
int n = lua_gettop(L);
double sum = 0;
int i;
/* loop through each argument */
for (i = 1; i <= n; i++)
{
/* total the arguments */
sum += lua_tonumber(L, i);
}
/* push the average */
lua_pushnumber(L, sum / n);
/* push the sum */
lua_pushnumber(L, sum);
/* return the number of results */
return 2;
}
int main ( int argc, char *argv[] )
{
/* initialize Lua */
L = lua_open();
/* load Lua base libraries */
lua_baselibopen(L);
/* register our function */
lua_register(L, "average", average);
/* run the script */
lua_dofile(L, "avg.lua");
/* cleanup Lua */
lua_close(L);
return 0;
}
下面是一个简单的Lua脚本:
-- simple test
代码print "Hello, World!"
确认它能运行。
编译:
使用你喜欢的编译器编译上面保存的C/C++文件,下面以Linux为例:
命令行键入:
代码:g++ luatest.cpp -llua -llualib -o luatest
如果没有错误的话,运行程序:
代码:./luatest
程序应该打印出:Hello, World!
如果你不是Linux操作系统,使用的是Vc++编译器,你需要:
1. 创建一个新的win32控制台应用工程。
2. 将文件luatest.cpp添加到你的工程中。
3. 到Project, Settings点击Link页。
4. 添加lua+lib.lib到Object/library modules列表中。
5. 按F7编译程序。
运行程序以前,你需要确保lua+lib.dll文件放在windows可以找到的地方,将这个文件从C:\Program Files\Lua-5.0拷贝到Visual C++ project目录,如果编译没有错误的话,现在可以Ctrl+F5运行程序了。