创建一个可在linux和windows上运行的可移植库

ant*_*009 28 c c++ compatibility

gcc (GCC) 4.7.2
Run Code Online (Sandbox Code Playgroud)

你好,

我正在创建一个将在linux上编译的共享库和一个将在Windows上使用相同的源代码编译的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
Run Code Online (Sandbox Code Playgroud)

在源代码中我有以下即module.c

#include "module.h"

LIB_INTERFACE(int) module_init()
{
    /* do something useful
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在我的测试应用程序中将链接并使用此模块.所以我有这个:

#include "module.h"

int main(void)
{
    if(module_init() != 0) {
    return -1;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

1)我上面所做的是为linux和windows创建可移植库的正确实现吗?

2)我只是想知道我已经包装了函数,extern "C"以便可以从用C++编译的程序调用该库.我是否还需要EXTERN_C以下内容:

#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type
Run Code Online (Sandbox Code Playgroud)

3)目的是EXTERN_C什么?

提前谢谢了,

Mar*_*nen 23

这是为Windows导出DLL API并仍然支持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
Run Code Online (Sandbox Code Playgroud)

在DLL源代码中:

#define MODULE_API_EXPORTS
#include "module.h"

MODULE_API int module_init()
{
    /* do something useful */
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您的申请来源是正确的.

使用上面的模型,在Windows上DLL将导出API,而应用程序将导入它.如果不在Win32上,__declspec则删除装饰.

由于标头包裹整个接口extern "C",EXTERN_C因此不需要在每个接口上使用宏. extern "C"用于告诉链接器使用C链接而不是C++.C链接是编译器的标准,而C++则不是,将DLL的使用限制为使用相同编译器构建的应用程序.

无需将返回类型集成到API宏中.


aou*_*out 13

extern"C"基本上意味着你告诉编译器不要破坏你的函数名.Mangling是"编码"函数名以供以后执行的过程,在C和C++中完全不同,因为C++可以具有不同的具有相同名称的函数(通过重载等...).

在C++源代码中,extern"C"的作用是什么?

编译完成后,可以从任何地方调用这些函数,但您可能希望在开始之前确定要创建的库(静态或动态).

另外,我建议您不要像在同一文件中那样使用DEFINES以实现可移植性,因为您在开发后期可能会遇到维护或可读性问题.我将创建一个定义接口的基本文件,该接口完全可以移植到WIN和UNIX,然后创建另外两个实现接口但不同平台的库.

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

然后根据平台编译您需要的那些.


Lik*_*ike 12

对于Linux,没有-fvisibility = hidden的gcc将默认导出函数,静态函数除外.

使用-fvisibility = hidden时,默认情况下gcc不会导出任何函数,除了由...装饰的函数

__attribute__ ((visibility ("default")))
Run Code Online (Sandbox Code Playgroud)

对于Windows,导出的函数由装饰

__attribute__ ((dllexport))
Run Code Online (Sandbox Code Playgroud)

使用导出的函数时,必须对它们进行修饰

__attribute__ ((dllimport))
Run Code Online (Sandbox Code Playgroud)

帖子中的宏

__declspec(dllexport)
Run Code Online (Sandbox Code Playgroud)

由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
Run Code Online (Sandbox Code Playgroud)
  • 确保必须使用 -DBUILDING_DLL 编译共享对象或DLL项目 .
  • 必须在不使用 -DBUILDING_DLL的情况下编译依赖于共享对象或DLL的项目

有关详细信息,请阅读http://gcc.gnu.org/wiki/Visibility