123456789_123456789_123456789_123456789_123456789_

Module: Fiddle::Importer

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, CParser, ::Fiddle
Defined in: ext/fiddle/lib/fiddle/import.rb

Overview

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.

Example

require 'fiddle'
require 'fiddle/import'

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

Constant Summary

::Fiddle - Included

ALIGN_CHAR, ALIGN_DOUBLE, ALIGN_FLOAT, ALIGN_INT, ALIGN_INTPTR_T, ALIGN_LONG, ALIGN_LONG_LONG, ALIGN_PTRDIFF_T, ALIGN_SHORT, ALIGN_SIZE_T, ALIGN_SSIZE_T, ALIGN_UINTPTR_T, ALIGN_VOIDP, BUILD_RUBY_PLATFORM, NULL, RUBY_FREE, SIZEOF_CHAR, SIZEOF_DOUBLE, SIZEOF_FLOAT, SIZEOF_INT, SIZEOF_INTPTR_T, SIZEOF_LONG, SIZEOF_LONG_LONG, SIZEOF_PTRDIFF_T, SIZEOF_SHORT, SIZEOF_SIZE_T, SIZEOF_SSIZE_T, SIZEOF_UINTPTR_T, SIZEOF_VOIDP, TYPE_CHAR, TYPE_DOUBLE, TYPE_FLOAT, TYPE_INT, TYPE_INTPTR_T, TYPE_LONG, TYPE_LONG_LONG, TYPE_PTRDIFF_T, TYPE_SHORT, TYPE_SIZE_T, TYPE_SSIZE_T, TYPE_UINTPTR_T, TYPE_VOID, TYPE_VOIDP, WINDOWS

Instance Method Summary

CParser - Included

#parse_ctype

Given a String of C type ty, returns the corresponding ::Fiddle constant.

#parse_signature

Parses a C prototype signature.

#parse_struct_signature

Parses a C struct's members.

#compact, #split_arguments

::Fiddle - Included

#dlopen

Creates a new handler that opens library, and returns an instance of Handle.

#dlunwrap

Returns the hexadecimal representation of a memory pointer address addr

#dlwrap

Returns a memory pointer of a function's hexadecimal address location val

#free

Free the memory at address addr

#malloc

Allocate size bytes of memory and return the integer memory address for the allocated memory.

#realloc

Change the size of the memory allocated at the memory location addr to size bytes.

Instance Method Details

#[](name)

Returns the function mapped to name, that was created by either #extern or #bind

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 230

def [](name)
  @func_map[name]
end

#bind(signature, *opts, &blk)

Creates a global method from the given C signature using the given opts as bind parameters with the given block.

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 186

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

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

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 Closure

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 306

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) Also known as: #value

Creates a class to wrap the C struct with the value ty

See also #struct

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 237

def create_value(ty, val=nil)
  s = struct([ty + " value"])
  ptr = s.malloc()
  if( val )
    ptr.value = val
  end
  return ptr
end

#dlload(*libs)

Creates an array of handlers for the given libs, can be an instance of Handle, Importer, or will create a new instance of Handle using Fiddle.dlopen

Raises a DLError if the library cannot be loaded.

See Fiddle.dlopen

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 73

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)

Creates a global method from the given C signature.

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 162

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

#handler

The CompositeHandler instance

Will raise an error if no handlers are open.

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 259

def handler
  @handler or raise "call dlload before importing symbols and functions"
end

#import_function(name, ctype, argtype, call_type = nil)

Returns a new 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

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 289

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)

Returns a new 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 Handle.sym

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 269

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)

Returns a new instance of the C struct with the value ty at the addr address.

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 249

def import_value(ty, addr)
  s = struct([ty + " value"])
  ptr = s.new(addr)
  return ptr
end

#parse_bind_options(opts) (private)

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 134

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

#sizeof(ty)

Returns the sizeof ty, using Fiddle::Importer.parse_ctype to determine the C type and the appropriate ::Fiddle constant.

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 102

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)

Creates a class to wrap the C struct described by signature.

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

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 215

def struct(signature)
  tys, mems = parse_struct_signature(signature, @type_alias)
  Fiddle::CStructBuilder.create(CStruct, tys, mems)
end

#typealias(alias_type, orig_type)

Sets the type alias for alias_type as orig_type

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 96

def typealias(alias_type, orig_type)
  @type_alias[alias_type] = orig_type
end

#union(signature)

Creates a class to wrap the C union described by signature.

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

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 223

def union(signature)
  tys, mems = parse_struct_signature(signature, @type_alias)
  Fiddle::CStructBuilder.create(CUnion, tys, mems)
end

#value(ty, val = nil)

Alias for #create_value.

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/import.rb', line 245

alias value create_value