Ruby 2.4

Fiddle::Importer

module Fiddle::Importer

Included modules:Fiddle, Fiddle::CParser

一个DSL提供了动态加载库和构建模块的方法,包括调用已加载的C库中的extern函数。

require 'fiddle' require 'fiddle/import' module LibSum extend Fiddle::Importer dlload './libsum.so' extern 'double sum(double*, int)' extern 'double split(double)' end

属性

type_aliasR

公共实例方法

Show source

返回映射到名称的函数,该函数由#extern或#bind创建

# File ext/fiddle/lib/fiddle/import.rb, line 232 def [](name) @func_map[name] end

bind(signature, *opts, &blk) Show source

使用给定的opts作为给定块的绑定参数,从给定的C signature

# File ext/fiddle/lib/fiddle/import.rb, line 188 def bind(signature, *opts, &blk) name, ctype, argtype = parse_signature(signature, type_alias) h = parse_bind_options(opts) case h[:callback_type] when :bind, nil f = bind_function(name, ctype, argtype, h[:call_type], &blk) else raise(RuntimeError, "unknown callback type: #{h[:callback_type]}") end @func_map[name] = f #define_method(name){|*args,&block| f.call(*args,&block)} begin /^(.+?):(\d+)/ =~ caller.first file, line = $1, $2.to_i rescue file, line = __FILE__, __LINE__+3 end module_eval(" def #{name}(*args,&block) @func_map['#{name}'].call(*args,&block) end ", file, line) module_function(name) f end

bind_function(name, ctype, argtype, call_type = nil, &block) Show source

name函数返回一个新的封闭包装。

  • ctype 是函数的返回类型

  • argtype 是一个传递给回调函数的参数数组

  • call_type 是关闭的abi

  • block 传递给回调

See Fiddle::Closure

# File ext/fiddle/lib/fiddle/import.rb, line 308 def bind_function(name, ctype, argtype, call_type = nil, &block) abi = CALL_TYPE_TO_ABI[call_type] closure = Class.new(Fiddle::Closure) { define_method(:call, block) }.new(ctype, argtype, abi) Function.new(closure, argtype, ctype, abi, name: name) end

create_value(ty, val=nil) Show source

创建一个类来包装具有值ty的C结构

另见#struct

# File ext/fiddle/lib/fiddle/import.rb, line 239 def create_value(ty, val=nil) s = struct([ty + " value"]) ptr = s.malloc() if( val ) ptr.value = val end return ptr end

别名:值

dlload(*libs) Show source

为给定的数组创建一个处理程序数组libs,可以是Fiddle :: Handle,Fiddle :: Importer的一个实例,或者将使用Fiddle#dlopen创建Fiddle :: Handle的新实例

如果库无法加载,则引发DLError。

请参阅Fiddle#dlopen

# File ext/fiddle/lib/fiddle/import.rb, line 75 def dlload(*libs) handles = libs.collect{|lib| case lib when nil nil when Handle lib when Importer lib.handlers else begin Fiddle.dlopen(lib) rescue DLError raise(DLError, "can't load #{lib}") end end }.flatten() @handler = CompositeHandler.new(handles) @func_map = {} @type_alias = {} end

extern(signature, *opts) Show source

根据给定的C signature创建一个全局方法。

# File ext/fiddle/lib/fiddle/import.rb, line 164 def extern(signature, *opts) symname, ctype, argtype = parse_signature(signature, type_alias) opt = parse_bind_options(opts) f = import_function(symname, ctype, argtype, opt[:call_type]) name = symname.gsub(/@.+/,'') @func_map[name] = f # define_method(name){|*args,&block| f.call(*args,&block)} begin /^(.+?):(\d+)/ =~ caller.first file, line = $1, $2.to_i rescue file, line = __FILE__, __LINE__+3 end module_eval(" def #{name}(*args, &block) @func_map['#{name}'].call(*args,&block) end ", file, line) module_function(name) f end

handler() Show source

The Fiddle::CompositeHandler instance

如果没有处理程序处于打开状态,则会引发错误。

# File ext/fiddle/lib/fiddle/import.rb, line 261 def handler (@handler ||= nil) or raise "call dlload before importing symbols and functions" end

import_function(name, ctype, argtype, call_type = nil) Show source

在给定name函数的内存地址返回一个新的Fiddle :: Function实例。

如果name不存在,则引发DLError 。

  • argtype是传递给name函数的一个参数数组。

  • ctype 是函数的返回类型

  • call_type 是函数的ABI

另请参见Fiddle:Function.new

请参阅Fiddle :: CompositeHandler#sym 和 Fiddle :: Handler.sym

# File ext/fiddle/lib/fiddle/import.rb, line 291 def import_function(name, ctype, argtype, call_type = nil) addr = handler.sym(name) if( !addr ) raise(DLError, "cannot find the function: #{name}()") end Function.new(addr, argtype, ctype, CALL_TYPE_TO_ABI[call_type], name: name) end

import_symbol(name) Show source

在给定名称符号的内存地址返回一个新的Fiddle :: Pointer实例。

如果name不存在,则引发DLError 。

请参阅Fiddle :: CompositeHandler#sym 和 Fiddle :: Handle.sym

# File ext/fiddle/lib/fiddle/import.rb, line 271 def import_symbol(name) addr = handler.sym(name) if( !addr ) raise(DLError, "cannot find the symbol: #{name}") end Pointer.new(addr) end

import_value(ty, addr) Show source

返回地址为addr的值为ty的C结构的新实例。

# File ext/fiddle/lib/fiddle/import.rb, line 251 def import_value(ty, addr) s = struct([ty + " value"]) ptr = s.new(addr) return ptr end

sizeof(ty) Show source

返回sizeof ty,使用Fiddle :: CParser#parse_ctype来确定C类型和适当的Fiddle常量。

# File ext/fiddle/lib/fiddle/import.rb, line 104 def sizeof(ty) case ty when String ty = parse_ctype(ty, type_alias).abs() case ty when TYPE_CHAR return SIZEOF_CHAR when TYPE_SHORT return SIZEOF_SHORT when TYPE_INT return SIZEOF_INT when TYPE_LONG return SIZEOF_LONG when TYPE_LONG_LONG return SIZEOF_LONG_LONG when TYPE_FLOAT return SIZEOF_FLOAT when TYPE_DOUBLE return SIZEOF_DOUBLE when TYPE_VOIDP return SIZEOF_VOIDP else raise(DLError, "unknown type: #{ty}") end when Class if( ty.instance_methods().include?(:to_ptr) ) return ty.size() end end return Pointer[ty].size() end

struct(signature) Show source

创建一个类来包装由signature描述的C结构。

MyStruct = struct ['int i', 'char c']

# File ext/fiddle/lib/fiddle/import.rb, line 217 def struct(signature) tys, mems = parse_struct_signature(signature, type_alias) Fiddle::CStructBuilder.create(CStruct, tys, mems) end

typealias(alias_type, orig_type) Show source

将alias_type的类型别名设置为orig_type

# File ext/fiddle/lib/fiddle/import.rb, line 98 def typealias(alias_type, orig_type) @type_alias[alias_type] = orig_type end

union(signature) Show source

创建一个类来包装由signature描述的C联合。

MyUnion = union ['int i', 'char c']

# File ext/fiddle/lib/fiddle/import.rb, line 225 def union(signature) tys, mems = parse_struct_signature(signature, type_alias) Fiddle::CStructBuilder.create(CUnion, tys, mems) end

value(ty, val=nil)

别名为:create_value

私有实例方法

parse_bind_options(opts) Show source

# File ext/fiddle/lib/fiddle/import.rb, line 136 def parse_bind_options(opts) h = {} while( opt = opts.shift() ) case opt when :stdcall, :cdecl h[:call_type] = opt when :carried, :temp, :temporal, :bind h[:callback_type] = opt h[:carrier] = opts.shift() else h[opt] = true end end h end