dl.so

Ruby/DL为UNIX的dlopen(3)或Windows的LoadLibrary()等dynamic linker提供接口。

Using Ruby/DL

通常使用dl/import.rb的 DL::Importable 模块。其中包含了用来访问库函数的高水准函数。在扩展某模块时, 要像下面这样使用 DL::Importable 。

require "dl/import"
module LIBC
  extend DL::Importable
end

此后,就可以使用该模块的dlload和extern方法了。可以像下面这样, 使用dlload来加载库, 然后分别对库函数使用extern来定义封装方法。

module LIBC
  extend DL::Importable
  dlload "libc.so.6","libm.so.6"
  extern "int strlen(char*)"
end
# Note that we should not include the module LIBC from some reason.

使用了LIBC.strlen之后, 就可以使用库函数strlen()了. 若给出的函数名的首字母是大写的话, 所定义的函数名的首字母就是小写.

可以像下例这样, 使用了dl/struct.rb中定义的struct或union函数之后, 就可以生成结构体或共用体的映像(memory image)了.

require "dl/import"
require "dl/struct"
module LIBC
  extend DL::Importable
  Timeval = struct [       # define timeval structure.
    "long tv_sec",
    "long tv_uses",
  ]
end
val = LIBC::Timeval.malloc # allocate memory.

请注意, 上例中分配内存时使用的是LIBC::Timeval.malloc, 而不是LIBC::Timeval.new。LIBC::Timeval.new的作用是将已生成的PtrData 对象封装起来。

可以像下例中这样, 使用模块函数callback来定义回叫(callback)。

module Foo
  extend DL::Importable
  def my_comp(str1,str2)
    str1 <=> str2
  end
  COMPARE = callback "int my_comp(char*,char*)"
end

这里的Foo::COMPARE是用来启动my_comp方法的Symbol 对象。

DL::Importable 模块非常易用。但有时也不得不直接使用像dlsym()这样的低级函数。这时应该使用DL 模块的函数。我们将在下节中谈到这个问题。

DL module

模块DL由3个包含若干模块函数和常数的类构成。Symbol类相当于可调用的符号。PtrData类用来表示像C的指针这样的内存块。由Handle类生成的对象负责操作已打开的库。

Constants

Functions

Handle class

Symbol class

PtrData class

Type specifiers

原型是由下列类型分类符构成的。原型的首元素表示返回值的类型, 其余元素表示各参数的类型。

C : 字符 (char)
c : 指向字符的指针 (char *)
H : short 整数  (short)
h : 指向short整数的指针 (short *)
I : 整数 (char, short, int)
i : 指向整数的指针 (char *, short *, int *)
L : long 整数 (long)
l : 指向long整数的指针 (long *)
F : 实数 (float)
f : 指向实数的指针 (float *)
D : 实数 (double)
d : 指向实数的指针(double *)
S : 不可变(immutable)字符串 (const char *)
s : 可变(mutable)字符串 (char *)
A : 数组(const type[])
a : 可变(mutable)数组 (type[])
P : 指针 (void *)
p : 可变(mutable)指针 (void *)
0 : void 函数(必须是原型的首字符)

cbtype由类型分类符0, C, I, H, L, F, D, S 以及 P 构成。例如:

DL.callback('IPP'){|ptr1,ptr2|
  str1 = ptr1.ptr.to_s
  str2 = ptr2.ptr.to_s
  str1 <=> str2
}