《Programming in Lua》里面提到“扩展扩展Lua的基本方法之一就是为应用程序注册新的C函数到Lua中去”,还有“当你打算使用C函数来扩展Lua的时候,即使你仅仅只想注册一个C函数,将你的C代码设计为一个库是个比较好的思想:不久的将来你就会发现你需要其他的函数”。 学习这部分用去了我几个小时来实践。我想把我遇到的问题和解决方法和大家分享一下。没准什么时候我自己都忘了怎么做,那时候还可以用这篇文章回忆一下。 我是跟着书学的,这里难免copy一些书上的东西。因为思路还没有整理好,可能会讲得比较乱。还会提到一些不太相关的问题。 我先用VC++ 2005建了一个空项目,在里面添加了一个文件:ldirlib.c。文件内容贴一下吧。
l_dir这个函数的内容基本上是我从MSDN上抄来的,功能是列出指定路径下的文件和目录。因为只是供学习之用,我也没考虑可移植性。 就像书上说的,第一步,定义库函数,我这里是l_dir;第二步,声明一个数组,保存所有的函数和他们对应的名字,我这里是dir_funcs;第三步,定义一个函数,该函数可以被成为“loader”,用来将前面数组中的C函数注册到Lua中去,我这里是luaopen_dirlib。头文件ldirlib.h内容如下:
头文件定义了库名字。DIRLIB_API用于输出函数。 然后,我修改项目设置,将代码编译成DLL。 那么,在哪里使用这个DLL?虽然我学了两个星期Lua了,但是脑子里面还是乱麻一团,没有清晰的认识。可能是因为这阵子经常熬夜的缘故吧。我就这么考虑了一番,在Lua代码里面,可以直接使用math.sin(1)、os.exit()这样的方法调用标准库提供的函数,这些函数的本质也是C函数。使用lua命令执行Lua程序的时候,解释器应该已经自动加载了标准库。标准库的实现方式和上面介绍的基本一致。那么我刚才编译的DLL算第三方库吧,用来扩展Lua的,那就是在Lua程序里面调用了。那怎么使用这个DLL呢?书上介绍的是这样的,
第一个参数是库文件的完整路径,第二个参数是用于打开库的函数的名字。我打开一个DOS窗口,执行lua解释器。输入如下内容,
package.loadlib这个函数所做的工作是这样的。先调用ll_register,在registry中以第一个参数添加前缀LIBPREFIX宏作为key查找是否存在value。如果未找到,就创建一个userdata(const void *类型),然后取registery["_LOADLIB"]的metatable,再将这个它设置为刚创建的userdata的metatable,然后在registry中添加一个域,这个域以库完整路径添加前缀LIBPREFIX宏作为key,以userdata作为value。如果ll_register没加载成功,调用ll_load,这个函数的实现是根据操作系统的不同而不同的,在windows系统下调用LoadLibraryA加载DLL。如果加载成功,再调用ll_sym,这个函数的实现也是根据操作系统的不同而不同的,在windows系统下调用GetProcAddress。最后将C函数压栈。我们得到了func,它也就是luaopen_dirlib。你必须再执行这个函数func,才能真正加载库。再输入如下内容,
这样就打开了我写的库。执行func时做的工作主要是建立一个表,表名就是luaL_register函数的第二个参数,这里是LUA_DIRLIBNAME,即库名。设置该表的一个域,key是上面介绍的结构数组中每个结构的第一个值(Lua程序中使用的函数名),value就是结构的第二个值(真正的C函数)。可以参考Lua加载标准库的过程。接下来,我输入了如下内容,
这就是在Lua程序中调用dir的方法,给它传的参数是表示路径的字符串,注意“\”要用“\\”表示。根据Lua参考手册和Lua语言的源代码来看,在Lua程序中,给Lua标准库中的函数传什么参数是由对应的C函数的实现决定的。dir函数对应的C函数是l_dir,它的实现里需要一个参数,就是路径,它的返回值是一个表。所以如果你要写一个第三方库来扩展Lua,你必须提供文档,说明库函数的原型。根据l_dir这个函数的实现可以知道,它在栈中放入一个表,这个表的内容大概是这样:{[1]="a", [2]="b", ...}。然后我输入如下内容,
窗口里面打印出一列文件和目录的名称。当然了,你也可以把在窗口中输入的内容整理到一个文件中,直接在命令行模式下用“Lua”命令执行这个文件。毕竟都是Lua代码嘛。 说到这里,大部分内容已经说完了。 再多说几句。其实,用C函数扩展Lua,就是添加Lua函数。在C应用中也可以调用Lua函数,所以你用于扩展Lua的C函数也可以间接的在C应用中调用。Lua就是这样,可以用C函数扩展Lua,Lua可以嵌入到C应用中。Lua本身是用C语言实现的,那么当你将Lua嵌入到C应用中的时候,也就是在用C间接调用C,中间层就是Lua。跳出来看,或者说从整体去把握,会有不同的感悟。 以上的想法、做法都是特定于我自己的开发环境。如果你的开发环境和我的不一样,我提供的方法仅供参考。你要尝试不同方法来得到解决问题的办法,多加努力。 能力有限,有错难免,望广大网友不吝赐教,多谢多谢。 如需转载,请标明出处。 http://www./lai3d/archive/2008/11/11/66662.html |
|