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 <stdio.h>
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 <stdio.h>
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 <stdio.h> 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运行程序了。
|
请发表评论