Foreign function interface (FFI)
FFI is used to allow a program written in one language invoke functions written in another.
In this example I wrote a small c program that we are going to invoke from a ruby program.
static const char* alias_name = "ALTER_EGO";
char* greet(char* name)
{
char* alias = getenv(alias_name);
char* buffer = (char*)malloc(128);
snprintf(buffer, 128, "Hello %s!\n", alias == NULL ? name : alias);
return buffer;
}
From the ruby side of the world we can use ‘ffi’ to load our c program. First we will need to compile our shared object (.so) file so that we can access it.
$ gcc -shared -o libgreeting.so -fPIC greeting.c
Now we can use FFI to define the interface of the c library function that we wish to invoke.
require 'ffi'
class Greeting
extend FFI::Library
ffi_lib 'greeting'
attach_function :greet, [:string], :string
end
puts Greeting.greet('mo')
The ffi_lib call loads the libgreeting.so file. attach_function defines a function called greet that accepts a string as an input argument and returns a string.
Now when we run this:
λ rake run
rm -f *.so
gcc -shared -o libgreeting.so -fPIC greeting.c
LD_LIBRARY_PATH=. ruby greeting.rb
Hello mo!
We can also run this with environment variable loaded.
λ ALTER_EGO=slim rake run
rm -f *.so
gcc -shared -o libgreeting.so -fPIC greeting.c
LD_LIBRARY_PATH=. ruby greeting.rb
Hello slim!
The full source code for this can be found on github.