您的位置:首页 > 编程语言 > Lua

通过编译luaSQL调用ODBC连接Access以及给OpenResty(LuaJIT)编写简单的C扩展示例

2016-11-26 00:06 966 查看
给OpenResty(LuaJIT)编写简单的C扩展示例以及通过编译luaSQL调用ODBC连接Access

前一篇文章写了一个通过ffi调用odbc连接mdb的一个库,当然,这个过程是很痛苦的……

于是我开始自我怀疑,luaJIT到底能不能使用lua的一些库?luaJIT按理说跟lua5.1版本是很接近的,那么接口的扩展方式也是一样的……

但是当我把luaSQL的odbc.dll拷进去,并且根据示例执行require(“luasql.odbc”)时,却提示“找不到指定的模块”……

这使我一度怀疑,luaJIT不能使用Lua的一些库……当然,现在要拨乱反正,证明这个想法是错误的……

在此之前,我们先编写一个简单的Hello world的C扩展给LuaJIT调用试试,这也是我的探索之路,相信在这个过程中,大家也会渐渐的明白到底问题在哪儿……

给OpenResty(LuaJIT)编写简单的C扩展示例

我们的扩展只有一个文件,那就是hello.c文件

//gcc lua51.dll hello.c -shared -Llua -Iinclude\luajit-2.1 -o hello.dll
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
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进行编译的,把hello.c文件放到OpenResty目录中去,调用gcc命令进行编译:

gcc lua51.dll hello.c -shared -Llua -Iinclude\luajit-2.1 -o hello.dll
编译成功后得到hello.dll,用luaJIT简单的测试一下:

> hello = require("hello")
> r = hello.doHello("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,里面很多乱七八糟的变量需要修改,而且编译后的文件名默认是odbc.so……

仔细看看它引出的函数就知道,这个文件名是不能被LuaJIT正确加载的,需要改成luasql_odbc……

我为了描述省事,直接写了两条gcc命令来编译,这两条命令只会编译luaSQL_ODBC:

gcc -I../include/luajit-2.1 -DLUASQL_VERSION_NUMBER='"2.3.4"' -c src/luasql.c -o luasql.o
gcc  -I../include/luajit-2.1 -DLUASQL_VERSION_NUMBER='"2.3.4"' ../lua51.dll src/ls_odbc.c -o luasql_odbc.dll -shared luasql.o -lodbc32


这两条命令将生成两个文件,luasql.o和luasql_odbc.dll……

把luasql_odbc.dll放到OpenResty的目录中,写个lua脚本来调用一下试试吧……

还是用上次的那个test.mdb做示例吧……测试脚本testLuaSqlOdbc.lua的内容为:

local ENV = require("luasql_odbc")
local env = ENV.odbc();
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
table.insert(out,k.."="..v)
end
print(table.concat(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绑定库……

故事很曲折却是因为绕了一个大圈……分享出来,以免网友们重蹈覆辙……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐