Ruby / DLはどのように使用しますか?これは正解?
質問
RSPEC(Rubyフレーバー付きBDD)とWindowsアプリケーション間のインターフェースを作成しようとしています。アプリケーション自体はあいまいな言語で記述されていますが、アクセスを提供するC APIがあります。私はRuby / DLを使いましたが、DLLメソッドの最も基本的な呼び出しでさえ動作するのに苦労しています。 gt4r.rbと呼ばれるファイルには、これまでのところ私が持っているものがあります:
require 'dl/import'
module Gt4r
extend DL::Importable
dlload 'c:\\gtdev\\r321\\bin\\gtvapi'
# GTD initialization/termination functions
extern 'int GTD_init(char *[], char *, char *)'
extern 'int GTD_initialize(char *, char *, char *)'
extern 'int GTD_done(void)'
extern 'int GTD_get_error_message(int, char **)'
end
これまでの私の読書は、これが私が進むために必要なすべてであることを示唆しているので、RSPECの例を書きました:
require 'gt4r'
@@test_environment = "INCLUDE=C:\\graphtalk\\env\\aiadev\\config\\aiadev.ini"
@@normal_user = "BMCHARGUE"
describe Gt4r do
it 'initializes' do
rv = Gt4r.gTD_initialize @@normal_user, @@normal_user, @@test_environment
rv.should == 0
end
end
そして実行時...
C:\code\GraphTalk>spec -fs -rgt4r gt4r_spec.rb
Gt4r
- initializes (FAILED - 1)
1)
'Gt4r initializes' FAILED
expected: 0,
got: 13 (using ==)
./gt4r_spec.rb:9:
Finished in 0.031 seconds
1 example, 1 failure
戻り値(13)は実際の戻りコードであり、エラーを意味しますが、RSPECにgTD_get_error_message呼び出しを追加しようとすると、パラメーターを機能させることができません。
私は正しい方向に向かっていますか、そして私が次に試すことができるものを誰かが指すことができますか?
ありがとう、 ブレット
この質問のフォローアップで、ターゲットライブラリからエラーメッセージを取得しようとすると失敗する部分を示します。
require 'gt4r'
@@test_environment = "INCLUDE=C:\\graphtalk\\env\\aiadev\\config\\aiadev.ini"
@@normal_user = "BMCHARGUE"
describe Gt4r do
it 'initializes' do
rv = Gt4r.gTD_initialize @@normal_user, @@normal_user, @@test_environment
Gt4r.gTD_get_error_message rv, @msg
@msg.should == ""
rv.should == 0
end
end
エラーメッセージが@msgに返されることを期待していますが、実行すると次のメッセージが表示されます。
Gt4r
(eval):5: [BUG] Segmentation fault
ruby 1.8.6 (2008-08-11) [i386-mswin32]
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
そして、代わりにシンボル(:msg)を使用する場合:
C:\code\GraphTalk\gt4r_dl>spec -fs -rgt4r gt4r_spec.rb
Gt4r
- initializes (ERROR - 1)
1)
NoMethodError in 'Gt4r initializes'
undefined method `to_ptr' for :msg:Symbol
(eval):5:in `call'
(eval):5:in `gTD_get_error_message'
./gt4r_spec.rb:9:
Finished in 0.046 seconds
1 example, 1 failure
明らかに、ルビーとCの間でパラメーターを渡すことについて何かが欠けていますが、何ですか?
解決
一般的なコンセンサスでは、DLを可能な限り避けたいと考えています。 (英語の)ドキュメントは非常に大雑把であり、インターフェイスは些細な例以外には使用するのが困難です。
RubyのネイティブCインターフェイスは、プログラミングがはるかに簡単です。または、DLに似たニッチを埋めるFFIを使用することもできます。FFIは、元々rubiniusプロジェクトに由来し、最近「通常」に移植されました。ルビー。より良いインターフェースを持ち、使用するのがずっと簡単です:
http://blog.headius.com/ 2008/10 / ffi-for-ruby-now-available.html
他のヒント
戻り値(13)は実際の 戻りコード、エラーを意味しますが、 私が追加しようとすると gTD_get_error_messageの呼び出し RSPEC、パラメータを取得できません 仕事。
機能したコードの代わりにエラーを投稿するのに役立つかもしれません:)
基本的に、(int、char **)のようにポインタを扱う必要があると、物事はいものになります。
他のCにはエラーメッセージを書き込む場所がないため、msgに書き込むデータポインタを割り当てる必要があります。 DL.malloを使用します。