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.
This gives you access to libraries & code that otherwise you would not have.
In Ruby, we often use this to work with C code.
You can write your own programs that use FFI with the help of the FFI module.
Let’s see some code examples!
FFI Basics: Loading & Importing Functions
You can work with FFI by including its functions into a module you create.
require 'ffi' module A extend FFI::Library end
Then, inside the module, we are going to load a library using the
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.
module A extend FFI::Library ffi_lib 'c' end
You can import specific functions from this library as Ruby methods.
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.
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:
For this example, we’re going to use VLC’s media player library:
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.
VLC.libvlc_get_version # "3.0.6 Vetinari"
You can give these methods a custom name by adding a 4th parameter.
attach_function :get_version, :libvlc_get_version, , :string
Then you can do:
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
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.
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!
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!