给OpenResty(LuaJIT)编写简单的C扩展示例以及通过编译luaSQL调用ODBC连接Access
前一篇文章写了一个通过ffi调用odbc连接mdb的一个库,当然,这个过程是很痛苦的……
于是我开始自我怀疑,luaJIT到底能不能使用lua的一些库?luaJIT按理说跟lua5.1版本是很接近的,那么接口的扩展方式也是一样的……
但是当我把luaSQL的拷进去,并且根据示例执行require(“”)时,却提示“找不到指定的模块”……
这使我一度怀疑,luaJIT不能使用Lua的一些库……当然,现在要拨乱反正,证明这个想法是错误的……
在此之前,我们先编写一个简单的Hello world的C扩展给LuaJIT调用试试,这也是我的探索之路,相信在这个过程中,大家也会渐渐的明白到底问题在哪儿……
给OpenResty(LuaJIT)编写简单的C扩展示例
我们的扩展只有一个文件,那就是文件
//gcc -shared -Llua -Iinclude\luajit-2.1 -o
#include ""
#include ""
#include ""
static const char* dohello(const char* src)
{
printf(src);
return "I'm OK!";
}
static int l_hello(lua_State* lua)
{
const char *src = NULL;
src = luaL_checkstring(lua, 1); //出栈获取源字符串
const char * des = dohello(src); //something
lua_pushstring(lua, des); //压栈返回给lua
return 1; //告诉lua返回了一个变量
}
//映射表,"doHello"为lua中的函数名,l_hello为真正C中的函数地址
static const struct luaL_Reg libhello[] = {
{"doHello", l_hello},
{NULL, NULL},
};
//模块注册函数
int luaopen_hello(lua_State* lua)
{
//注册本模块中所有的功能函数,hello为模块名,libhello数组存储所有函数的映射关系
luaL_register(lua, "hello", libhello);
return 1;
}
我是通过MinGW进行编译的,把文件放到OpenResty目录中去,调用gcc命令进行编译:
gcc -shared -Llua -Iinclude\luajit-2.1 -o
编译成功后得到,用luaJIT简单的测试一下:
> hello = require("hello")
> r = ("run~\n")
run~
> print(r)
I'm OK!
看来很成功~可惜我一开始做的时候不是这么顺利的……
在不断的调试过程中我发现了一点:
luaopen_后面跟着的字符串与luaL_register函数调用的第二个参数一定要一样!同时与dll的文件名也一定要一样!切记!切记!
这点很重要,是我经过多次的失败才发现的……这种要求大约也是我当年在java下编译HelloWorld一下午不成功的原因……当时都要哭了……
由于受这一点的启发,我似乎明白了我一直以来总是调用luasql_odbc不成功的原因……名称不一致……
下面介绍编译并调用luaSQL的正确姿势……
通过编译luaSQL调用ODBC连接Access
首先,去下载luaSQL的源码……
然后将下载下来的文件放到OpenResty的目录下的luasql目录中去,这么放的目的仅仅是为了引用include文件以及dll方便……
直接make odbc是不行的,我看了一下它的makefile,里面很多乱七八糟的变量需要修改,而且编译后的文件名默认是……
仔细看看它引出的函数就知道,这个文件名是不能被LuaJIT正确加载的,需要改成luasql_odbc……
我为了描述省事,直接写了两条gcc命令来编译,这两条命令只会编译luaSQL_ODBC:
gcc -I../include/luajit-2.1 -DLUASQL_VERSION_NUMBER='"2.3.4"' -c src/ -o
gcc -I../include/luajit-2.1 -DLUASQL_VERSION_NUMBER='"2.3.4"' ../ src/ls_odbc.c -o luasql_odbc.dll -shared -lodbc32
这两条命令将生成两个文件,和luasql_odbc.dll……
把luasql_odbc.dll放到OpenResty的目录中,写个lua脚本来调用一下试试吧……
还是用上次的那个做示例吧……测试脚本的内容为:
local ENV = require("luasql_odbc")
local env = ();
local conn,err = env:connect("excuteSQL");
if not conn then
print(err);
env:close();
return -3;
end
function excuteSQL(sql)
local n = conn:execute(sql);
if not n then
print("执行SQL失败");
return -4;
else
print("影响行数:"..tostring(n));
end
return 0;
end
function itorator(cur)
local row = {};
return function()
return cur:fetch(row,'a');
end
end
function excuteQuery(sql)
local cur = conn:execute(sql);
if not cur then
print("执行SQL失败");
return -5;
else
local row = nil;
for row in itorator(cur) do
local out = {};
for k,v in pairs(row) do
(out,k.."="..v)
end
print((out,","));
end
cur:close();
end
return 0;
end
excuteSQL("insert into [test]([name],[value]) values('testluasqlodbc',123)");
excuteQuery("select * from [test]");
conn:close();
env:close();
return 0;
更多的luaSQL_odbc的调用接口在源码的doc里面看吧,这里只是简单的测试一下我们刚刚编译的东西能不能用……输出结果:
影响行数:1
value=101,name=testOOO,id=1
value=23,name=tesooo0,id=2
value=100,name=testodbcConn1,id=3
value=2333,name=tesodbcConntp1,id=4
value=123,name=testluasqlodbc,id=5
应该是没什么大问题的……然而,luaSQL_odbc所实现的接口其实也不多,也是刚刚够用而已……
然而……让我踏入的大坑则是LuaSQL生成的动态链接库的文件名称不一致……
这致使我一直以为LuaSQL连接ODBC在OpenResty环境下是一个不能用的库……
于是也直接引发了我为LuaJIT写了一个ffi绑定库……
故事很曲折却是因为绕了一个大圈……分享出来,以免网友们重蹈覆辙……