はじめに
RubyのC拡張でバインディングを作成する場合、ext/fooba
にCファイルを配置する。伝統的なRubyのGemはこのディレクトリにフラットにCファイルを展開するようだ。けれども、サブディレクトリを使いたい場合がある。具体的には Git submoduleなどで、バインディング先のCのライブラリを ext/foobar
に配置してバージョン管理したいような場合だ。
その場合、$INCFLAGS
や $VPATH
を利用するという方法がよく紹介される。
INCFLAGS << " -I$(srcdir)/libFooBar"
VPATH << " $(srcdir)/libFooBar"
しかしこの方法は一見するとrake compile
が成功するのだが、いざテストを実行すると、と symbol lookup error が発生する。そして ldd
をしても特に足りない共有ライブラリなどはない。どうすればいいのだろうか?
どうればいいのか? 一つの方法
インターネット上を探しても回答は多くない。
mysqlバインディングや、opencvバインディングのような有名なGemを参考にしようと見に行っても、1つのディレクトリで構成されている。
それでも英語のStackOverFlowにこの問題に対する回答があった。大域変数 $obj
を指定すればいいそうだ。
たとえば、次のような方法である。
$objs = Dir.glob([".c", "libFooBar/*.c"], base: __dir__)
.map { |f| File.expand_path(f, __dir__) }
.map { |f| f.sub(/\.c$/, ".o") }
とする。ただし、この回答はkojix2がStackOverFlowの回答を参考に書いてみたらうまくいった方法にすぎない。(フィードバックのため3番目に投稿してある)、うまくいかない場合は書き直してほしい。何が問題で、どうすればよかったのかQiitaやブログの記事にしたり、コメントに書き込んで情報をRubyコミュニティにフィードバックしてググラビリティの改善に貢献してほしいです。
ちなみに、これを指定すると、#INCFLAGS
と $VPATH
は特に必要ないようだ。
どうしてそうなるのか仕組みはわからない。
追記
ruby-jp のslackに質問をして、C拡張の作成にサブディレクトリの使用はとくに問題ない(非推奨ではない)との回答をいただきました。Rubyの拡張ライブラリは一つのディレクトリにフラットにファイル展開されていることが多いが、別にそのようにしたほうがいいという決まりはないそうです。
この記事は以上です。