I want to answer one simple question…
What is FFI in Ruby?
FFI stands for “Foreign Function Interface”.
It’s a way to use functions defined in other programming languages.
Ruby’s FFI module gives you access to external libraries & code that you wouldn’t have otherwise.
We often use this to work with C code.
Examples include:
You can write your own programs that use FFI with the help of the FFI module.
How?
Let’s see a few code examples!
FFI Basics: Loading & Importing Functions
You can work with FFI by including its functions into a module you create.
Like this:
require 'ffi' module A extend FFI::Library end
Then, inside the module, we are going to load a library using the ffi_lib
method.
A C library, like a “DLL” in Windows, or “SO” in Linux, exports a list of “symbols”, or function definitions that a program makes available for others to use.
Let’s require “libc“, C’s standard library.
Here’s how:
module A extend FFI::Library ffi_lib 'c' end
Now:
You can import specific functions from this library as Ruby methods.
With the attach_function
method.
Here’s an example:
module A extend FFI::Library ffi_lib 'c' attach_function :strlen, [:string], :int end A.strlen("abc") # 3
How does this work?
First, we know that there is a function in C called strlen
, this function takes chars *
as an argument.
chars *
translates to String
in Ruby.
Then…
This strlen
function returns a value, which is the length of the string.
In other words, attach_function
takes 3 parameters:
- Name of the C function
- An array of argument types
- A return type
You’ll have to read the documentation to find out which types a particular function works with.
Time for another example!
Build Your Own Media Player
You can find many interesting libraries to play with.
In Linux, most are found under the /usr/lib/
directory, starting with “lib” in their name & ending with the “so” extension.
List them like this:
ls /usr/lib/lib*.so
For this example, we’re going to use VLC’s media player library:
/usr/lib/libvlc.so
Our goal is to load an mp3 file & play it!
Let’s start with this:
require 'ffi' module VLC extend FFI::Library ffi_lib 'vlc' attach_function :libvlc_get_version, [], :string end
This allows you to test if the library is loading correctly & then print its version.
Like this:
VLC.libvlc_get_version # "3.0.6 Vetinari"
You can give these methods a custom name by adding a 4th parameter.
Example:
attach_function :get_version, :libvlc_get_version, [], :string
Then you can do:
VLC.get_version
What do we need to play an mp3 now?
If we look at the documentation, the libvlc_media_player_play
function looks like the way to go.
This function needs a media player “object”.
A media player needs a media, and a media needs a VLC instance.
Here’s the process:
VLC instance -> media -> media_player -> play
I pieced this together by reading the documentation for libVLC
.
Memory Pointers in Ruby???
In C you’ll not find any objects, everything is handled with memory pointers.
A memory pointer is a memory address with data.
Let’s see a code example:
module VLC extend FFI::Library ffi_lib 'vlc' attach_function :get_version, :libvlc_get_version, [], :string attach_function :new, :libvlc_new, [:int, :int], :pointer end VLC.new(0, 0) # FFI::Pointer address=0x000055c6f04ae7b0
As a result of calling VLC.new
we get a pointer.
We have to pass it along to other C functions that need it.
Now:
The full example & how to use it.
module VLC extend FFI::Library ffi_lib 'vlc' attach_function :version, :libvlc_get_version, [], :string attach_function :new, :libvlc_new, [:int, :int], :pointer attach_function :libvlc_media_new_path, [:pointer, :string], :pointer attach_function :libvlc_media_player_new_from_media, [:pointer], :pointer attach_function :play, :libvlc_media_player_play, [:pointer], :int attach_function :stop, :libvlc_media_player_stop, [:pointer], :int attach_function :pause, :libvlc_media_player_pause, [:pointer], :int end
That’s enough to play some music:
vlc = VLC.new(0, 0) media = VLC.libvlc_media_new_path(vlc, "/home/jesus/Downloads/meditation.mp3") player = VLC.libvlc_media_player_new_from_media(media) VLC.play(player)
This will play the music, without opening any kind of visual interface.
You could build your own web interface on top of this.
Give it a try!
Summary
You’ve learned about the amazing power of FFI
! A Ruby module that allows you to use external libraries as if they were part of the language itself.
Please share this article so more people can enjoy it
Thanks for reading!
Great article, Thanks!
Thanks for reading
Thanks for sharing, i couldnt find libvlc.so on my lib folder btw
Thanks for reading! You need the VLC media player installed on your computer
If you installed vlc via apt-get you can use ‘libvlc.so.5’. Probably there is no more ‘libvlc.so’
Thanks for great article!
Thanks for reading!
Is it possible to do it with Mac OS?
Yes, give it a try