lua调用C模块过程记录

时间:2024-04-03 16:08:20

        lua写了很久了,但有些部分一直没有接触过,最近把lua程序设计又看了一遍查缺补漏。在lua调用c模块这边着实折腾了一番,不多说,开始正题。记录下整个操作过程。

【先贴图最后的结果】:

lua调用C模块过程记录

1.到官网下载lua5.3的源码。(PS:我用的5.3,每个版本稍微有点区别,都行,后面在c模块源码中会提到)lua调用C模块过程记录

2.由于是lua调用自己写的C模块,所以我一开始用VS(我的版本是vs2017社区版)把lua源码生成了lua解释器lua编译器,lua静态库和lua动态库。lua编译器这篇文章都没用到,是我顺便生成的,具体生成方法:

     2.1> 我首先在桌面创建了4个文件夹分别对应lua解释器、lua编译器、lua动态库和lua静态库

lua调用C模块过程记录

    2.2> 以生成lua解释器为例,首先说明这个lua解释器是用不了的,后面会讲到正确的(PS:这是我第一次尝试过程,其实这样使用静态依赖生成解释器是无法正确调用C模块的。会产生multiple Lua VMs detected 错误)

lua调用C模块过程记录

    接下来将解决方案资源管理器 中,右键点击项目名 lua, 点击属性,上方的配置设置为Release, 平台设置为x64(根据windows系统, 32位系统的选择Win32)  设置   配置类型 为 应用程序(.exe)

    把刚开始下载的lua源码复制到这个目录中,

lua调用C模块过程记录

点击箭头所示按钮,显示当前所有文件,并点击lua项目找到src,右键src包括在项目中lua调用C模块过程记录

点击展开 src 文件夹,鼠标右键点击文件 luac.c, 在菜单中点击 从项目中排除,将文件 luac.c 从项目中排除,并且注意下图所示对应你的windows系统位数lua调用C模块过程记录

点击生成就生成了lua解释器lua.exe,lua调用C模块过程记录

检验是否能使用,双击点开输入一些lua的打印代码如 print("This is lua")lua调用C模块过程记录

接下来类似生成 编译器、静态库、动态库

2.2>生成Lua编译器(luac.exe)

步骤与1相同, 但同样需要新建项目,命名为luac, 选中桌面上的luac文件夹作项目文件夹,

需要在src文件夹中排除的文件是lua.c

在项目属性中设置   配置类型 为 应用程序(.exe) 

2.3> 生成lua动态链接库(dll)

步骤与1相同,需要新建项目,命名为luadll, 选中桌面上的luadll文件夹作项目文件夹,

需要在src文件夹中排除的文件是 lua.c 、 luac.c 、 lua.hpp

在项目属性中设置  配置类型 为 动态库(.dll) 

2.4> 生成lua静态链接库(lib)

步骤与1相同,需要新建项目,命名为lualib, 选中桌面上的lualib文件夹作项目文件夹,

需要在src文件夹中排除的文件是 lua.c 、 luac.c 、 lua.hpp

在项目属性中设置   配置类型 为 静态库(.lib) 

 

3.编写C模块

 先创建空项目test,将属性页的 Release和平台都和上面一样设置好,还有上面菜单栏下面那个Release和x64设置好,要和上面生成库一致。项目如下设置为dll

lua调用C模块过程记录

  将一开始下载的官网lua源码复制到项目中,分别修改下面3项,以便使用lua库:

    3.1.附加包含目录,是引用刚刚复制到项目的lua源码文件

lua调用C模块过程记录

      3.2.连接器附加库目录,即引用的lua库

lua调用C模块过程记录

    3.3.附加依赖项,添加桌面生成的静态lua库名lualib.lib

lua调用C模块过程记录

test.c 文件代码:

#include <math.h>
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"


static int my_math_sin(lua_State *L) {
    lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
    return 1;
}

static int my_math_cos(lua_State *L) {
    lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
    return 1;
}


static const luaL_Reg mathlib[] = {
{"my_cos",   my_math_cos},
{"my_sin",   my_math_sin},
{NULL, NULL}
};


__declspec(dllexport) int luaopen_test(lua_State *L) {
    //luaL_openlib(L, "mylib", mylib, 0); //lua5.1可以,lua5.2不能用了
    luaL_newlib(L, mathlib);  //5.3使用,看定义相当于lua_newtable(L);luaL_setfuncs(L, myLibs,0);
    return 1;
}

   点击生成test.dll,最后在release文件夹可以看到

lua调用C模块过程记录

 

4.准备调用C模块。首先创建一个lua文件取名luaCModuleTest.lua,写入

my_math = require("test")

print(my_math.my_sin(3.14))
print(my_math.my_cos(3.14))

将之前生成的test.dll、桌面生成的lua解释器、luaCModuleTest文件放在同一个目录中

lua调用C模块过程记录

运行lua:

lua调用C模块过程记录

报错multiple Lua VMs detected,就是说有多个虚拟机加载,起冲突了。我们之前lua解释器用静态来编译,就会加载一个虚拟机,当解释器去调用c模块时,这时也会加载一个lua虚拟机,所以自然就起了冲突。只要lua解释器和c库都调用同一个dll就好,dll是共享库,只会加载一次到内存,所以就不会出现冲突。所以说我们编写的C模块和lua解释器都用同个lua共享库就好。不能用静态库。

这里需要做以下更改:

4.1.生成luadll方式的更改,之前生成luadll的项目配置,加入 LUA_BUILD_AS_DLL,不然不会生成引导lib,解释器也用不了lua调用C模块过程记录

点击生成后发现多了一个lib,

lua调用C模块过程记录

4.2.修改生成lua解释器的配置,让他使用上面成的动态库的lib,

lua调用C模块过程记录

lua调用C模块过程记录

点击生成,然后去release中点击新生成的lua文件,发现报错了,找不到dll文件,那当然,因为引用的dll不在项目下,把luadll复制到同一个目录就可以了

lua调用C模块过程记录

4.3.除此之外,c模块也要引用同样的共享库,同样修改配置。

lua调用C模块过程记录

 

lua调用C模块过程记录

点击生成,将新生成的test.dll、lua解释器、luaCModuleTest文件放在同一个目录中,并且将luadll.dll复制到同一个目录

lua调用C模块过程记录

成功。