概要
ffi は C や C++ ように作成された共有ライブラリを Ruby で扱うことができるようにするためのライブラリです
libffi を使っているので事前にインストールが必要です
NativeExtensions を直接扱わずに C を操作することができます
今回は簡単なサンプルコード動かしてみました
環境
- macOS 10.14.3
- Ruby 2.5.1p57
- ffi 1.10.0
インストール
libffi がない場合は
brew install libffi
でインストールできます
bundle init
vim Gemfile
gem "ffi"
bundle install --path vendor
Hello world
とりあえず Hello world してみます
libc の printf
関数を Ruby で扱えるようにしてみます
require 'ffi'
module MyLib
extend FFI::Library
ffi_lib FFI::Library::LIBC
attach_function("my_printf", "printf", [ :string, :string ], :int)
end
MyLib.my_printf("%s\n", "hello")
FFI::Library::LIBC
は libc.dylib
という文字列が設定されています
各プラットフォームごとに読み込む共有ライブラリが違うので FFI::Library を使ったほうがいいです
Ruby 側で呼び出す関数名と C 側の関数名を紐付けるには attach_function
を使います
「Ruby の関数名」「C の関数名」「引数の型」「返り値」で指定します
これで OK です
あとは module メソッドとしてコールするだけです
可変引数を取る場合
require 'ffi'
module MyLib
extend FFI::Library
ffi_lib FFI::Library::LIBC
attach_function("my_printf", "printf", [ :string, :varargs ], :int)
end
MyLib.my_printf("%s %d\n", :string, "hello", :int, 100)
:varargs
を使います
型の指定が必要になりますがこれで複数の可変引数を取ることができます
指定可能なタイプの一覧
指定可能なタイプはここに一覧があります
もしくはプラットフォームごとに conf ファイルが用意されているのでそれで確認しても OK です
Pointer
Pointer も使えます
require 'ffi'
module MyLib
extend FFI::Library
ffi_lib FFI::Library::LIBC
attach_function("my_printf", "printf", [ :string, :pointer ], :int)
end
p1 = FFI::MemoryPointer.from_string('hello')
MyLib.my_printf("%p\n", p1)
p2 = FFI::MemoryPointer.new(:int, 5)
MyLib.my_printf("%p\n", p2)
Ruby 側でポインタ変数を扱う場合は FFI::MemoryPointer
を使うと管理が楽になります
最後に
ruby-ffi を試してみました
libxxx 系の Ruby ラッパーを簡単に作ることができるようになるライブラリかなと思います
自分で so ファイルなどを作っている場合はこれを使うことで Ruby からコールすることも可能になります
0 件のコメント:
コメントを投稿