3

Linux/Unix システムで外部ライブラリの関数を動的に呼び出そうとしています。

ライブラリである程度成功しdlましたが、プリミティブ C 型が使用され、引数が値渡しされた場合のみです。

require 'dl/import'
module LibM
  extend DL::Importer
  dlload 'libm.so'
  extern 'double sin(double)'
end

puts LibM.sin(3.14159265358979323846 / 2)    # 1.0

しかし、C 構造体のようなより複雑な型を使用して、または引数が呼び出しの結果が格納されるポインターである場合、関数をどのようにインターフェースすることができますか?

module LibX11
  extend DL::Importer
  dlload 'libX11.so.6'
  extern 'Display *XkbOpenDisplay (char *display_name, int *event_rtrn, int *error_rtrn, int *major_in_out, int *minor_in_out, int *reason_rtrn)'
end

Displayは大きな構造体であり、event_rtrnいくつかの結果などが格納されています。

私はDL::CStructBuilderを見てきましたが、それは仕事をすることができるように見えますが、ドキュメントは非常に簡潔で、実際の例が見つからないため、適切に使用する方法がわかりません。

ターゲット マシンに追加の gem をインストールすることは禁止されているため、(可能であれば) 標準の Ruby 1.9 モジュールを使用する必要があります。

4

1 に答える 1

2

私はこの時期に C ライブラリとのインターフェースに直面しており ( libgtop のラッパーを書いています)、 ffi使用することにしました。困ったときに手を差し伸べてくれる人がいっぱい。

そこで、ffi を使用するソリューションを提案します。

require 'ffi'

module LibX11
  extend FFI::Library
  ffi_lib 'libX11.so.6'

  # Display *XkbOpenDisplay (char *display_name, int *event_rtrn, int *error_rtrn, int *major_in_out, int *minor_in_out, int *reason_rtrn)
  attach_function :XkbOpenDisplay, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :pointer

end

次に、ここDisplayに書かれているように、構造体のレイアウトを記述する必要があります。

class Display < FFI::Struct
  layout  :value,       :double,
          :other_value, :char,
          ...
end

そして、次のようにします。

p1 = FFI::MemoryPointer.new(:char)
p2 = FFI::MemoryPointer.new(:int)
p3 = FFI::MemoryPointer.new(:int)
p4 = FFI::MemoryPointer.new(:int)
p5 = FFI::MemoryPointer.new(:int)
p6 = FFI::MemoryPointer.new(:int)

# write to pointer if needed, otherwise it is a null pointer
# p1.write_char('a')
# p2.write_int(1)
# ...

struct_pointer = LibX11.XkbOpenDisplay(p1, p2, p3, p4, p5, p6)

# read the struct
struct = Display.new(display_struct_pointer)
p Hash[ s.members.map { |m| [ m, s[m] ] } ]

私はコードをテストしていませんが、おおよそ正しいはずです。そうでない場合は、今私にさせてください。


ruby 2.0 の DL について調査した結果、非推奨であり、fiddle に置き換えられていることがわかりました。FFI を使用できない場合は、DL ではなく使用することを検討してください。Fiddle は ruby​​ 1.9.3 と 1.9.2 でも利用できるようです

于 2013-03-29T10:03:13.527 に答える