#通过编译LuaSQL调用ODBC连接Access以及给OpenResty(LuaJIT)编写简单的C扩展示例 **目录** [TOC] [前一篇文章](LuaJIT_FFI_ODBC_Connect_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`文件 ```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`命令进行编译: ```Shell 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`的源码](https://github.com/keplerproject/luasql "下载`luaSQL`的源码")…… 然后将下载下来的文件放到`OpenResty`的目录下的`luasql目录`中去,这么放的目的仅仅是为了引用`include文件`以及`dll`方便…… 直接`make odbc`是不行的,我看了一下它的`makefile`,里面很多乱七八糟的变量需要修改,而且编译后的文件名默认是`odbc.so`…… 仔细看看它引出的函数就知道,这个文件名是不能被`LuaJIT`正确加载的,需要改成`luasql_odbc`…… 我为了描述省事,直接写了两条`gcc命令`来编译,这两条命令只会编译`luaSQL_ODBC`: ```Shell 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`的内容为: ```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绑定库`…… 故事很曲折却是因为绕了一个大圈……分享出来,以免网友们重蹈覆辙……


发表评论

必填,公开,这样称呼起来方便~

必填,不会被公开,不必担心~

http://

非必填,公开,目的是方便增进友好访问~

必填,请输入下方图片中的字母或数字,以证明你是人类

看不清楚
必填,最好不要超过500个字符
     ↑返回顶端↑