遅延シンボルのバインドに失敗しました:シンボルが見つかりません
-
20-12-2019 - |
質問
私は3つのヘッダーファイルを持っています 私のプロジェクトでは オブジェクトを記述する Rational
, Complex
, 、および RubyObject
.最初の2つはテンプレートです。すべては、ヘッダーファイルで定義されているコピーコンストラクタを使用して相互変換することができます。 Rational
と Complex
から const RubyObject&
定義されているs、 ソースファイル内で.
メモ: これらの定義は必然的にそこにあります。もし彼らが すべて ヘッダーに移動すると、次のようになります 循環依存性.
しばらく前に、私はに遭遇しました いくつかの未解決のシンボルエラー ソースファイルで定義されている二つのコピーコンストラクタを使用します。ソースファイルに次の関数を含めることができました
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をアップグレードし、エラーが戻ってきました。実際、GCC4.6とは少し異なる場所で発生するようです (例えば、Travis-CIについて).
しかし、それはバージョン固有の問題ではありません(私が前に考えていたように)。私たちはそれを見る Travis CIのUbuntuベースのシステム, これはGCC4.6を実行します。しかし、GCC4.8.1または4.8.2のUbuntuマシンでは表示されません。しかし、私たちは do 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
出力。"だから私は追加してみました 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
ヒント: 言及する価値があることの1つは、次の場合にエラーが発生しないことです nm_init_data()
呼び出されます(つまり、ライブラリがロードされたとき)。それはずっと後に、これらの面倒な関数への別の呼び出し中に起こります。
どのように私は一度、すべてのためにこの問題を修正し、他の人はそれを好きですか?
解決
あなたは私が疑う次の主張を主張します。
それらの定義は必需品によってあります。それらがすべてヘッダーに入るならば、あなたは円形の依存関係を得ます。
ほとんどの場合、コードを追加の.hppファイルに分けることで、コードを追加することで、このような循環的な絡み合いを解くことができます。これは、必要な場所のどこにでもテンプレート定義を含むクラス定義と一緒に含まれています。
コードが実際の循環依存関係を持っている場合は、コンパイルできませんでした。通常、依存関係が円形になっているように見える場合は、近くに見えてメソッドレベルに移動し、どちらが両方のタイプをコンパイルする必要があるかを確認します。
だからあなたの種類は互いに使用してから1つの.cppファイル(例えば、3つの.hppを介して含む)ですべてコンパイルされる可能性があります。 あるいは、別の型へのポインタはポインタだけであり、次にすべてのテンプレートが解決されていることを確認するために宣言を宣言します。 または3番目に、前後に依存するいくつかの方法があり、1つのファイルに1種類のファイルを入れて、もう1つのファイルに入れて、もう一度大丈夫です。
さらに、欠けているアイテムの前方宣言を使用する必要があるようです。関数の定義後に次のようなものが期待されます。 e.g。:
template nm::Complex<nm::RubyObject>::Complex(const nm::RubyObject& other);
. 他のヒント
Rational
,Complex
...テンプレートですコンストラクタをコピーします。..ヘッダーファイルで定義されている—構築するものを除いて
Rational
とComplex
からconst RubyObject&
s, これはソースファイルで定義されています。
そして、そこにあなたの問題があります。以来 Rational
と Complex
テンプレートです, すべて それらのメソッドはヘッダーファイルで利用可能である必要があります。
そうでない場合は、呼び出される順序とリンクされる順序に応じて、それを回避できることがありますが、多くの場合、定義されていないシンボルについて奇妙なエラーが発生します。これはまさにここで起こっていることです。
の定義を移動するだけです Rational(const RubyObject&)
と Complex(const RubyObject&)
それぞれのヘッダーに入れて、すべてがうまくいくはずです。