2011-09-13 61 views
4

我有一個混合的C/C++庫。爲什麼我不能使用gcc鏈接具有C接口的混合C/C++靜態庫?

在外部,它使用extern C提供一個C接口。內部有模板和類。使用「ar」創建庫沒有任何問題。該文件被稱爲libo-client.a。

然而,用gcc鏈接.a文件(不是G ++)的時候,我有很多的錯誤,看起來像這樣:

libo-client.a(mysocket.o):(.rodata._ZTV7mStream[vtable for mStream]+0x10): undefined reference to `__cxa_pure_virtual' 
... 
mysocket.cpp:(.text+0x15ad): undefined reference to `operator new[](unsigned long)' 
mysocket.cpp:(.text+0x15c1): undefined reference to `operator delete(void*)' 
mysocket.cpp:(.text+0x167a): undefined reference to `__cxa_allocate_exception' 
mysocket.cpp:(.text+0x16a6): undefined reference to `__cxa_throw' 
... 

我的編譯/鏈接行看起來是這樣的:

gcc $(CFLAGS) $(INCLUDES) test2.c libo-client.a -o test2 

test2是我的測試工具。

當我使用g ++時,不會發生此問題。但是,我將把這個庫連接到用gcc編譯的C項目中。我如何解決這個問題?這是什麼原因?

編輯:

即使我沒有使用C++標準庫這顯然需要一些東西像運營商新/刪除等,並有例外內部。

我把這個東西與Xen hypervisor連接起來,所以我不確定我有什麼選擇,但要完全重寫這個東西,或者試着用G ++編譯Xen。

+1

使它成爲一個動態庫也可能有所幫助。你有沒有看過那個? –

+0

謝謝克里斯。這實際上是一個動態共享對象。 – Matt

回答

9

解決問題的最簡單方法就是鏈接與g++;這會得到正確的庫。

問題是C++有很多要求,C沒有,並且在調用main()以確保正確初始化之前做了更多工作。

如果你堅持用C編譯器進行鏈接,至少你必須在鏈接命令中包含C++支持庫。

+0

+1 - 在C項目中包含一個C++庫不僅僅是將目標文件扔在它上面。 –

+0

切換到g ++也爲我解決了這個問題,但有沒有更便攜的方法?我將如何爲非Linux系統編寫Makefile? –

+0

@EdwardFalk:比使用C++編譯器連接(部分)C++程序更方便嗎?沒有;這將是最便捷的方式。另一種方法是計算C++編譯器如何調用鏈接器來完成C++的工作,然後解決如何將C編譯器調整爲以與C++編譯器爲您自動調用鏈接器相同的方式。如果你想嘗試,成爲我的客人,但這將是根本難以做到,並且大大減少便攜。 –

1

歸檔文件仍然只是一堆目標文件(.o),因此,將它們鏈接到可執行文件或共享庫時,仍需要鏈接g++才能將符號解析到C++運行庫(例如,如果您看到在你的錯誤信息中)。

爲了讓C函數具有C關聯,它應該足以將它們包裝在extern "C"塊中。事情可能會變得更復雜,例如Windows,它有大量的連接宏(STDCALL,WINAPI等),擴展到其他東西(一些編譯器特定),如__stdcall,__declspec(export)等。

1

您看到的錯誤似乎是由於與標準C++庫缺少連接而出現的,該標準C++庫具有操作符new的符號定義,操作符delete等。嘗試鏈接stdc++gcc $(CFLAGS) $(INCLUDES) test2.c libo-client.a -o test2 -lstdc++。更好的選擇是Jonathan Leffler建議使用g++而不是gcc

2

您的C++庫在內部仍然是C++庫,這意味着它包含對來自C++標準庫的各種內務管理函數的外部引用。爲了解決這些鏈接,你必須鏈接你最終的C++標準庫的可執行文件。 gcc不會爲你自動完成。要麼明確地將C++標準庫提供給gcc,要麼使用g++編譯器。

0

用C++編寫的東西可以從C中使用,不需要額外C++需要的是很難。甚至可能依賴於編譯器。您的庫需要C++運行庫,並且在調用main()之前需要特別支持來初始化C++運行庫。當你鏈接到C文件時,即使它是main()和你的庫之外的其他所有東西,你的chimaera仍然是一個C++程序。