Module: Fiddle

Included in:
Importer
Defined in:
ext/fiddle/fiddle.c,
lib/fiddle.rb,
lib/fiddle/pack.rb,
lib/fiddle/types.rb,
lib/fiddle/value.rb,
lib/fiddle/import.rb,
lib/fiddle/struct.rb,
lib/fiddle/closure.rb,
lib/fiddle/cparser.rb,
lib/fiddle/version.rb,
lib/fiddle/function.rb,
lib/fiddle/ffi_backend.rb,
ext/fiddle/fiddle.c,
ext/fiddle/closure.c

Overview

A libffi wrapper for Ruby.

Description

Fiddle is an extension to translate a foreign function interface (FFI) with ruby.

It wraps libffi, a popular C library which provides a portable interface that allows code written in one language to call code written in another language.

Example

Here we will use Fiddle::Function to wrap floor(3) from libm

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

Defined Under Namespace

Modules: BasicTypes, CParser, CStructBuilder, FFIBackend, Importer, PackInfo, Types, ValueUtil, Win32Types Classes: CStruct, CStructEntity, CUnion, CUnionEntity, ClearedReferenceError, Closure, CompositeHandler, DLError, Error, Function, Handle, MemoryView, Packer, Pinned, Pointer, StructArray

Constant Summary collapse

RTLD_GLOBAL =

Add constants for backwards compat

Handle::RTLD_GLOBAL
RTLD_LAZY =

:nodoc:

Handle::RTLD_LAZY
RTLD_NOW =

:nodoc:

Handle::RTLD_NOW
VERSION =
"1.1.6"
WINDOWS =
Qfalse
RUBY_FREE =

Address of the ruby_xfree() function

PTR2NUM(ruby_xfree)
NULL =

A NULL pointer

rb_fiddle_ptr_new(0, 0, 0)
ALIGN_VOIDP =

The alignment size of a void*

INT2NUM(ALIGN_VOIDP)
ALIGN_CHAR =

The alignment size of a char

INT2NUM(ALIGN_CHAR)
ALIGN_SHORT =

The alignment size of a short

INT2NUM(ALIGN_SHORT)
ALIGN_INT =

The alignment size of an int

INT2NUM(ALIGN_INT)
ALIGN_LONG =

The alignment size of a long

INT2NUM(ALIGN_LONG)
ALIGN_LONG_LONG =

The alignment size of a long long

INT2NUM(ALIGN_LONG_LONG)
ALIGN_INT8_T =

The alignment size of a int8_t

INT2NUM(ALIGN_INT8_T)
ALIGN_INT16_T =

The alignment size of a int16_t

INT2NUM(ALIGN_INT16_T)
ALIGN_INT32_T =

The alignment size of a int32_t

INT2NUM(ALIGN_INT32_T)
ALIGN_INT64_T =

The alignment size of a int64_t

INT2NUM(ALIGN_INT64_T)
ALIGN_FLOAT =

The alignment size of a float

INT2NUM(ALIGN_FLOAT)
ALIGN_DOUBLE =

The alignment size of a double

INT2NUM(ALIGN_DOUBLE)
ALIGN_BOOL =

The alignment size of a bool

INT2NUM(ALIGN_OF(bool))
ALIGN_SIZE_T =

The alignment size of a size_t

INT2NUM(ALIGN_OF(size_t))
ALIGN_SSIZE_T =

same as size_t

INT2NUM(ALIGN_OF(size_t))
ALIGN_PTRDIFF_T =

The alignment size of a ptrdiff_t

INT2NUM(ALIGN_OF(ptrdiff_t))
ALIGN_INTPTR_T =

The alignment size of a intptr_t

INT2NUM(ALIGN_OF(intptr_t))
ALIGN_UINTPTR_T =

The alignment size of a uintptr_t

INT2NUM(ALIGN_OF(uintptr_t))
SIZEOF_VOIDP =

size of a void*

INT2NUM(sizeof(void*))
SIZEOF_CHAR =

size of a char

INT2NUM(sizeof(char))
SIZEOF_UCHAR =

size of a unsigned char

INT2NUM(sizeof(unsigned char))
SIZEOF_SHORT =

size of a short

INT2NUM(sizeof(short))
SIZEOF_USHORT =

size of a unsigned short

INT2NUM(sizeof(unsigned short))
SIZEOF_INT =

size of an int

INT2NUM(sizeof(int))
SIZEOF_UINT =

size of an unsigned int

INT2NUM(sizeof(unsigned int))
SIZEOF_LONG =

size of a long

INT2NUM(sizeof(long))
SIZEOF_ULONG =

size of a unsigned long

INT2NUM(sizeof(unsigned long))
SIZEOF_LONG_LONG =

size of a long long

INT2NUM(sizeof(LONG_LONG))
SIZEOF_ULONG_LONG =

size of a unsigned long long

INT2NUM(sizeof(unsigned LONG_LONG))
SIZEOF_INT8_T =

size of a int8_t

INT2NUM(sizeof(int8_t))
SIZEOF_UINT8_T =

size of a uint8_t

INT2NUM(sizeof(uint8_t))
SIZEOF_INT16_T =

size of a int16_t

INT2NUM(sizeof(int16_t))
SIZEOF_UINT16_T =

size of a uint16_t

INT2NUM(sizeof(uint16_t))
SIZEOF_INT32_T =

size of a int32_t

INT2NUM(sizeof(int32_t))
SIZEOF_UINT32_T =

size of a uint32_t

INT2NUM(sizeof(uint32_t))
SIZEOF_INT64_T =

size of a int64_t

INT2NUM(sizeof(int64_t))
SIZEOF_UINT64_T =

size of a uint64_t

INT2NUM(sizeof(uint64_t))
SIZEOF_FLOAT =

size of a float

INT2NUM(sizeof(float))
SIZEOF_DOUBLE =

size of a double

INT2NUM(sizeof(double))
SIZEOF_BOOL =

size of a bool

INT2NUM(sizeof(bool))
SIZEOF_SIZE_T =

size of a size_t

INT2NUM(sizeof(size_t))
SIZEOF_SSIZE_T =

same as size_t

INT2NUM(sizeof(size_t))
SIZEOF_PTRDIFF_T =

size of a ptrdiff_t

INT2NUM(sizeof(ptrdiff_t))
SIZEOF_INTPTR_T =

size of a intptr_t

INT2NUM(sizeof(intptr_t))
SIZEOF_UINTPTR_T =

size of a uintptr_t

INT2NUM(sizeof(uintptr_t))
SIZEOF_CONST_STRING =

size of a const char*

INT2NUM(sizeof(const char*))
BUILD_RUBY_PLATFORM =

Platform built against (i.e. “x86_64-linux”, etc.)

See also RUBY_PLATFORM

rb_str_new2(RUBY_PLATFORM)
Qtrue =

The value of Qtrue

INT2NUM(Qtrue)
Qfalse =

The value of Qfalse

INT2NUM(Qfalse)
Qnil =

The value of Qnil

INT2NUM(Qnil)
Qundef =

The value of Qundef

INT2NUM(Qundef)

Class Method Summary collapse

Class Method Details

.dlopen(library) ⇒ Object

call-seq: dlopen(library) => Fiddle::Handle

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

If nil is given for the library, Fiddle::Handle::DEFAULT is used, which is the equivalent to RTLD_DEFAULT. See man 3 dlopen for more.

lib = Fiddle.dlopen(nil)

The default is dependent on OS, and provide a handle for all libraries already loaded. For example, in most cases you can use this to access libc functions, or ruby functions like rb_str_new.

See Fiddle::Handle.new for more.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File '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

.dlunwrap(addr) ⇒ Object

Returns the Ruby object stored at the memory address addr

Example:

x = Object.new
# => #<Object:0x0000000107c7d870>
Fiddle.dlwrap(x)
# => 4425504880
Fiddle.dlunwrap(_)
# => #<Object:0x0000000107c7d870>


74
75
76
77
78
# File 'ext/fiddle/fiddle.c', line 74

VALUE
rb_fiddle_ptr2value(VALUE self, VALUE addr)
{
    return (VALUE)NUM2PTR(addr);
}

.dlwrap(val) ⇒ Object

Returns the memory address of the Ruby object stored at val

Example:

x = Object.new
# => #<Object:0x0000000107c7d870>
Fiddle.dlwrap(x)
# => 4425504880

In the case val is not a heap allocated object, this method will return the tagged pointer value.

Example:

Fiddle.dlwrap(123)
# => 247


100
101
102
# File 'ext/fiddle/fiddle.c', line 100

def self.dlwrap(val)
  Pointer.to_ptr(val)
end

.free(addr) ⇒ Object

Free the memory at address addr



51
52
53
54
# File 'ext/fiddle/fiddle.c', line 51

def self.free(ptr)
  Fiddle::Pointer::LibC::FREE.call(ptr)
  nil
end

.last_errorObject

Returns the last Error of the current executing Thread or nil if none



57
58
59
60
61
62
63
64
# File '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

.last_error=(error) ⇒ Object

Sets the last Error of the current executing Thread to error



67
68
69
70
71
72
73
74
# File '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

.malloc(size) ⇒ Object

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



22
23
24
# File 'ext/fiddle/fiddle.c', line 22

def self.malloc(size)
  Fiddle::Pointer.malloc(size)
end

.realloc(addr, size) ⇒ Object

Change the size of the memory allocated at the memory location addr to size bytes. Returns the memory address of the reallocated memory, which may be different than the address passed in.



37
38
39
40
41
42
43
44
# File 'ext/fiddle/fiddle.c', line 37

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);
}

.win32_last_errorObject

Returns the last win32 Error of the current executing Thread or nil if none



16
17
18
19
20
21
22
23
# File '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

.win32_last_error=(error) ⇒ Object

Sets the last win32 Error of the current executing Thread to error



26
27
28
29
30
31
32
# File '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

.win32_last_socket_errorObject

Returns the last win32 socket Error of the current executing Thread or nil if none



36
37
38
39
40
41
42
43
# File '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

.win32_last_socket_error=(error) ⇒ Object

Sets the last win32 socket Error of the current executing Thread to error



47
48
49
50
51
52
53
# File '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