Fiddle 模块

Ruby 的 libffi 包装器。

说明

Fiddle 是一个扩展,用于用 Ruby 翻译外来函数接口 (FFI)。

它包装了 libffi,这是一个流行的 C 库,它提供了一个可移植的接口,允许用一种语言编写的代码调用用另一种语言编写的代码。

示例

这里我们将使用 Fiddle::Function 来包装 libm 中的 floor(3)

require 'fiddle'

libm = Fiddle.dlopen('/lib/libm.so.6')

floor = Fiddle::Function.new(
  libm['floor'],
  [Fiddle::TYPE_DOUBLE],
  Fiddle::TYPE_DOUBLE
)

puts floor.call(3.14159) #=> 3.0

常量

ALIGN_BOOL

ALIGN_BOOL

bool 的对齐大小

ALIGN_CHAR

ALIGN_CHAR

char 的对齐大小

ALIGN_DOUBLE

ALIGN_DOUBLE

double 的对齐大小

ALIGN_FLOAT

ALIGN_FLOAT

float 的对齐大小

ALIGN_INT

ALIGN_INT

int 的对齐大小

ALIGN_INT16_T

ALIGN_INT16_T

int16_t 的对齐大小

ALIGN_INT32_T

ALIGN_INT32_T

int32_t 的对齐大小

ALIGN_INT64_T

ALIGN_INT64_T

int64_t 的对齐大小

ALIGN_INT8_T

ALIGN_INT8_T

int8_t 的对齐大小

ALIGN_INTPTR_T

ALIGN_INTPTR_T

intptr_t 的对齐大小

ALIGN_LONG

ALIGN_LONG

long 的对齐大小

ALIGN_LONG_LONG

ALIGN_LONG_LONG

long long 的对齐大小

ALIGN_PTRDIFF_T

ALIGN_PTRDIFF_T

ptrdiff_t 的对齐大小

ALIGN_SHORT

ALIGN_SHORT

short 的对齐大小

ALIGN_SIZE_T

ALIGN_SIZE_T

size_t 的对齐大小

ALIGN_SSIZE_T

ALIGN_SSIZE_T

ssize_t 的对齐大小

ALIGN_UINTPTR_T

ALIGN_UINTPTR_T

uintptr_t 的对齐大小

ALIGN_VOIDP

ALIGN_VOIDP

void* 的对齐大小

BUILD_RUBY_PLATFORM

BUILD_RUBY_PLATFORM

针对其构建的平台(例如“x86_64-linux”等)

另请参阅 RUBY_PLATFORM

Qfalse

Qfalse

Qfalse 的值

Qnil

Qnil

Qnil 的值

Qtrue

Qtrue

Qtrue 的值

Qundef

Qundef

Qundef 的值

RUBY_FREE

RUBY_FREE

ruby_xfree() 函数的地址

SIZEOF_BOOL

SIZEOF_BOOL

bool 的大小

SIZEOF_CHAR

SIZEOF_CHAR

char 的大小

SIZEOF_CONST_STRING

SIZEOF_CONST_STRING

const char* 的大小

SIZEOF_DOUBLE

SIZEOF_DOUBLE

double 的大小

SIZEOF_FLOAT

SIZEOF_FLOAT

float 的大小

SIZEOF_INT

SIZEOF_INT

int 的大小

SIZEOF_INT16_T

SIZEOF_INT16_T

int16_t 的大小

SIZEOF_INT32_T

SIZEOF_INT32_T

int32_t 的大小

SIZEOF_INT64_T

SIZEOF_INT64_T

int64_t 的大小

SIZEOF_INT8_T

SIZEOF_INT8_T

int8_t 的大小

SIZEOF_INTPTR_T

SIZEOF_INTPTR_T

intptr_t 的大小

SIZEOF_LONG

SIZEOF_LONG

long 的大小

SIZEOF_LONG_LONG

SIZEOF_LONG_LONG

long long 的大小

SIZEOF_PTRDIFF_T

SIZEOF_PTRDIFF_T

ptrdiff_t 的大小

SIZEOF_SHORT

SIZEOF_SHORT

short 的大小

SIZEOF_SIZE_T

SIZEOF_SIZE_T

size_t 的大小

SIZEOF_SSIZE_T

SIZEOF_SSIZE_T

ssize_t 的大小

SIZEOF_UCHAR

SIZEOF_UCHAR

unsigned char 的大小

SIZEOF_UINT

SIZEOF_UINT

unsigned int 的大小

SIZEOF_UINT16_T

SIZEOF_UINT16_T

uint16_t 的大小

SIZEOF_UINT32_T

SIZEOF_UINT32_T

uint32_t 的大小

SIZEOF_UINT64_T

SIZEOF_UINT64_T

uint64_t 的大小

SIZEOF_UINT8_T

SIZEOF_UINT8_T

uint8_t 的大小

SIZEOF_UINTPTR_T

SIZEOF_UINTPTR_T

uintptr_t 的大小

SIZEOF_ULONG

SIZEOF_ULONG

unsigned long 的大小

SIZEOF_ULONG_LONG

SIZEOF_ULONG_LONG

unsigned long long 的大小

SIZEOF_USHORT

SIZEOF_USHORT

unsigned short 的大小

SIZEOF_VOIDP

SIZEOF_VOIDP

void* 的大小

VERSION
WINDOWS

返回一个布尔值,表示主机是否是 WIN32

公共类方法

dlopen(library) → Fiddle::Handle 点击切换源代码

创建一个新的处理程序,打开 library,并返回一个 Fiddle::Handle 实例。

如果为 library 指定 nil,则使用 Fiddle::Handle::DEFAULT,它等效于 RTLD_DEFAULT。有关更多信息,请参见 man 3 dlopen

lib = Fiddle.dlopen(nil)

默认值取决于操作系统,并为所有已加载的库提供一个句柄。例如,在大多数情况下,你可以使用它来访问 libc 函数或 rb_str_new 等 ruby 函数。

有关更多信息,请参见 Fiddle::Handle.new

# File ext/fiddle/lib/fiddle.rb, line 60
def dlopen library
  begin
    Fiddle::Handle.new(library)
  rescue DLError => error
    case RUBY_PLATFORM
    when /linux/
      case error.message
      when /\A(\/.+?): (?:invalid ELF header|file too short)/
        # This may be a linker script:
        # https://sourceware.org/binutils/docs/ld.html#Scripts
        path = $1
      else
        raise
      end
    else
      raise
    end

    File.open(path) do |input|
      input.each_line do |line|
        case line
        when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
          # TODO: Should we support multiple files?
          return dlopen($1)
        end
      end
    end

    # Not found
    raise
  end
end
dlunwrap(addr) 点击切换源代码

返回存储在内存地址 addr 中的 Ruby 对象

示例

x = Object.new
# => #<Object:0x0000000107c7d870>
Fiddle.dlwrap(x)
# => 4425504880
Fiddle.dlunwrap(_)
# => #<Object:0x0000000107c7d870>
VALUE
rb_fiddle_ptr2value(VALUE self, VALUE addr)
{
    return (VALUE)NUM2PTR(addr);
}
dlwrap(val) 单击以切换源

返回存储在 val 中的 Ruby 对象的内存地址

示例

x = Object.new
# => #<Object:0x0000000107c7d870>
Fiddle.dlwrap(x)
# => 4425504880

如果 val 不是堆分配对象,此方法将返回标记的指针值。

示例

Fiddle.dlwrap(123)
# => 247
static VALUE
rb_fiddle_value2ptr(VALUE self, VALUE val)
{
    return PTR2NUM((void*)val);
}
free(addr) 单击以切换源

释放地址 addr 处的内存

VALUE
rb_fiddle_free(VALUE self, VALUE addr)
{
    void *ptr = NUM2PTR(addr);

    ruby_xfree(ptr);
    return Qnil;
}
last_error() 单击以切换源

返回当前执行 Thread 的最后一个 Error,如果没有则返回 nil

# File ext/fiddle/lib/fiddle.rb, line 35
def self.last_error
  Thread.current[:__FIDDLE_LAST_ERROR__]
end
last_error=(error) 单击以切换源

将当前执行 Thread 的最后一个 Error 设置为 error

# File ext/fiddle/lib/fiddle.rb, line 40
def self.last_error= error
  Thread.current[:__DL2_LAST_ERROR__] = error
  Thread.current[:__FIDDLE_LAST_ERROR__] = error
end
malloc(size) 单击以切换源

分配 size 字节的内存并返回分配的内存的整数内存地址。

static VALUE
rb_fiddle_malloc(VALUE self, VALUE size)
{
    void *ptr;
    ptr = (void*)ruby_xcalloc(1, NUM2SIZET(size));
    return PTR2NUM(ptr);
}
realloc(addr, size) 单击以切换源

将内存位置 addr 处分配的内存大小更改为 size 字节。返回重新分配的内存的内存地址,该地址可能与传入的地址不同。

static VALUE
rb_fiddle_realloc(VALUE self, VALUE addr, VALUE size)
{
    void *ptr = NUM2PTR(addr);

    ptr = (void*)ruby_xrealloc(ptr, NUM2SIZET(size));
    return PTR2NUM(ptr);
}
win32_last_error() 单击以切换源

返回当前执行 Thread 的最后一个 win32 Error,如果没有则返回 nil

# File ext/fiddle/lib/fiddle.rb, line 12
def self.win32_last_error
  Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
end
win32_last_error=(error) 单击以切换源

将当前执行 Thread 的最后一个 win32 Error 设置为 error

# File ext/fiddle/lib/fiddle.rb, line 17
def self.win32_last_error= error
  Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
end
win32_last_socket_error() 单击以切换源

返回当前执行 Thread 的最后一个 win32 socket Error,如果没有则返回 nil

# File ext/fiddle/lib/fiddle.rb, line 23
def self.win32_last_socket_error
  Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
end
win32_last_socket_error=(error) 单击以切换源

将当前执行 Thread 的最后一个 win32 socket Error 设置为 error

# File ext/fiddle/lib/fiddle.rb, line 29
def self.win32_last_socket_error= error
  Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
end

私有实例方法

dlopen(library) → Fiddle::Handle 点击切换源代码

创建一个新的处理程序,打开 library,并返回一个 Fiddle::Handle 实例。

如果为 library 指定 nil,则使用 Fiddle::Handle::DEFAULT,它等效于 RTLD_DEFAULT。有关更多信息,请参见 man 3 dlopen

lib = Fiddle.dlopen(nil)

默认值取决于操作系统,并为所有已加载的库提供一个句柄。例如,在大多数情况下,你可以使用它来访问 libc 函数或 rb_str_new 等 ruby 函数。

有关更多信息,请参见 Fiddle::Handle.new

# File ext/fiddle/lib/fiddle.rb, line 60
def dlopen library
  begin
    Fiddle::Handle.new(library)
  rescue DLError => error
    case RUBY_PLATFORM
    when /linux/
      case error.message
      when /\A(\/.+?): (?:invalid ELF header|file too short)/
        # This may be a linker script:
        # https://sourceware.org/binutils/docs/ld.html#Scripts
        path = $1
      else
        raise
      end
    else
      raise
    end

    File.open(path) do |input|
      input.each_line do |line|
        case line
        when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
          # TODO: Should we support multiple files?
          return dlopen($1)
        end
      end
    end

    # Not found
    raise
  end
end