2008-12-18 80 views
29

是否有可能擁有一個C靜態庫API,它在內部使用C++並將其隱藏在庫的用戶之中?使用iPhone中的C/C++靜態庫ObjectiveC Apps

我已經寫了一個可移植的C++庫,我希望靜態鏈接到iPhone應用程序。

我已經使用Max OS X'靜態庫'模板創建了一個Xcode項目,並且使用(extern「C」)複製了源代碼,並編寫了C wapper(用於處理異常)。

我想在另一個可可iPhone應用程序中使用生成的庫(.a文件)。

如果我在庫中的調用ObjectiveC文件和(.cpp)實現類上使用(.mm)擴展,一切都可以正常工作。

但是,當我嘗試將包裝文件更改爲(.c)擴展時,即使所有包裝函數文件都只是C函數,我在鏈接上遇到了未解析的符號。

只是因爲C++在庫中內部使用,這是否意味着外部它仍然必須被視爲一個C++程序。是否還沒有執行這種抽象?

編輯:感謝您的答覆,

我一直在使用的extern「C」,我只是不確定其中需要調用什麼項目配置。即。如果預計的調用將需要知道它是否使用C++或可能是無知的,並認爲它是一個純粹的C庫。

看來我不能,我必須在我的ObjectiveC類上使用(.mm)文件。

+0

你是用extern「C」聲明你的C庫函數嗎? – 2008-12-18 05:32:18

+0

Akusete,你的問題真的不是關於Objective-C ......它是關於C/C++和工具問題。我認爲你的問題在於你沒有得到C++運行時支持,因爲Xcode是你連接C應用程序的東西。如果在Q – 2008-12-18 06:00:00

+0

中沒有關於Obj-C的任何具體內容,請不要使用Obj-C標記我的錯誤,我沒有意識到您已將其移除。 – Akusete 2008-12-18 06:01:58

回答

34

這太難做到這一點的評論,所以我只是要快速演示給你鏈接的問題是什麼,你遇到。當Xcode遇到文件時,它使用基於後綴的構建規則來決定使用哪個編譯器。默認情況下,gcc將文件鏈接到標準C庫,但不與標準C++庫鏈接。歸檔文件(靜態庫)完全沒有鏈接解決方案。它們基本上是需要鏈接的目標文件的存檔文件。由於您的項目中沒有.mm或.cpp文件,因此從不會調用g ++,您的文件也不會鏈接到標準庫。爲了解決這個問題,只需將標準C++庫添加到Xcode項目中的其他鏈接器標誌中,或者只需將它們作爲-l(例如-lstdC++)添加到預定義的其他標誌選項即可。

這裏是一個快速演示:

stw.h:

#ifdef __cplusplus 
extern "C" 
#endif 
void show_the_world(void); 

stw.cpp:

#include <iostream> 
#include "stw.h" 
using namespace std; 

extern "C" void show_the_world() { 
    cout << "Hello, world!\n"; 
} 

構建庫:

$ g++ -c stw.cpp -o stw.cpp -O0 -g 
$ ar rcs stw.a stw.o 

使用庫來自C應用程序:

myapp.c:

#include "stw.h" 

int main() { 
    show_the_world(); 
    return 0; 
} 

構建C應用程序:

$ gcc -o myapp myapp.c stw.a -lstdc++ -g -O0 
$ ./myapp 
Hello, world! 
$ 

如果您嘗試沒有-lstdc編譯++,你會得到所有未解決的問題,因爲C編譯器已經完全沒有它應該鏈接到C++運行時(它爲什麼會這樣,對!!!?),所以你必須手動添加它。你擁有的另一個選擇是更改項目的構建規則......而不是讓Xcode使用gcc來構建.c和.m文件,告訴它使用g ++,並且問題將得到解決。

2

您應該聲明您想要顯示的功能extern "C"。它們的簽名需要是C兼容的,但內容不會(例如,您可以訪問C++對象,但不能直接傳遞它們;指針也可以)。符號將在任何C兼容環境中可見。

編輯:並將其編譯爲C++源文件,C沒有語言鏈接的概念。還有一些其他的語言鏈接問題(例如,所有名稱相同的extern "C"函數都是相同的函數,無論名稱空間如何)。編輯2:在頭文件中,您可以檢查宏__cplusplus,並分別使用它設置C++和其他語言(因爲C++將需要extern "C"聲明,其他語言可能會抱怨它們)。

+0

謝謝,'將它編譯爲C++源文件'意味着我仍然需要一個(.mm)Objective C文件才能正確使用它? 'C沒有語言連接的概念'我想這意味着如果我有一個庫內的任何地方的C++,整個事情必須被編譯爲C++。 – Akusete 2008-12-18 05:49:25

1

基本上,當您使用C++編譯器編譯C函數時,它會破壞函數名稱並使用C++ ABI。

當您使用* .cpp或* .mm擴展名時,您正在使用C++編譯器。

你想要做的就是強制編譯器生成具有un-mangles名稱和使用C ABI的C函數。 C編譯器

  • 編譯:

    您可以通過做到這一點。

  • 編譯的C++編譯器,但請確保您前綴與外部的「C」函數聲明

最喜歡的方式來建立的頭文件,使同一個文件可以從兩個C和包括C++源文件是:

#ifndef HEADER_GUARD_1_H 
#define HEADER_GUARD_1_H 

#ifdef __cplusplus 
extern "C" { 
#endif 

// Declare C function interface here. 
int myFunc(int x,char*); 

#ifdef __cplusplus 
} 
#endif 

#endif 
1

謝謝你,討論這麼好。

我所做的是:

1)我創建了一個靜態庫使用cocaotouch靜態庫選項。在那我有c/C++/obj-c所有混合。但是,我的出口只是obj-c類。 事實上,我使用objc到C到C++。

2)然後我在X代碼proj中創建iphone應用程序。 我添加了其他鏈接標誌我的lib名稱(-lxyz)//我的lib名稱是libxyz.a 我添加了lib搜索路徑,標題搜索路徑

3)然後我編譯。我有錯誤。 說oeprator新,找不到運算符刪除。

3)然後分開我的appdelegate,視圖控制器,我添加 虛擬cpp(.h,.cpp)... atestdummy.h atestdummy.cpp

4)然後我又建...

這就是它的工作。

所以 - 我無論他們早些時候給我的建議是什麼。 的基本原因,除非你的應用程序看到一個.CPP文件.CPP代碼文件, 鏈接將不會使用g ++。

謝謝大家。 我已閱讀上述內容並解決了我的問題。

你們很好分享。