2011-01-30 47 views
3

我絕對需要你的幫助。dllimport/dllexport和靜態庫編譯在visual C++

我試圖靜態編譯visual C++ 2008編譯器的窗口上的poppler庫(特別是qt4)。爲了完成這個任務,我需要靜態編譯一些其他庫作爲poppler的依賴項。當我終於產生poppler的靜態版本我建設我的應用程序時,得到了一個鏈接錯誤:

error LNK2019: unresolved external symbol "__declspec(dllimport)... 

我已經添加了新的包含路徑和鏈接poppler的-qt4.lib但我得到的錯誤反正。 尋找解決的辦法我在計算器

How to link a static library in Visual C++ 2008?

白衣這個信息,我枕着庫的包含文件發現這裏討論(如zlib的poppler的相關性,的libpng,開羅......)和我在各種情況下發現它們沒有預處理器指令來指定lib的靜態版本。 實例靜態指令(openjpeg.h):

#if defined(OPJ_STATIC) || !(defined(_WIN32) || defined(WIN32) || defined(__WIN32__)) 
# define OPJ_API 
# define OPJ_CALLCONV 
#else 
# define OPJ_CALLCONV __stdcall 
# ifdef OPJ_EXPORTS 
# define OPJ_API __declspec(dllexport) 
# else 
# define OPJ_API __declspec(dllimport) 
# endif /* OPJ_EXPORTS */ 
#endif /* !OPJ_STATIC || !WIN32 */ 

例無靜態指令(從JPEG LIB jconfig.h):

#if defined(_WIN32) 
    #if defined(libjpeg_EXPORTS) 
     #define JPEG_EXPORT __declspec(dllexport) 
    #else 
     #define JPEG_EXPORT __declspec(dllimport) 
    #endif 
#else 
    #define JPEG_EXPORT 
#endif 

我的問題是:是不足以改變的屬性項目從動態變爲靜態,所以我必須更改這個頭文件嗎?如果這是真的,我可以在哪裏定義這個新的指令來區別靜態或動態編譯?

在此先感謝。

回答

2

如果您將項目屬性從動態鏈接更改爲靜態鏈接(如openjpeg.h中所指定的那樣),您必須指定可使用靜態鏈接的預處理器......除了將屬性從動態更改爲靜態之外,預處理OPJ_STATIC ...

例如:

#if defined(_WIN32) 
    #if defined(OPJ_STATIC) 
     # define OPJ_CALLCONV __stdcall 
    #el if defined(libjpeg_EXPORTS) 
     #define JPEG_EXPORT __declspec(dllexport) 
    #else 
     #define JPEG_EXPORT __declspec(dllimport) 
    #endif 
#else 
    #define JPEG_EXPORT 
#endif 
+0

但在這種情況下,我必須定義OPJ_STATIC所以知道如果宏定義? – 2011-01-30 17:06:01

0

首先請注意Windows沒有任何動態鏈接的。驚喜!相反,它使用thunk。所以會發生什麼:如果你創建了一個符號dllexport,它有它的實際名稱,就像它不是dllexport一樣。但它在目標文件中標記爲導出。

如果你說dllimport,另一方面,名稱被改變,在C中粗略地將__imp_加入名字,在C++中更加討厭。

現在,當你鏈接一個DLL時,你會得到一個DLL(當然),但你也會得到一個LIB文件。這是一個靜態鏈接庫。鏈接器可以處理的唯一一種。對於從DLL導出的每個符號,該LIB文件中都有一個dllimport符號,特別是帶有__imp_前綴或C++的任何符號。

因此,現在在一個程序或DLL中,您要鏈接到該DLL,而不是針對導入LIB鏈接。導入LIB例程是補丁到DLL的實際加載時間地址的thunk。

因此,現在,如果您嘗試通過簡單地組合包含某些dllexport的OBJ文件對LIB.EXE生成的LIB文件執行普通的靜態鏈接,那麼如果引用是dllimport,它將會失敗。因爲當庫實際包含普通函數()時引用__imp_function()。

因此,與靜態鏈接,你不得不放棄了dllimport的。 AFAIK dllexport無關緊要。請注意,這適用於圖書館,而不是庫本身的客戶

這是什麼意思?那麼靜態鏈接到一個庫,然後動態鏈接到另一個庫是非常好的。事實上,默認情況下,Windows上的靜態鏈接動態鏈接到C運行時和操作系統DLL。所以規則是:客戶必須選擇鏈接到庫的方法,該提供商應提供兩個版本。但保重他們有不同的名字! (否則LINK使得DLL將使fred.LIB和LIB也將使fred.LIB)