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

image.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别...
    吃瓜群众呀阅读 14,158评论 3 42
  • 动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。大多数操作系统将解析外部引用(比如库)作为加载过...
    小5筒阅读 10,910评论 0 3
  • 第一篇 语言 第0章 序言 Lua仅让你用少量的代码解决关键问题。 Lua所提供的机制是C不擅长的:高级语言,动态...
    testfor阅读 7,732评论 1 7
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 12,385评论 0 27
  • 动态调用动态库方法c/c++linuxwindows 关于动态调用动态库方法说明 一、 动态库概述 1、 动态库的...
    KINGZ1993阅读 14,743评论 0 10