Hacking Limbo

Reading / Coding / Hacking

Load Library Reliably for LuaJIT FFI

在做一个 OpenResty 实验时发现必须写 ffi.load('GraphicsMagickWand.so.2') 才能成功加载 GraphicsMagick, 但是并不想在代码里写死这个后缀(虽然只有我一个人在用这个 fork 出来的库),考虑了几种方案:

  1. io.open()ffi.C.access() 判断 /usr/lib/libGraphicsMagickWand.so/usr/lib/libGraphicsMagickWand.so.2 是否存在,过于依赖命名规则和具体的路径,不太科学。

  2. 列出常见的文件名(GraphicsMagickWandGraphicsMagickWand.so.2),逐个尝试调用 ffi.load() 直到加载成功或穷尽所有可能。

  3. 提供全局变量 g_ffi_libgmwand 用于覆盖默认的 so 文件名 GraphicsMagickWand.

后两个选项涉及到 ffi.load() 的错误处理——怪自己对 Lua 语言不够了解,Google 了半天才搞明白怎样在 FFI 调用时避免 Lua VM 崩溃。具体来说就是用 pcall()xpcall()(Lua VM 内置的错误处理函数)。选择方案 3 的话,只需用 pcall() 捕捉 ffi.load() 抛出的「异常」即可,具体实现如下:

local ok, clib = pcall(ffi.load, g_ffi_libgmwand or 'GraphicsMagickWand')

if ok then
    clib.InitializeMagick();
else
    error('Failed on loading GraphicsMagickWand shared library: ' .. rv)
end

鉴于 Lua 不提倡使用全局变量,可以用环境变量代替,顺便偷懒省掉错误处理,变成:

local clib_name = os.getenv('LUA_FFI_GM_WAND_LIB') or 'GraphicsMagickWand'
local clib = ffi.load(clib_name)
clib.InitializeMagick()