A DSL that provides the means to dynamically load libraries and build modules around them including calling extern functions within the C library that has been loaded.
require 'fiddle' require 'fiddle/import' module LibSum extend Fiddle::Importer dlload './libsum.so' extern 'double sum(double*, int)' extern 'double split(double)' end
Creates a global method from the given C signature using the
given opts as bind parameters with the given block.
# File fiddle/lib/fiddle/import.rb, line 185
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
Returns a new closure wrapper for the name function.
ctype is the return type of the function
argtype is an Array of arguments, passed to the callback
function
call_type is the abi of the closure
block is passed to the callback
See Fiddle::Closure
# File fiddle/lib/fiddle/import.rb, line 305
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
Creates a class to wrap the C struct with the value ty
See also #struct
# File fiddle/lib/fiddle/import.rb, line 236
def create_value(ty, val=nil)
s = struct([ty + " value"])
ptr = s.malloc()
if( val )
ptr.value = val
end
return ptr
end
Creates an array of handlers for the given libs, can be an
instance of Fiddle::Handle, Fiddle::Importer, or will create a new istance of
Fiddle::Handle using Fiddle.dlopen
Raises a DLError if the library cannot be loaded.
See Fiddle.dlopen
# File fiddle/lib/fiddle/import.rb, line 72
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
Creates a global method from the given C signature.
# File fiddle/lib/fiddle/import.rb, line 161
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
The Fiddle::CompositeHandler instance
Will raise an error if no handlers are open.
# File fiddle/lib/fiddle/import.rb, line 258
def handler
@handler or raise "call dlload before importing symbols and functions"
end
Returns a new Fiddle::Function instance at the
memory address of the given name function.
Raises a DLError if the name
doesn’t exist.
argtype is an Array of arguments, passed to the
name function.
ctype is the return type of the function
call_type is the ABI of the function
See also Fiddle:Function.new
See Fiddle::CompositeHandler#sym and Fiddle::Handler.sym
# File fiddle/lib/fiddle/import.rb, line 288
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
Returns a new Fiddle::Pointer instance at the
memory address of the given name symbol.
Raises a DLError if the name
doesn’t exist.
See Fiddle::CompositeHandler#sym and Fiddle::Handle.sym
# File fiddle/lib/fiddle/import.rb, line 268
def import_symbol(name)
addr = handler.sym(name)
if( !addr )
raise(DLError, "cannot find the symbol: #{name}")
end
Pointer.new(addr)
end
Returns a new instance of the C struct with the value ty at
the addr address.
# File fiddle/lib/fiddle/import.rb, line 248
def import_value(ty, addr)
s = struct([ty + " value"])
ptr = s.new(addr)
return ptr
end
Returns the sizeof ty, using Fiddle::CParser#parse_ctype to
determine the C type and the appropriate Fiddle constant.
# File 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_LONG_LONG
return SIZEOF_LONG_LON
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
Creates a class to wrap the C struct described by signature.
MyStruct = struct ['int i', 'char c']
# File fiddle/lib/fiddle/import.rb, line 214
def struct(signature)
tys, mems = parse_struct_signature(signature, @type_alias)
Fiddle::CStructBuilder.create(CStruct, tys, mems)
end
Sets the type alias for alias_type as orig_type
# File fiddle/lib/fiddle/import.rb, line 95
def typealias(alias_type, orig_type)
@type_alias[alias_type] = orig_type
end
Creates a class to wrap the C union described by signature.
MyUnion = union ['int i', 'char c']
# File fiddle/lib/fiddle/import.rb, line 222
def union(signature)
tys, mems = parse_struct_signature(signature, @type_alias)
Fiddle::CStructBuilder.create(CUnion, tys, mems)
end
Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.
If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.
If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.
If you want to help improve the Ruby documentation, please see Improve the docs, or visit Documenting-ruby.org.