美文网首页
Lua编译扩展(DLL)

Lua编译扩展(DLL)

作者: 绿箭ML | 来源:发表于2017-09-17 17:27 被阅读263次

    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

    image.png

    相关文章

      网友评论

          本文标题:Lua编译扩展(DLL)

          本文链接:https://www.haomeiwen.com/subject/jekmsxtx.html