# module Fiddle

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

### Constants

ALIGN_BOOL

  `ALIGN_BOOL`

  The alignment size of a bool

ALIGN_CHAR

  `ALIGN_CHAR`

  The alignment size of a char

ALIGN_DOUBLE

  `ALIGN_DOUBLE`

  The alignment size of a double

ALIGN_FLOAT

  `ALIGN_FLOAT`

  The alignment size of a float

ALIGN_INT

  `ALIGN_INT`

  The alignment size of an int

ALIGN_INT16_T

  `ALIGN_INT16_T`

  The alignment size of a int16_t

ALIGN_INT32_T

  `ALIGN_INT32_T`

  The alignment size of a int32_t

ALIGN_INT64_T

  `ALIGN_INT64_T`

  The alignment size of a int64_t

ALIGN_INT8_T

  `ALIGN_INT8_T`

  The alignment size of a int8_t

ALIGN_INTPTR_T

  `ALIGN_INTPTR_T`

  The alignment size of a intptr_t

ALIGN_LONG

  `ALIGN_LONG`

  The alignment size of a long

ALIGN_LONG_LONG

  `ALIGN_LONG_LONG`

  The alignment size of a long long

ALIGN_PTRDIFF_T

  `ALIGN_PTRDIFF_T`

  The alignment size of a ptrdiff_t

ALIGN_SHORT

  `ALIGN_SHORT`

  The alignment size of a short

ALIGN_SIZE_T

  `ALIGN_SIZE_T`

  The alignment size of a size_t

ALIGN_SSIZE_T

  `ALIGN_SSIZE_T`

  The alignment size of a ssize_t

ALIGN_UINTPTR_T

  `ALIGN_UINTPTR_T`

  The alignment size of a uintptr_t

ALIGN_VOIDP

  `ALIGN_VOIDP`

  The alignment size of a void*

BUILD_RUBY_PLATFORM

  `BUILD_RUBY_PLATFORM`

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

  See also RUBY_PLATFORM

NULL
Qfalse

  `Qfalse`

  The value of `Qfalse`

Qnil

  `Qnil`

  The value of `Qnil`

Qtrue

  `Qtrue`

  The value of `Qtrue`

Qundef

  `Qundef`

  The value of `Qundef`

RUBY_FREE

  `RUBY_FREE`

  Address of the ruby_xfree() function

SIZEOF_BOOL

  `SIZEOF_BOOL`

  size of a bool

SIZEOF_CHAR

  `SIZEOF_CHAR`

  size of a char

SIZEOF_CONST_STRING

  `SIZEOF_CONST_STRING`

  size of a const char*

SIZEOF_DOUBLE

  `SIZEOF_DOUBLE`

  size of a double

SIZEOF_FLOAT

  `SIZEOF_FLOAT`

  size of a float

SIZEOF_INT

  `SIZEOF_INT`

  size of an int

SIZEOF_INT16_T

  `SIZEOF_INT16_T`

  size of a int16_t

SIZEOF_INT32_T

  `SIZEOF_INT32_T`

  size of a int32_t

SIZEOF_INT64_T

  `SIZEOF_INT64_T`

  size of a int64_t

SIZEOF_INT8_T

  `SIZEOF_INT8_T`

  size of a int8_t

SIZEOF_INTPTR_T

  `SIZEOF_INTPTR_T`

  size of a intptr_t

SIZEOF_LONG

  `SIZEOF_LONG`

  size of a long

SIZEOF_LONG_LONG

  `SIZEOF_LONG_LONG`

  size of a long long

SIZEOF_PTRDIFF_T

  `SIZEOF_PTRDIFF_T`

  size of a ptrdiff_t

SIZEOF_SHORT

  `SIZEOF_SHORT`

  size of a short

SIZEOF_SIZE_T

  `SIZEOF_SIZE_T`

  size of a size_t

SIZEOF_SSIZE_T

  `SIZEOF_SSIZE_T`

  size of a ssize_t

SIZEOF_UCHAR

  `SIZEOF_UCHAR`

  size of a unsigned char

SIZEOF_UINT

  `SIZEOF_UINT`

  size of an unsigned int

SIZEOF_UINT16_T

  `SIZEOF_UINT16_T`

  size of a uint16_t

SIZEOF_UINT32_T

  `SIZEOF_UINT32_T`

  size of a uint32_t

SIZEOF_UINT64_T

  `SIZEOF_UINT64_T`

  size of a uint64_t

SIZEOF_UINT8_T

  `SIZEOF_UINT8_T`

  size of a uint8_t

SIZEOF_UINTPTR_T

  `SIZEOF_UINTPTR_T`

  size of a uintptr_t

SIZEOF_ULONG

  `SIZEOF_ULONG`

  size of a unsigned long

SIZEOF_ULONG_LONG

  `SIZEOF_ULONG_LONG`

  size of a unsigned long long

SIZEOF_USHORT

  `SIZEOF_USHORT`

  size of a unsigned short

SIZEOF_VOIDP

  `SIZEOF_VOIDP`

  size of a void*

VERSION
WINDOWS

  Returns a boolean regarding whether the host is WIN32

### Public Class Methods

dlopen(library) → Fiddle::Handle
Source

    # File ext/fiddle/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

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.

dlunwrap(addr)
Source

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

Returns the Ruby object stored at the memory address `addr`

Example:

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

dlwrap(val)
Source

    static VALUE
    rb_fiddle_value2ptr(VALUE self, VALUE val)
    {
        return PTR2NUM((void*)val);
    }

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

free(addr)
Source

    VALUE
    rb_fiddle_free(VALUE self, VALUE addr)
    {
        void *ptr = NUM2PTR(addr);

        ruby_xfree(ptr);
        return Qnil;
    }

Free the memory at address `addr`

last_error ()
Source

    # File ext/fiddle/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

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

last_error= (error)
Source

    # File ext/fiddle/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

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

malloc(size)
Source

    static VALUE
    rb_fiddle_malloc(VALUE self, VALUE size)
    {
        void *ptr;
        ptr = (void*)ruby_xcalloc(1, NUM2SIZET(size));
        return PTR2NUM(ptr);
    }

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

realloc(addr, size)
Source

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

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.

win32_last_error ()
Source

    # File ext/fiddle/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

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

win32_last_error= (error)
Source

    # File ext/fiddle/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

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

win32_last_socket_error ()
Source

    # File ext/fiddle/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

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

win32_last_socket_error= (error)
Source

    # File ext/fiddle/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

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

### Private Instance Methods

dlopen(library) → Fiddle::Handle
Source

    # File ext/fiddle/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

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.