0

我有一个最初用 MSVS 编写的库 (dll),我需要制作跨平台 (Mac/Win)。我开始使用 XCode,但有了新的 Embarcadero C++ builder XE3,我认为一个开发环境会是更好的选择。宿主应用程序是用 Delphi 编写的,因此更有理由将其移至一组工具。

对于我现有的代码,一切都是 cdecl 但我无法让它在 C++ builder 上工作。如果我将它转换为stdcall,那么它可以正常工作,但据我所知,在OSX下使用库时我需要使用cdecl。

在 MSVC 中,我像这样导出我的函数:

extern "C" __declspec(dllexport) int Init(char * init_dir, DebugCallbackFunc f, DeviceCallbackFunc f1)

在 C++ Builder 中,我像这样导出:

extern "C" __declspec( dllexport ) int _cdecl Init(char * init_dir, DebugCallbackFunc f, DeviceCallbackFunc f1)

问题是,当我使用 cdecl 时,Delphi 主机应用程序总是使用 GetProcAddress 返回 NULL,但如果我将其更改为 stdcall,则工作正常。

TUDMXInit = function(p: PAnsiChar; f: TDebugCallbackFunc; f1: TDeviceCallbackFunc): integer; cdecl;

我还将欣赏一个处理“_”的最佳方法的示例,该示例假定在 OSX 下作为导出函数的前缀。我应该只使用条件将其添加到所有函数的前面吗?

提前致谢。马丁

4

2 回答 2

4

这样做的通常方法是使用宏。declspec 和 cdecl/stdcall 是特定于 Windows 的。您想要的 OSX(和其他 Unix)中的调用是

extern "C" int Init(char * init_dir, DebugCallbackFunc f, DeviceCallbackFunc f1)

所以通常的方法是定义一个宏,例如 DLL_EXPORT 参见 Boost 库中的示例,例如来自Serialization或来自Tcl的更简单的描述

假设 WINDOWS 在您的构建中为 Windows 库定义

#ifdef WINDOWS
  #define DLLEXPORT  __declspec( dllexport )
#else
  #define DLLEXPORT
#endif

您也可以在此处构建 DLL 或在需要时调用 DLL 时使此定义正确运行__declspec( dllimport )

于 2012-10-09T10:28:16.493 回答
2

我处理这些差异的方式始终是相同的基本思想:看看每个编译器是如何做的,然后想出一个或一组宏,它们可以生成所有需要的表格,而且使用起来不太麻烦。

对于您的 _cdecl,像“EXPORT_CDECL”这样的简单宏似乎就足够了;然后,您可以根据编译器的要求将其设置为空,“_cdecl”或“stdcall”。

您还可以使用类似这样的东西来为名称添加一些东西,例如#define EXPORT_NAME(Name) _##Name

当然,您也可以创建一个“大”宏,它采用单个组件(返回类型、函数名称、函数参数)并吐出整个结果行。

于 2012-10-09T10:26:16.363 回答