模块 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
-
bool 的对齐大小
- ALIGN_CHAR
-
char 的对齐大小
- ALIGN_DOUBLE
-
double 的对齐大小
- ALIGN_FLOAT
-
float 的对齐大小
- ALIGN_INT
-
int 的对齐大小
- ALIGN_INT16_T
-
int16_t 的对齐大小
- ALIGN_INT32_T
-
int32_t 的对齐大小
- ALIGN_INT64_T
-
int64_t 的对齐大小
- ALIGN_INT8_T
-
int8_t 的对齐大小
- ALIGN_INTPTR_T
-
intptr_t 的对齐大小
- ALIGN_LONG
-
long 的对齐大小
- ALIGN_LONG_LONG
-
long long 的对齐大小
- ALIGN_PTRDIFF_T
-
ptrdiff_t 的对齐大小
- ALIGN_SHORT
-
short 的对齐大小
- ALIGN_SIZE_T
-
size_t 的对齐大小
- ALIGN_SSIZE_T
-
ssize_t 的对齐大小
- ALIGN_UINTPTR_T
-
uintptr_t 的对齐大小
- ALIGN_VOIDP
-
void* 的对齐大小
- BUILD_RUBY_PLATFORM
-
构建所针对的平台(例如,“x86_64-linux”等)
另请参阅 RUBY_PLATFORM
- NULL
- Qfalse
-
Qfalse
的值 - Qnil
-
Qnil
的值 - Qtrue
-
Qtrue
的值 - Qundef
-
Qundef
的值 - RUBY_FREE
-
ruby_xfree() 函数的地址
- SIZEOF_BOOL
-
bool 的大小
- SIZEOF_CHAR
-
char 的大小
- SIZEOF_CONST_STRING
-
const char* 的大小
- SIZEOF_DOUBLE
-
double 的大小
- SIZEOF_FLOAT
-
float 的大小
- SIZEOF_INT
-
int 的大小
- SIZEOF_INT16_T
-
int16_t 的大小
- SIZEOF_INT32_T
-
int32_t 的大小
- SIZEOF_INT64_T
-
int64_t 的大小
- SIZEOF_INT8_T
-
int8_t 的大小
- SIZEOF_INTPTR_T
-
intptr_t 的大小
- SIZEOF_LONG
-
long 的大小
- SIZEOF_LONG_LONG
-
long long 的大小
- SIZEOF_PTRDIFF_T
-
ptrdiff_t 的大小
- SIZEOF_SHORT
-
short 的大小
- SIZEOF_SIZE_T
-
size_t 的大小
- SIZEOF_SSIZE_T
-
ssize_t 的大小
- SIZEOF_UCHAR
-
unsigned char 的大小
- SIZEOF_UINT
-
unsigned int 的大小
- SIZEOF_UINT16_T
-
uint16_t 的大小
- SIZEOF_UINT32_T
-
uint32_t 的大小
- SIZEOF_UINT64_T
-
uint64_t 的大小
- SIZEOF_UINT8_T
-
uint8_t 的大小
- SIZEOF_UINTPTR_T
-
uintptr_t 的大小
- SIZEOF_ULONG
-
unsigned long 的大小
- SIZEOF_ULONG_LONG
-
unsigned long long 的大小
- SIZEOF_USHORT
-
unsigned short 的大小
- SIZEOF_VOIDP
-
void* 的大小
- VERSION
- WINDOWS
返回关于主机是否为 WIN32 的布尔值
公共类方法
创建一个新的处理程序,打开 library
,并返回 Fiddle::Handle
的实例。
如果为 library
提供 nil
,则使用 Fiddle::Handle::DEFAULT,它等效于 RTLD_DEFAULT。有关详细信息,请参阅 man 3 dlopen
。
lib = Fiddle.dlopen(nil)
默认值取决于操作系统,并为所有已加载的库提供一个句柄。例如,在大多数情况下,您可以使用它来访问 libc
函数或 ruby 函数(如 rb_str_new
)。
有关详细信息,请参阅 Fiddle::Handle.new
。
# File fiddle/lib/fiddle.rb, line 91 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? first_input = $1 if first_input.start_with?("-l") first_input = "lib#{first_input[2..-1]}.so" end return dlopen(first_input) end end end # Not found raise end end
返回存储在内存地址 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); }
返回存储在 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); }
释放地址 addr
处的内存
VALUE rb_fiddle_free(VALUE self, VALUE addr) { void *ptr = NUM2PTR(addr); ruby_xfree(ptr); return Qnil; }
返回当前执行的 Thread
的最后一个 Error
,如果没有则返回 nil
# File fiddle/lib/fiddle.rb, line 57 def self.last_error if RUBY_ENGINE == 'jruby' errno = FFI.errno errno == 0 ? nil : errno else Thread.current[:__FIDDLE_LAST_ERROR__] end end
将当前执行的 Thread
的最后一个 Error
设置为 error
# File fiddle/lib/fiddle.rb, line 67 def self.last_error= error if RUBY_ENGINE == 'jruby' FFI.errno = error || 0 else Thread.current[:__DL2_LAST_ERROR__] = error Thread.current[:__FIDDLE_LAST_ERROR__] = error end end
分配 size
字节的内存,并返回已分配内存的整数内存地址。
static VALUE rb_fiddle_malloc(VALUE self, VALUE size) { void *ptr; ptr = (void*)ruby_xcalloc(1, NUM2SIZET(size)); return PTR2NUM(ptr); }
将内存位置 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); }
返回当前执行的 Thread
的最后一个 win32 Error
,如果没有则返回 nil
# File fiddle/lib/fiddle.rb, line 16 def self.win32_last_error if RUBY_ENGINE == 'jruby' errno = FFI.errno errno == 0 ? nil : errno else Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] end end
将当前执行的 Thread
的最后一个 win32 Error
设置为 error
# File fiddle/lib/fiddle.rb, line 26 def self.win32_last_error= error if RUBY_ENGINE == 'jruby' FFI.errno = error || 0 else Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error end end
返回当前执行的 Thread
的最后一个 win32 套接字 Error
,如果没有则返回 nil
# File fiddle/lib/fiddle.rb, line 36 def self.win32_last_socket_error if RUBY_ENGINE == 'jruby' errno = FFI.errno errno == 0 ? nil : errno else Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] end end
将当前执行的 Thread
的最后一个 win32 套接字 Error
设置为 error
# File fiddle/lib/fiddle.rb, line 47 def self.win32_last_socket_error= error if RUBY_ENGINE == 'jruby' FFI.errno = error || 0 else Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error end end
私有实例方法
创建一个新的处理程序,打开 library
,并返回 Fiddle::Handle
的实例。
如果为 library
提供 nil
,则使用 Fiddle::Handle::DEFAULT,它等效于 RTLD_DEFAULT。有关详细信息,请参阅 man 3 dlopen
。
lib = Fiddle.dlopen(nil)
默认值取决于操作系统,并为所有已加载的库提供一个句柄。例如,在大多数情况下,您可以使用它来访问 libc
函数或 ruby 函数(如 rb_str_new
)。
有关详细信息,请参阅 Fiddle::Handle.new
。
# File fiddle/lib/fiddle.rb, line 91 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? first_input = $1 if first_input.start_with?("-l") first_input = "lib#{first_input[2..-1]}.so" end return dlopen(first_input) end end end # Not found raise end end