创建一个win32项目,起名mylib(因为我已经创建过mylib了,所以这里用的mylib2)。
下面开始编写C模块:
mylib.h如下:
/*mylib.h*/
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <dirent.h>
#include <errno.h>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
using namespace std;
#ifdef MYLIB_EXPORTS
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif
extern "C" __declspec(dllexport) MYLIB_API int luaopen_mylib(lua_State* L);
mylib.cpp如下(这里包含了两个函数功能,一个是l_sin函数,一个是遍历目录的l_dir函数):
// mylib.cpp : 定义 DLL 应用程序的导出函数。
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include "mylib.h"
#include <iostream>
#include <string>
#include <dirent.h>
#include <errno.h>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
extern "C" int l_sin(lua_State *L) {
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1;
}
extern "C" int l_dir(lua_State *L) {
DIR *dir;
struct dirent *entry;
int i;
const char *path = luaL_checkstring(L, 1);
dir = opendir(path);
if (dir == NULL) {
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
return 2;
}
lua_newtable(L);
i = 1;
while ((entry = readdir(dir)) != NULL) {
lua_pushnumber(L, i++);
lua_pushstring(L, entry->d_name);
lua_settable(L, -3);
}
closedir(dir);
return 1;
}
static const struct luaL_reg mylib[] = {
{ "mydir", l_dir },
{ "mysin", l_sin },
{ NULL, NULL }
};
extern "C" __declspec(dllexport)
MYLIB_API int luaopen_mylib(lua_State* L) {
luaL_register(L, "mylib", mylib);
return 1;
}
这里尤其注意
extern "C" __declspec(dllexport)
MYLIB_API int luaopen_mylib(lua_State* L)
extern “C” 和 dllexport,dll需要导出符号。
同时extern “C”避免名字粉碎。
extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。
比如说你用C 开发了一个DLL 库,为了能够让C ++语言也能够调用你的DLL输出(Export)的函数,你需要用extern “C”来强制编译器不要修改你的函数名。
编写好程序后,直接点击编辑生成mylib.dll和mylib.lib文件,会出现如下提示,忽略它就好。
然后将生成的mylib.dll和mylib.lib文件放到与lua程序的同目录下,这里创建一个lua文件叫做lib.lua:
mylib = require ("mylib");
print (mylib.mysin (3.14 / 2));
t = mylib.mydir ("D:\\Lua-5.1\\lua-5.1.5\\lua-5.1.5");
for k, v in pairs (t) do
print (k, v);
end
如此lib.lua会通过require将动态库mylib链接到lua,并寻找luaopen_mylib函数,将其注册为一个lua函数,然后调用它以打开模块。运行结果如下:
如此就完成了整个lua采用动态链接库调用C模块的过程。