代码改变世界

lua 加载C动态库

2012-11-23 10:37  respawn  阅读(14489)  评论(0编辑  收藏  举报

今天翻看luasocket的C源码,也翻看了很多BSD Socket的资料,算是重新复习了一下BSD Socket. 在ubuntu上面使用安装使用luasocket,

我安装的是lua5.1,不要使用apt安装luasocket && luasocket-dev. 如果采用这种方式安装,测试luasocket是不能使用的.我们应该安装库,

安装liblua5.1-socket.这样才可以.

 

原因是,luasocket在调用的时候是lua加载C的动态库. 这个可以从luasocket的makefile看的出来.

 1 all: $(SOCKET_SO) $(MIME_SO)
 2 
 3 $(SOCKET_SO): $(SOCKET_OBJS)
 4         $(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS)
 5 
 6 $(MIME_SO): $(MIME_OBJS)
 7         $(LD) $(LDFLAGS) -o $@ $(MIME_OBJS)
 8 
 9 $(UNIX_SO): $(UNIX_OBJS)
10         $(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS)

另外,也可以从config文件中找出:

 

1 #------
2 # Output file names
3 #
4 EXT=so
5 SOCKET_V=2.0.2
6 MIME_V=1.0.2
7 SOCKET_SO=socket.$(EXT).$(SOCKET_V)
8 MIME_SO=mime.$(EXT).$(MIME_V)
9 UNIX_SO=unix.$(EXT)

 

至于socket模块,按照config中的配置,编译后应该会生成一个socket.so.2.0.2的动态库.如果不想自己编译的话,也可以到网上去下载,编译

完整的库可以搜索liblua5.1-socket.so.2.0.2.(应该是这个.)

 

至于为什么会说到,lua加载C动态库这个问题,是因为我看到luasocket中socket.lua文件中的一句代码不明白:

1 local socket = require("socket.core") // socket.core?

 

如果不是加载一个模块的话,那么就是加载库,但是我在源码中没有找到这个库,再说,看到这个库的名字不感觉有点奇怪吗?

不过,可以看看源码中的这段代码:

 

1 /*-------------------------------------------------------------------------*\
2 * Initializes all library modules.
3 \*-------------------------------------------------------------------------*/
4 LUASOCKET_API int luaopen_socket_core(lua_State *L) {
5     int i;
6     base_open(L);
7     for (i = 0; mod[i].name; i++) mod[i].func(L);
8     return 1;
9 }

 base_open(lua_State *L)的函数源码如下:

 1 static int base_open(lua_State *L) {
 2     if (socket_open()) {
 3         /* export functions (and leave namespace table on top of stack) */
 4         luaL_openlib(L, "socket", func, 0);
 5 #ifdef LUASOCKET_DEBUG
 6         lua_pushstring(L, "_DEBUG");
 7         lua_pushboolean(L, 1);
 8         lua_rawset(L, -3);
 9 #endif
10         /* make version string available to scripts */
11         lua_pushstring(L, "_VERSION");
12         lua_pushstring(L, LUASOCKET_VERSION);
13         lua_rawset(L, -3);
14         return 1;
15     } else {
16         lua_pushstring(L, "unable to initialize library");
17         lua_error(L);
18         return 0;
19     }
20 }

 

 其中,需要注意的是luaL_openlib函数的功能(ps:注意,不是luaL_openlibs函数,在lua官网上面可能找不到该函数的API解释.)

 

另外,lua官网有文档说明,如何注册C库.详细的文档请去参考:http://www.lua.org/pil/26.2.html

1 When you extend Lua with C functions, it is a good idea to design your code as a C library, even when you want to register only one C function: 
Sooner or later (usually sooner) you will need other functions. As usual, the auxiliary library offers a helper function for this job. The luaL_openlib
function receives a list of C functions and their respective names and registers all of them inside a table with the library name.

 

现在已经弄明白在使用C扩展lua的时候,应该将我们的代码设计成为C库.

另外,我这里有一个简单的实例程序:

 1 #include <stdio.h>
 2 #include "./src/lua.h"
 3 #include "./src/lualib.h"
 4 #include "./src/lauxlib.h"
 5 
 6 static int add(lua_State *L)
 7 {
 8 int a,b,c;
 9 a = lua_tonumber(L,1);
10 b = lua_tonumber(L,2);
11 c = a+b;
12 lua_pushnumber(L,c);
13 printf("test hello!!!\r\n");
14 return 1;
15 }
16 static const struct luaL_Reg lib[] =
17 {
18 {"testadd",add},
19 {NULL,NULL}
20 };
21 int luaopen_testlib_core(lua_State *L)  // 注意这里的函数写法
22 {
23 //luaL_register(L,"testlib",lib);   // 1
24 luaL_openlib(L,"testlib",lib,0);    // 2
25 return 1;
26 }
27 
28 ~            

 

 下面给出一个lua脚本:

 

1 #!/usr/bin/env lua
2 require("testlib.core")  // 注意这里的调用,和上面的函数写法是相关联的
3 c = testlib.testadd(15,25)
4 print("The result is ",c);
5 ~                          

 

 

 到这里就很明白了,如果我在上面的C源码中使用的是luaopen_testlib(lua_State *L),那么在下面的lua脚本中直接require("testlib")就可以了.

 但是如果是像我上面的这种命名方式,那么就需要像我这么做.而luasocket中出现的require("socket.core"),就是这么出现的.