RubyとC。パート2。

最後の部分では、RubyInlineライブラリを調べました。これにより、CコードをRubyメソッドに直接挿入できます。 いくつかの重要なメソッドを高速化する必要がある場合に使用すると非常に便利です。 しかし、Cライブラリを実装してRubyで使用する必要がある場合、または既存のライブラリのラッパーを作成する必要がある場合は、C APIが拡張機能の作成を支援します。


Ruby C APIは、Cを使用してRubyコードを記述する手段を提供します。少し奇妙に聞こえますが、例を見てみましょう。
Rubyコード:
    クラステスト
         defテスト
             #メソッドの実装
        終わり
    終わり

同様のCコード:
     VALUE test_method(VALUE self){
         //メソッドの実装
     }

     Init_test(){
         VALUE cTest = rb_define_class( "Test"、rb_cObject);  //クラスTestを作成します
         rb_define_method( "test"、cTest、test_method、0);  // Testクラスにテストメソッドを作成します
     }


簡単な例は、1つのメソッドでクラスを作成することです。 次に、Cコードの詳細を検討します。
rb_define_class関数を使用して、Objectクラスの子孫であるTestクラスを作成します。 次に、rb_define_method関数を使用して、Testクラスのテストメソッドを作成し、このメソッドの実装としてtest_method関数を渡します。 最後のパラメーターは、メソッドに引数がないことを意味します。

この例では、すべての場所でVALUEデータ型を使用しています。 Cの文字列、数値、クラス、モジュールなどのRubyオブジェクトは、VALUE型です。
Ruby C APIは、Rubyデータ型をCに、またはその逆に変換するためのマクロと関数のセットを提供します。
以下にそれらのいくつかを示します(RubyからCへ)。
     int NUM2INT(VALUE)
     int FIX2INT(値)
    ダブルNUM2DBL(VALUE)
     char * StringValuePtr(VALUE) 
マクロSTR2CSTRもありますが、使用しない方が良いでしょう。ドキュメントから引用してください:
because STR2CSTR() has a risk of a dangling pointer problem in the to_str() impliclit conversion.

CからRubyへ:
        VALUE INT2NUM(整数)
	 VALUE INT2FIX(int)
	 VALUE rb_str_new2(char *)
	 VALUE rb_float_new(ダブル) 	


モジュールはクラスと同様に作成されます:
VALUE rb_define_module(const char *name)

次にメソッドについて説明します。
メソッドを作成するための関数がいくつかあります。 それらのいくつかを次に示します。
 void rb_define_method(VALUE klass、const char * name、VALUE(* func)()、int argc)
 void rb_define_private_method(VALUE klass、const char * name、VALUE(* func)()、int argc)
引数は、クラス、メソッドの名前、メソッドの実装を含む関数への参照、および引数の数です。
メソッドを実装する関数は、次の形式である必要があります。
VALUE test(VALUE self, VALUE arg1, VALUE arg2, ...)
self、これはオブジェクトへのポインタであり、メソッドに引数がない場合でも常に存在します。
argc引数の値に応じて、署名は異なる場合があります。 負のargc値は、可変数の引数を持つメソッドを定義するために使用されます。
argcが-1:の場合
VALUE test(int argc, VALUE *argv, VALUE self)
argcは引数の数、* argvは引数の配列です。
argcが-1:の場合
VALUE test(VALUE args, VALUE self)
args-引数を持つRuby配列。

Init_test()関数は、拡張機能が初期化されたときに呼び出され、クラスとモジュールを作成するだけです。

ここで、Ruby C APIの基本機能を確認した後、独自の拡張機能を作成してみましょう。 私は人為的な例を思い付かず、既存のCライブラリのラッパーを使用した拡張機能の作成を説明することにしました。 長い検索の後(ほとんどすべての一般的なライブラリーには既にラッパーがあります)、QRコードを認識するためのライブラリーであるlibdecodeqrを選択しました。 Cでの作業の簡単な例は、 qrtest.cにあります

拡張機能は非常にシンプルで、静的デコードメソッドを持つQRDecoderクラスです。
decodeメソッドは引数としてファイルの名前とQRコードを受け取り、そこでエンコードされた文字列を返します。
使用例(Cのコードと比較してください:)):
     「decodeqr」が必要
     QRDecoder.decode "test.png"を置きます

タスクは明確です。始めましょう。
必要なもの:
1.拡張機能を構築するためのruby1.8-devパッケージ。
sudo apt-get install ruby1.8-dev
2. libdecodeqrライブラリ。
sudo apt-get install libdecodeqr libdecodeqr-dev

拡張機能を初期化することから始めましょう。
     Init_decodeqr(){
         VALUE cQRDecoder = rb_define_class( "QRDecoder"、rb_cObject);
         rb_define_singleton_method(cQRDecoder、「デコード」、デコード、1);
     }

簡単です。QRDecoderクラスと静的デコードメソッドを作成します。
デコード機能の実装:
     VALUEデコード(VALUE self、VALUEファイル){
         char * file_name = StringValuePtr(ファイル);  // Ruby文字列をCに変換します
         // libdecodeqrライブラリを操作します。詳細はCの例に記載されています
         QrDecoderHandle qr = qr_decoder_open();
         IplImage * src = cvLoadImage(file_name、0);
         qr_decoder_decode_image(qr、src、DEFAULT_ADAPTIVE_TH_SIZE、DEFAULT_ADAPTIVE_TH_DELTA);
         QrCodeHeader * qrh = calloc(sizeof(QrCodeHeader)、1);
         qr_decoder_get_header(qr、qrh);
         char * buf = calloc(qrh-> byte_size + 1、1);
         qr_decoder_get_body(qr、(unsigned char *)buf、qrh-> byte_size + 1);
         qr_decoder_close(qr);
         return rb_str_new2(buf);  // Ruby文字列を返します
     }

拡張機能の準備ができました! コード全体はこちらdecodqr.cにあります
次に、拡張機能を組み立てる必要があります。 これを行うには、標準のmkmf Rubyライブラリを使用して、Makeファイルを生成します。
例、extconf.rbファイル:
     「mkmf」が必要

     have_library( "cv")および#ライブラリ "cv"がある場合
     have_library( "decodeqr")および#およびライブラリ "decodeqr"
     have_library( "highgui")および#および "highgui"
     find_header( "highgui.h"、 "/ usr / include / opencv /")その後#そしてヘッダーファイル "highgui.h"を見つけました
         create_makefile( "decodeqr")#次にMakeファイルを作成
    他に
         「おっと...」#それ以外の場合は作成しません
    終わり

そして、その実行の結果:
 $ ruby​​ extconf.rb
     -lcvでmain()を確認します...はい
     -ldecodeqrでmain()をチェックします...はい
     -lhighguiでmain()をチェックします...はい
     / usr / include / opencv / ...でhighgui.hをチェック
    メイクファイルの作成

そして今、標準のもの:
    作る
     sudo make install

拡張機能を使用する準備が整いました。

したがって、Cコードがある場合、またはCライブラリを使用する場合、またはRubyを高速化する場合は、拡張機能を作成してRubyプログラムで使用するだけです。

この記事で触れなかったもの:
1.文字列と配列を操作する
2.ガベージコレクター
3. C構造体のラッパーの作成

これについては、以下のリンクで読むことができます。
1. Rubyディストリビューションに付属のREADME.EXTファイル。
2.有名なつるはしで Rubyを拡張する責任者
3.この素晴らしいブログmaxidoors.ru

興味のある方は、libdecodeqrライブラリ: trac.koka-in.org/libdecodeqr
ご注意 すべてが日本語で書かれています:)ドキュメントはヘッダーファイルで直接表示できます。
trac.koka-in.org/libdecodeqr/browser/tags/release-0.9.3/src/libdecodeqr/decodeqr.h

次のパートでは、C / C ++アプリケーションでスクリプト言語としてRubyを使用することについて説明します。

Source: https://habr.com/ru/post/J49202/


All Articles