Skip to content
akzhan edited this page Apr 9, 2012 · 10 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
end

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, or any library used by the current process (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.

Note that windows users will want to add an extra ffi_lib 'msvcrt' in there, to get access to the puts method.

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
end

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](http://en.wikipedia.org/wiki/Stdcall calling) 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 unpointered structs to methods

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

typedef struct _WHAT {
  int d;
} WHAT;

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

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

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

[StackOverflow Question Relating to this](http://stackoverflow.com/questions/8982393/how-to-wrap-function-in-ruby-ffi-method-that-takes-struct-as-argument/8990201#8990201)

## External links

[Charles Nutter's FFI announcement](http://blog.headius.com/2008/10/ffi-for-ruby-now-available.html)
Clone this wiki locally