[英]Lazy symbol binding failed: symbol not found
我的項目中有三個頭文件,用於描述Rational
, Complex
和RubyObject
對象。 前兩個是模板。 所有都可以使用復制構造const RubyObject&
復制構造函數在頭文件中定義 - 除了那些從const RubyObject&
構造Rational
和Complex
文件 ,它們是在源文件中定義的。
注意:這些定義是必要的。 如果它們都進入標題,則會獲得循環依賴 。
前段時間,我遇到了源文件中定義的兩個復制構造函數的一些未解決的符號錯誤 。 我能夠在源文件中包含以下函數
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上) 。
但它不是特定於版本的問題(正如我之前所想的那樣)。 我們在Travis CI的基於Ubuntu的系統上看到它,它運行GCC 4.6。 但我們不會在具有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
我不確定為什么有兩個定義的條目從屬於未定義的符號,但我也不知道我喜歡編譯器。
它看起來像復制構造函數是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));
}
需要注意的是,現在我得到了完全相同的錯誤,但對於Complex對象卻是如此。 哎呀!
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()
時(即加載庫時nm_init_data()
不會發生錯誤。 它發生在很久以后,在另一次調用這些麻煩的功能時。
我如何一勞永逸地解決這個問題,以及其他類似問題?
您聲稱以下內容,我懷疑。
那些定義是必要的。 如果它們都進入標題,則會獲得循環依賴。
在大多數情況下,您可以通過將代碼分成另一個.hpp文件來解決這種循環糾纏,該文件與包含所需模板定義的類定義一起包含在內。
如果您的代碼具有真正的循環依賴,則無法編譯。 通常,如果您的依賴項似乎是循環的,則必須仔細觀察並進入方法級別並檢查它們中的哪一個需要兩種類型進行編譯。
所以可能是你的類型互相使用,然后在一個.cpp文件中編譯所有文件(例如通過三個.hpp包含)。 或者只有指向另一種類型的指針,然后使用前向聲明來確保所有模板都已解析。 或者第三,你有一些依賴向前的方法和一些向后依賴的方法,然后將一種方法放在一個文件中,其他方式放在另一個文件中,你再好了。
此外,您似乎應該為缺失的項目使用前向聲明。 在函數定義之后我會期待類似下面的內容。 例如:
template nm::Complex<nm::RubyObject>::Complex(const nm::RubyObject& other);
Rational
,Complex
......是模板復制構造函數...在頭文件中定義 - 除了那些從
const RubyObject&
構造Rational
和Complex
的東西, 它們是在源文件中定義的。
這就是你的問題所在。 由於Rational
和Complex
是模板,因此需要在頭文件中提供所有方法。
如果他們不是,那么你有時可能會逃脫它取決於調用事物的順序和事物的連接順序 - 但更多時候你會得到關於未定義符號的奇怪錯誤,正是這里發生的事情。
只需將Rational(const RubyObject&)
和Complex(const RubyObject&)
的定義移動到相應的頭文件中,一切都應該正常工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.