模組 Fiddle::Importer
一個 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
屬性
公開執行個體方法
傳回對應到 name
的函式,該函式是由 Fiddle::Importer.extern
或 Fiddle::Importer.bind
所建立。
# File ext/fiddle/lib/fiddle/import.rb, line 237 def [](name) @func_map[name] end
使用給定的 signature
C 建立一個全域方法,並使用給定的 opts
作為繫結參數,以及給定的區塊。
# File ext/fiddle/lib/fiddle/import.rb, line 193 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(<<-EOS, file, line) def #{name}(*args,&block) @func_map['#{name}'].call(*args,&block) end EOS module_function(name) f end
傳回 name
函式的新的封閉包裝器。
-
ctype
是函式的傳回類型 -
argtype
是傳遞給回呼函式的Array
-
call_type
是封閉的 abi -
block
傳遞給回呼
請參閱 Fiddle::Closure
# File ext/fiddle/lib/fiddle/import.rb, line 313 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
建立一個類別來包裝具有值 ty
的 C 結構。
# File ext/fiddle/lib/fiddle/import.rb, line 244 def create_value(ty, val=nil) s = struct([ty + " value"]) ptr = s.malloc() if( val ) ptr.value = val end return ptr end
為給定的 libs
建立一個處理常式陣列,可以是 Fiddle::Handle
、Fiddle::Importer
的執行個體,或將使用 Fiddle.dlopen
建立 Fiddle::Handle
的新執行個體。
如果無法載入函式庫,會引發 DLError
。
請參閱 Fiddle.dlopen
# File ext/fiddle/lib/fiddle/import.rb, line 76 def dlload(*libs) handles = libs.collect{|lib| case lib when nil nil when Handle lib when Importer lib.handlers else Fiddle.dlopen(lib) end }.flatten() @handler = CompositeHandler.new(handles) @func_map = {} @type_alias = {} end
從指定的 C signature
建立全域方法。
# File ext/fiddle/lib/fiddle/import.rb, line 169 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(<<-EOS, file, line) def #{name}(*args, &block) @func_map['#{name}'].call(*args,&block) end EOS module_function(name) f end
如果沒有開啟任何處理常式,將引發錯誤。
# File ext/fiddle/lib/fiddle/import.rb, line 266 def handler (@handler ||= nil) or raise "call dlload before importing symbols and functions" end
傳回一個新的 Fiddle::Function
執行個體,其記憶體位址為指定的 name
函式。
如果 name
不存在,會引發 DLError
。
-
argtype
是傳遞給name
函式的引數Array
。 -
ctype
是函式的傳回類型 -
call_type
是函式的 ABI
另請參閱 Fiddle:Function.new
請參閱 Fiddle::CompositeHandler.sym
和 Fiddle::Handler.sym
# File ext/fiddle/lib/fiddle/import.rb, line 296 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
傳回一個新的 Fiddle::Pointer
執行個體,其記憶體位址為指定的 name
符號。
如果 name
不存在,會引發 DLError
。
請參閱 Fiddle::CompositeHandler.sym
和 Fiddle::Handle.sym
# File ext/fiddle/lib/fiddle/import.rb, line 276 def import_symbol(name) addr = handler.sym(name) if( !addr ) raise(DLError, "cannot find the symbol: #{name}") end Pointer.new(addr) end
傳回一個新的 C 結構執行個體,其值為 ty
,位址為 addr
。
# File ext/fiddle/lib/fiddle/import.rb, line 256 def import_value(ty, addr) s = struct([ty + " value"]) ptr = s.new(addr) return ptr end
傳回 ty
的 sizeof,使用 Fiddle::Importer.parse_ctype
來判斷 C 型別和適當的 Fiddle
常數。
# File ext/fiddle/lib/fiddle/import.rb, line 101 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_FLOAT return SIZEOF_FLOAT when TYPE_DOUBLE return SIZEOF_DOUBLE when TYPE_VOIDP return SIZEOF_VOIDP when TYPE_CONST_STRING return SIZEOF_CONST_STRING when TYPE_BOOL return SIZEOF_BOOL else if defined?(TYPE_LONG_LONG) and ty == TYPE_LONG_LONG return SIZEOF_LONG_LONG else raise(DLError, "unknown type: #{ty}") end end when Class if( ty.instance_methods().include?(:to_ptr) ) return ty.size() end end return Pointer[ty].size() end
建立一個類別來包裝 signature
所描述的 C 結構。
MyStruct = struct ['int i', 'char c']
# File ext/fiddle/lib/fiddle/import.rb, line 222 def struct(signature) tys, mems = parse_struct_signature(signature, type_alias) Fiddle::CStructBuilder.create(CStruct, tys, mems) end
設定 alias_type
的型別別名為 orig_type
# File ext/fiddle/lib/fiddle/import.rb, line 95 def typealias(alias_type, orig_type) @type_alias[alias_type] = orig_type end
建立一個類別來包裝由 signature
描述的 C union。
MyUnion = union ['int i', 'char c']
# File ext/fiddle/lib/fiddle/import.rb, line 230 def union(signature) tys, mems = parse_struct_signature(signature, type_alias) Fiddle::CStructBuilder.create(CUnion, tys, mems) end
私有實體方法
# File ext/fiddle/lib/fiddle/import.rb, line 140 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