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 

/*
 文件名: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

Lua编译扩展(DLL)_第1张图片
image.png

你可能感兴趣的:(Lua编译扩展(DLL))