Lua编译扩展(DLL)
Lua扩展模块编译
真的是把我逼疯的节奏
在这期间有很多疑惑,如下:
- Lua是如何自动去“加载”(或者说搜索)c库中的函数
- Lua的扩展库的编译环境
- Lua在C中是怎么被调用的
带着这些问题,的确困扰了我很久,直到我看完了手册
关于gcc的一些参数
-I 从某个目录搜索头文件
-L 从某个目录链接动态库,好比如 -L.代表在本目录
-l 要链接的动态库,比如说libab.dll 则是-lab,这个mingw的确给我来了个措手不稽(说好的ab.dll用-lab呢,吐槽还是太年轻)
-c 编译,但是不链接,声称.o文件
Lua提供的库
这些文件都可以在lua的安装环境中找到
注意%LUA_DEV%指的是lua的安装目录,如果是自己编译源码的,不包括扩展库,只有基本库,
%LUA_DEV%\include lua函数声明的头文件,其中包括了
- lua.h c调用lua的函数声明基本都在这,还有结构体
- lualib.h 动态库编译(DLL,SO)相关的函数定义都在这,还有结构体
- luaxlib.h 这个还真不知道,好像是扩展库的
- lua.hpp 这个是c++的,实际上和lua.h差不多的
- luaconf.h 这个是配置的,好比如说配置参数检查,就在包含这个头文件前设定一个宏
%LUA_DEV%\lib 这里是lua库的放的地方,有两种库,一种是静态库(xx.lib相当于Linux下的xxx.a,通过ar生成)另一种是动态库dll
-
lua51.dll
-
lua51.lib
-
lua5.1.dll
-
lua5.1.lib
其实只是名字不太一样,两个动态库和静态库一样的
好的,开始修仙,只讨论怎么编译一个最简单的,能够被调用的,不讨论C编写的细节
这段例子网上抄的
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include <windows.h>
/*
文件名:mylib.c
编译的库名:mylib.dll
这个名字很重要,对不上就没办法调用了
*/
//这里定义了一个lua可以调用的函数,lua_State是一个状态机
static int mylib_pp(lua_State *L){
MessageBox(NULL,"Hello","Hei",MB_OK);
//返回值指的是返回值个数的数量
return 0;
}
//---注册函数
//本身luaL_reg结构体就是一个名称和函数名对应的,这里是一个结构体数组,最后我们用{NULL,NULL}结束
static const luaL_reg Mylib[]={
{"pp",mylib_pp},
{NULL,NULL},
};
//暴露的函数,都要写上extern,还有一个很重要的地方就是:
//luaopen_库名 好比如库叫mylib,文件名就得叫mylib.dll,而且登记的库名也得交mylib,保持一致才能调用
extern int luaopen_mylib(lua_State *L)
{
luaL_register(L,"mylib",Mylib);
return 1;
}
好的以上就是代码的相关内容,然后我们来到编译,需要以下东西
- mingw
- lua的静态库lib
- lua的头文件include
首先先把lua的扩展编译成.o文件,请注意,有个特殊的环境变量,%LUA_DEV%指的是lua的安装目录
gcc -I %LUA_DEV%\include -c mylib.c
然后链接
gcc -shared -fPIE -o mylib.dll mylib.o %LUA_DEV%\lib\lua51.lib
最后生成的mylib.dll
打开lua
package.path = package.path .. ".\?.dll"
-- 把当前目录添加到搜索目录
require('mylib')
-- 这个对应的是luaL_reg中注册的名称
mylib.pp()
伪总结
编译的时候注意事项:
1.头文件只是提供了结构体定义和函数声明,但是具体的实现还是在静态库的,编译期间要包含头文件
2.编译dll的时候,把静态库一并加进来,就可以了
3.在注册的函数中,命名有规则,a.dll对应extern int luaopen_a(lua_State *L),同时对应的库名称是a,也就是luaL_register(L,"a",表),如果规则不符合他就会提示找不到特定程序
他是调用某个特定的函数,这个函数包含了注册这个模块的信息,但是这个函数得符合上面的3的规则,如果不是标准的,就不能直接require导入,至于对一个的名称和函数的地址关系,是通过一个表来实现的
VS2017版本
使用VS2017编译lua扩展
代码跟上面一样,有设置不一样的地方
1.lua解释器不能使用静态编译,如果使用静态编译,只能使用一个虚拟机,再加载一个虚拟机就会报错(百度结果,原因未理解)
2.编译dll时,luaopen_xxx函数要添加_declspec(dllexport)
3.使用extern "C"包裹luaopen_xxx