プロジェクトには、オブジェクトRational
、Complex
、およびを記述する3 つのヘッダー ファイルがありRubyObject
ます。最初の 2 つはテンプレートです。すべては、ヘッダー ファイルで定義されているコピー コンストラクターを使用して相互Rational
変換Complex
できます。const RubyObject&
注:これらの定義は必然的に存在します。それらがすべてヘッダーに入ると、循環依存関係が発生します。
少し前に、ソース ファイルで定義された 2 つのコピー コンストラクターで未解決のシンボル エラーが発生しました。ソースファイルに次の関数を含めることができました
void nm_init_data() {
nm::RubyObject obj(INT2FIX(1));
nm::Rational32 x(obj);
nm::Rational64 y(obj);
nm::Rational128 z(obj);
volatile nm::Complex64 a(obj);
volatile nm::Complex128 b(obj);
}
次に、メイン ソース ファイルのライブラリ エントリ ポイントから呼び出しnm_init_data()
ます。そうすることで、これらのシンボルが適切にリンクされました。
残念ながら、最近 GCC をアップグレードしたところ、エラーが再発しました。実際、GCC 4.6 では少し異なる場所(Travis-CI など) で発生しているようです。
しかし、これはバージョン固有の問題ではありません (前に考えていたように)。GCC 4.6 を実行するTravis CI の Ubuntu ベースのシステムで確認できます。しかし、GCC 4.8.1 または 4.8.2 を搭載した Ubuntu マシンでは表示されません。しかし、4.8.2 を搭載した Mac OS X マシンでは見られますが、4.7.2 を搭載した同じマシンではありません。最適化をオフにしても効果がないようです。
ライブラリで実行するnm
と、シンボルは間違いなく未定義です。
$ nm tmp/x86_64-darwin13.0.0/nmatrix/2.0.0/nmatrix.bundle |grep RationalIsEC1ERKNS
U __ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
00000000004ca460 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache
00000000004ca458 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache_0
未定義のシンボルに従属する定義済みのエントリが 2 つある理由はわかりませんが、コンパイラについてもあまり知りません。
Rational
また、コピー コンストラクターは、テンプレートの各バージョンの未定義のシンボルのようです。
__ZN2nm8RationalIiEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIxEC1ERKNS_10RubyObjectE
「うーん、それは奇妙だ」と私は思った。"Complex64
とComplex128
もそのnm_init_data
関数で呼び出されますが、どちらも適切に解決され、nm -u
出力には表示されません。" そこで、Rational のコピー構築の前にも追加volatile
してみました。最適化してほしくないものをコンパイラーが最適化していたのかもしれないと考えました。しかし、悲しいことに、それも解決しませんでした。これは、注意して行いました:
void nm_init_data() {
volatile VALUE t = INT2FIX(1);
volatile nm::RubyObject obj(t);
volatile nm::Rational32 x(const_cast<nm::RubyObject&>(obj));
volatile nm::Rational64 y(const_cast<nm::RubyObject&>(obj));
volatile nm::Rational128 z(const_cast<nm::RubyObject&>(obj));
volatile nm::Complex64 a(const_cast<nm::RubyObject&>(obj));
volatile nm::Complex128 b(const_cast<nm::RubyObject&>(obj));
}
注意点は、まったく同じエラーが発生することですが、代わりに複合オブジェクトの場合です。ああ!
dyld: lazy symbol binding failed: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
Expected in: flat namespace
dyld: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
Expected in: flat namespace
これは完全にばかげています。関数と同じソース ファイル内のこれらの関数の両方の定義を次に示しnm_init_data()
ます。
namespace nm {
template <typename Type>
Complex<Type>::Complex(const RubyObject& other) {
// do some things
}
template <typename Type>
Rational<Type>::Rational(const RubyObject& other) {
// do some other things
}
} // end of namespace nm
ヒント:nm_init_data()
言及する価値のあることの 1 つは、 gets が呼び出されたとき (つまり、ライブラリが読み込まれたとき) にエラーが発生しないことです。それはずっと後になって、これらの面倒な関数への別の呼び出し中に発生します。
この問題を一度だけ修正するにはどうすればよいですか?他の人も気に入っていますか?