lua写了很久了,但有些部分一直没有接触过,最近把lua程序设计又看了一遍查缺补漏。在lua调用c模块这边着实折腾了一番,不多说,开始正题。记录下整个操作过程。
【先贴图最后的结果】:
1.到官网下载lua5.3的源码。(PS:我用的5.3,每个版本稍微有点区别,都行,后面在c模块源码中会提到)
2.由于是lua调用自己写的C模块,所以我一开始用VS(我的版本是vs2017社区版)把lua源码生成了lua解释器lua编译器,lua静态库和lua动态库。lua编译器这篇文章都没用到,是我顺便生成的,具体生成方法:
2.1> 我首先在桌面创建了4个文件夹分别对应lua解释器、lua编译器、lua动态库和lua静态库
2.2> 以生成lua解释器为例,首先说明这个lua解释器是用不了的,后面会讲到正确的(PS:这是我第一次尝试过程,其实这样使用静态依赖生成解释器是无法正确调用C模块的。会产生multiple Lua VMs detected 错误)
接下来将解决方案资源管理器 中,右键点击项目名 lua, 点击属性,上方的配置设置为Release, 平台设置为x64(根据windows系统, 32位系统的选择Win32) 设置 配置类型 为 应用程序(.exe)
把刚开始下载的lua源码复制到这个目录中,
点击箭头所示按钮,显示当前所有文件,并点击lua项目找到src,右键src包括在项目中
点击展开 src 文件夹,鼠标右键点击文件 luac.c, 在菜单中点击 从项目中排除,将文件 luac.c 从项目中排除,并且注意下图所示对应你的windows系统位数
点击生成就生成了lua解释器lua.exe,
检验是否能使用,双击点开输入一些lua的打印代码如 print("This is lua")
接下来类似生成 编译器、静态库、动态库
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源码复制到项目中,分别修改下面3项,以便使用lua库:
3.1.附加包含目录,是引用刚刚复制到项目的lua源码文件
3.2.连接器附加库目录,即引用的lua库
3.3.附加依赖项,添加桌面生成的静态lua库名lualib.lib
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文件夹可以看到
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:
报错multiple Lua VMs detected,就是说有多个虚拟机加载,起冲突了。我们之前lua解释器用静态来编译,就会加载一个虚拟机,当解释器去调用c模块时,这时也会加载一个lua虚拟机,所以自然就起了冲突。只要lua解释器和c库都调用同一个dll就好,dll是共享库,只会加载一次到内存,所以就不会出现冲突。所以说我们编写的C模块和lua解释器都用同个lua共享库就好。不能用静态库。
这里需要做以下更改:
4.1.生成luadll方式的更改,之前生成luadll的项目配置,加入 LUA_BUILD_AS_DLL,不然不会生成引导lib,解释器也用不了
点击生成后发现多了一个lib,
4.2.修改生成lua解释器的配置,让他使用上面成的动态库的lib,
点击生成,然后去release中点击新生成的lua文件,发现报错了,找不到dll文件,那当然,因为引用的dll不在项目下,把luadll复制到同一个目录就可以了
4.3.除此之外,c模块也要引用同样的共享库,同样修改配置。
点击生成,将新生成的test.dll、lua解释器、luaCModuleTest文件放在同一个目录中,并且将luadll.dll复制到同一个目录
成功。