2013-10-17 65 views
26
gcc (GCC) 4.7.2 

您好運行,創建一個可移植庫在Linux和Windows

我創建一個共享庫,將編譯在Linux上,這將彙編使用相同的源代碼窗口的DLL。所以我正在爲Linux和Windows創建一個可移植的庫。

在該庫我的頭文件是這樣的module.h中即

#ifdef __cplusplus 
extern "C" { 
#endif 

#ifdef _WIN32 
#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type 
#else 
#define LIB_INTERFACE(type) type 
#endif 

LIB_INTERFACE(int) module_init(); 

#ifdef __cplusplus 
} 
#endif 

在源我有以下即的module.c

#include "module.h" 

LIB_INTERFACE(int) module_init() 
{ 
    /* do something useful 
    return 0; 
} 

而且在我的測試應用程序,將鏈接並使用此module.so我有這個:

#include "module.h" 

int main(void) 
{ 
    if(module_init() != 0) { 
    return -1; 
    } 
    return 0; 
} 

1)是我在上面做的是它是一個正確的工程爲Linux和Windows創建便攜式庫的ntation?

2)我只是想知道我已經包裝了extern "C"中的函數,以便可以從已經用C++編譯的程序調用該庫。我還需要這EXTERN_C在以下幾點:

#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type 

3)什麼是EXTERN_C的目的是什麼?

提前許多感謝,

+5

它是一個宏,它解析爲用於C++編譯的'extern「C」',用於C編譯的'extern'或者什麼也不是。 (我真的不記得哪一個,但突出顯示它並按F12,它應該帶你到實際的定義)。它的目的是指示編譯器從正在從庫中導出的符號中刪除C++名稱。不,如果你已經把整個頭部封裝在'extern「C」{'你可以消除它(假設gcc理解同一個block-extern-C,再次,我不誠實地記得它是否會)。 – WhozCraig

+1

請閱讀[this](http://gcc.gnu.org/wiki/Visibility)。你可能想要使用這種機制。 –

+0

@ ant2009您的庫必須從C使用,還是可以將其限制爲C++ 11? –

回答

20

這是導出一個DLL API for Windows和仍然支持Linux的一個典型方式:

#ifdef __cplusplus 
extern "C" { 
#endif 

#ifdef _WIN32 
# ifdef MODULE_API_EXPORTS 
# define MODULE_API __declspec(dllexport) 
# else 
# define MODULE_API __declspec(dllimport) 
# endif 
#else 
# define MODULE_API 
#endif 

MODULE_API int module_init(); 

#ifdef __cplusplus 
} 
#endif 

在DLL來源:

#define MODULE_API_EXPORTS 
#include "module.h" 

MODULE_API int module_init() 
{ 
    /* do something useful */ 
    return 0; 
} 

你的應用程序源代碼是正確的。

使用上述模型,在Windows上,DLL將導出API,而應用程序將導入它。如果不在Win32上,__declspec裝飾被刪除。

由於標題將extern "C"中的整個接口封裝起來,因此不需要在每個接口上使用EXTERN_C宏。 extern "C"用於告訴鏈接器使用C鏈接而不是C++。 C連接在編譯器中是標準的,而C++不是,它將DLL的使用限制在使用相同編譯器構建的應用程序中。

沒有必要將返回類型集成到API宏中。

13

的extern「C」基本上意味着你在告訴編譯器不要裂傷你函數名。 Mangling是爲以後執行「編碼」函數名稱的過程,在C和C++中完全不同,因爲C++可以具有不同的具有相同名稱的函數(通過重載等)。

In C++ source, what is the effect of extern "C"?

一旦編譯這些功能可以在任何地方調用,但你可能想知道什麼樣的你正在創建庫(靜態或動態),然後再開始。

另外,我建議您不要使用DEFINES,就像您在同一個文件中進行移植一樣,因爲您在開發中稍後可能會遇到維護或可讀性問題。 我將創建一個基本文件,定義一個完全可移植到WIN和UNIX的接口,然後創建兩個其他庫來實現接口,但是用於不同的平臺。

例如,你可以有: AbstractInterface.h,WinInterface.h,UnixInterface.h

然後只編譯你需要根據不同的平臺上的人。

3

由於C++語言特有的多態性概念,C++中定義的所有函數都被破壞。即爲每個重寫函數創建唯一名稱,「編譯器」裝飾函數名稱。由於名稱修改是由「編譯器」處理的,並且沒有規定嚴格定義名稱修改規則,所以每個編譯器都以不同方式修飾名稱。簡而言之,gcc和msvc編譯器爲相同的代碼創建不同的函數簽名。你可以在wiki文章here上進一步閱讀關於名稱改變的內容。

您的module.h文件只是告訴編譯器使用c風格的名稱修改或根本沒有修改。由於此指令,由gcc編譯的庫可用於鏈接到在Visual Studio中編寫的二進制文件。這將幫助您分發庫的二進制文件而不是源代碼。另一方面,如果不使用EXTERN_C指令,則應該使用相同的編譯器編譯鏈接到庫的庫和項目。例如,對於庫和鏈接到該庫的項目,必須使用gcc for linux編譯和msvc編譯windows編譯。

+0

's/polymorphism/overloading /' –

+0

多態性是超載的超集; p – madrag

8

對於Linux,不帶靜態函數的gcc不帶-fvisibility = hidden將使默認導出函數。

隨着-fvisibility =隱藏,GCC將沒有默認被導出功能,除了功能由

__attribute__ ((visibility ("default"))) 

裝飾對於Windows,導出的函數使用導出功能時

__attribute__ ((dllexport)) 

裝飾,他們必須裝飾

__attribute__ ((dllimport)) 

宏中您的帖子

__declspec(dllexport) 

由MSVC支持。

所以交叉Linux和Windows宏如下:

#if defined _WIN32 || defined __CYGWIN__ || defined __MINGW32__ 
    #ifdef BUILDING_DLL 
    #ifdef __GNUC__ 
     #define DLL_PUBLIC __attribute__ ((dllexport)) 
    #else 
     #define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. 
    #endif 
    #else 
    #ifdef __GNUC__ 
     #define DLL_PUBLIC __attribute__ ((dllimport)) 
    #else 
     #define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax. 
    #endif 
    #endif 
    #define DLL_LOCAL 
#else 
    #if __GNUC__ >= 4 
    #define DLL_PUBLIC __attribute__ ((visibility ("default"))) 
    #define DLL_LOCAL __attribute__ ((visibility ("hidden"))) 
    #else 
    #define DLL_PUBLIC 
    #define DLL_LOCAL 
    #endif 
#endif 
  • 確保共享對象或DLL項目必須編譯 -DBUILDING_DLL。
  • 這取決於你的共享對象或DLL上的項目必須在沒有 -DBUILDING_DLL

對於更多的細節被編譯,請閱讀http://gcc.gnu.org/wiki/Visibility

2

而不是寫一個頭文件自己,你也可以讓CMake的生成一個使用CMake's generate_export_header像這樣(從鏈接頁面所採取的例子)建築編譯:

add_library(libfoo foo.cpp) 
generate_export_header(libfoo)
#include "libfoo_export.h" 
class LIBFOO_EXPORT FooClass { 
    int bar; 
};
相關問題