2013-11-15 73 views
4

我有三個頭文件in my project,它們描述對象Rational,ComplexRubyObject。前兩個是模板。所有可以使用在頭文件中定義的拷貝構造函數進行相互轉換 - 除了那些從const RubyObject& s構造RationalComplex的構造函數之外,其定義爲​​。懶惰符號綁定失敗:找不到符號

注:那些定義是必要的。如果他們全部進入標題,您將得到circular dependency

後來,我碰到some unresolved symbol errors與源文件中定義的兩個複製構造函數。我能夠在源文件中包含以下功能

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); 
} 

然後call nm_init_data() from the library entry point in the main source file。這樣做會迫使這些符號正確鏈接。

不幸的是,我最近升級了GCC,錯誤又回來了。事實上,它似乎發生在與GCC 4.6 (e.g., on Travis-CI)略有不同的地方。

但它不是一個特定於版本的問題(正如我以前所想的)。我們在Travis CI's Ubuntu-based system上看到它,它運行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 

「嗯,這很奇怪,」我想。 「Complex64Complex128也被稱爲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()被調用,不會發生錯誤(即,當庫被加載時)。事情發生得很晚,在另一次調用這些麻煩的功能時。

如何一勞永逸解決這個問題,以及其他人喜歡它?

+0

另外值得注意的是,'nm_init_data()'和庫入口點都在'extern「C」{}'塊中聲明。 –

+0

gcc 4。6我在使用它時遇到了很多問題 –

回答

2

您聲稱以下,我懷疑。

那些定義是必要的。如果他們都進入標題,你會得到循環依賴。

在大多數情況下,你可以通過你的代碼中分離到一個額外.HPP文件,該文件與包含在任何地方所需要的模板定義的類定義包括在一起解決這樣的圓形糾纏。

如果你的代碼有一個真正的循環依賴,它不能編譯。通常情況下,如果你的依賴似乎是循環的,你必須仔細觀察,然後進入方法級別並檢查哪些需要編譯這兩種類型。所以它可能是你的類型相互使用,然後在一個.cpp文件中編譯所有(例如通過三個.hpp包含)。 或者只有指向其他類型的指針,然後使用前向聲明來確保所有模板都已解析。 或者第三,你有一些依賴於前向的方法和一些依賴於後向的方法,然後將一種方法放在一個文件中,另一種放在另一個文件中,而你又很好。

此外,您似乎應該使用前瞻性聲明來填充缺失的項目。在函數的定義之後,我會期待類似下面的內容。例如:

template nm::Complex<nm::RubyObject>::Complex(const nm::RubyObject& other); 
+0

你能提供一個鏈接到某種簡單的.hpp文件的這種用法的例子?爲什麼在函數定義之後,前向decl是必要的?我覺得這是一個有用的答案,但我無法理解你在某些地方的意思。例如,「你必須仔細觀察方法級別並檢查哪些方法需要編譯這兩種類型。」還有,「或者第三,你有一些依靠前進的方法,一些依賴於後向的方法,然後將其中一種放在一個文件中,另一種放在另一個文件中,而你又很好。」 –

+0

好的,所以這實際上工作!這是瘋了,因爲我相當肯定我已經嘗試過了。多麼尷尬。感謝您的幫助。 –

0

RationalComplex ...是模板

複製構造...都在頭文件中定義的 - 除了那些構建RationalComplexconst RubyObject& S,其在源文件中定義。

其中存在你的問題。由於RationalComplex是模板,所以全部是它們的方法需要在頭文件中可用。

如果他們不是,那麼你可能有時會根據事物的調用順序和事物鏈接的順序脫離它 - 但更多的時候你會得到奇怪的錯誤未定義的符號,這正是發生在這裏。

只需將Rational(const RubyObject&)Complex(const RubyObject&)的定義移動到相應的標題中,一切都應該正常工作。

+0

就我所知,這不是一種選擇。每個類都有其他類的複製構造函數。包含的順序是'complex.h','rational.h',然後是'rubyobject.h'。我能夠在頭文件中創建除這兩項工作以外的每個副本構造函數,但這些必須位於源文件中或者存在編譯錯誤。我也嘗試了前瞻性聲明。這是一個循環依賴問題,因模板的存在而複雜化。 –

+0

下面是爲什麼一些必須在源文件中聲明的解釋:http://stackoverflow.com/questions/625799/resolve-circular-dependencies-in-c –

相關問題