ffi这个Gem功能是扩展C语言函数库,与Ruby对接。

扩展C原生库

require 'ffi'

module MyLib
  extend FFI::Library
  ffi_lib 'c'
  attach_function :puts, [ :string ], :int
end

MyLib.puts 'Hello, World using libc!'

扩展自定义C库

  • 编写自定义C库
//so_test.h:
#include "stdio.h"
void test_a();
void test_b();
void test_c();

//test_a.c:
#include "so_test.h"
void test_a()
{
  printf("this is in test_a...\n");
}

//test_b.c:
#include "so_test.h"
void test_b()
{
  printf("this is in test_b...\n");
}

//test_c.c:
#include "so_test.h"
void test_c()
{
  printf("this is in test_c...\n");
}
  • 编译动态库生成*.so文件

将这几个文件编译成一个动态库:libtest.so

$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

  • 使用ffi移植函数
require 'ffi'

module MyLib
  extend FFI::Library
  ffi_lib 'libtest.so'
  attach_function :test_a, [], :void
  attach_function :test_b, [], :void
  attach_function :test_c, [], :void
end

MyLib.test_a #=> this is in test_a...
MyLib.test_b #=> this is in test_b...
MyLib.test_c #=> this is in test_c...

附录

动态库(.so)和静态库(.a) 的区别

  • [.a文件] 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。编译之后程序文件大,但加载快,隔离性也好。
  • [.so文件] 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。多个应用程序可以使用同一个动态库,启动多个应用程序的时候,只需要将动态库加载到内存一次即可。