Basic Usage

Leonid Vlasov edited this page May 29, 2017 · 8 revisions

Ruby programs can now easily call native C library functions via the FFI mechanism.

Basics: require 'ffi' and attach_function

The require 'ffi' directive will load and initialize the FFI library. You then need to use extend FFI::Library in a module you wish to attach native functions to, and finally, use attach_function to link the native C functions into the module.

Hello, World using FFI

require 'ffi'

module Hello
  extend FFI::Library
  ffi_lib FFI::Library::LIBC
  attach_function :puts, [ :string ], :int

Hello.puts("Hello, World")

The interesting part above is the attach_function call. It requests that a C function named puts which takes a :string argument and returns an :int, be attached to the Hello module.

The attach_function method locates the C function in a specific external library (i.e. libc in the example). To use it, you need to supply the name of the function to load, the parameter types the function takes, and the return type of the function.

Hello, Windows using FFI

require 'ffi'

module HelloWin
  extend FFI::Library

  ffi_lib 'user32'
  ffi_convention :stdcall

  attach_function :message_box, :MessageBoxA,[ :pointer, :string, :string, :uint ], :int

rc = HelloWin.message_box nil, 'Hello Windows!', 'FFI on Windows', 1
puts "Return code: #{rc}" 

Using the Windows API is almost as easy as the previous example. Typically you need to tell FFI what Windows library to search via the ffi_lib method and tell FFI to use the stdcall convention used by the Windows API. The ffi_convention method tells FFI what calling convention to use.

You also need to ensure that you attach the correctly named function to your Ruby module. For all functions that take string arguments, the Windows API provides "short name" macros that expand to function names with a suffix indicating ASCII or Unicode. ANSI versions are suffixed with a "A", and Unicode versions are suffixed with a "W".

Parameter and return types

Here below there is a partial list of the types supported by FFI. For a more exhaustive list you may look at Types page.

  • :char and :uchar - 8 bit signed and unsigned values
  • :short and :ushort - 16 bit signed and unsigned values
  • :int and :uint - 32 bit signed and unsigned values
  • :long_long and :ulong_long - 64 bit signed and unsigned values
  • :long and :ulong - native cpu word (32 bit or 64bit) signed and unsigned values. Equivalent to C 'long' type.
  • :float and :double
  • :string - C string, NULL terminated.
  • :pointer - a C pointer

Passing structs as value parameters to functions

Assuming you have a C library that looks like this, where the function takes a struct as an argument by value:

typedef struct _WHAT {
  int d;

int doit(WHAT w) {
  printf("%d\n", w.d);
  return w.d;

The resulting FFI wrapper code for the function should look like this:

class WHAT < FFI::Struct
  layout :d, :int
attach_function 'doit', [ WHAT.by_value ], :int

StackOverflow Question Relating to this

External links

Charles Nutter's FFI announcement