2018年12月27日木曜日

Ruby で C言語を扱う方法

概要

RubyInline を使います
他にも Rice や FFI といったライブラリもありますが今回は RubyInline を使います

環境

  • macOS 10.14.1
  • clang Apple LLVM version 10.0.0 (clang-1000.11.45.5)
  • Ruby 2.5.1p57

インストール

  • bundle init
  • vim Gemfile
gem "RubyInline"
  • bundle install --path vendor

gem の名前に注意しましょう
inline ではありません

Hello World

とりあえず printf でメッセージを表示するサンプルを書いてみましょう

  • vim test.rb
require 'inline'

class Test
  inline(:C) do |builder|
    builder.include '<stdio.h>'
    builder.c '
      void say(char *msg) {
        printf("%s\n", msg);
      }
    '         
  end
end

t = Test.new
t.say "hello"
  • bundle exec ruby test.rb

で「hello」と表示されます

builder を使ってヘッダファイルの読み込み (.include) や C言語の関数を登録 (.c) します
Ruby から参照する場合はクラスを作成して、そのクラスのメソッドとして呼び出します
Ruby の文字列は char のポインタで普通に渡せました

返り値がある場合

require 'inline'

class Test
  inline(:C) do |builder|
    builder.include '<stdio.h>'
    builder.c '
      int sum(int a, int b) {
        return a + b;
      }
    '         
  end
end

t = Test.new
ret = t.sum 1, 2
puts ret.class
puts ret

int は Ruby 側では Integer として扱われました

複数の include

require 'inline'

class Test
  inline(:C) do |builder|
    builder.include '<stdio.h>'
    builder.include '<math.h>'
    builder.c '
      double my_pow(double a, double b) {
        printf("%lf\n", a);
        printf("%lf\n", b);
        return pow(a, b);
      }
    '         
  end
end

t = Test.new
ret = t.my_pow 10, 2
puts ret.class
puts ret

単純に 2 度 .include をコールすれば OK です
ちなみに C言語の double は Ruby では Float でした

最後に

Ruby から C 言語をコールしてみました
もし C の共有ライブラリ (.so 形式) などでしか作られていない場合は使えるかなと思います
あとは RubyInline を使う理由に C で処理したほうが早いという理由もありあした
C 以外に C++ も使えるのでたしかに速度重視の場合は考慮してもいいかもしれません

0 件のコメント:

コメントを投稿