0
votes

I have a library (dll) originally written in MSVS that I need to make cross platform (Mac/Win). I started using XCode but with the new Embarcadero C++ builder XE3 I am thinking that one development environment would be a better way to go. The host application is written in Delphi so more reason to move it to one set of tools.

For my existing code everything is cdecl but I cannot get this to work on C++ builder. If I convert it to stdcall then it works fine but as I understand it I need to use cdecl when using the library under OSX.

In MSVC I export my functions like this:

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

In C++ Builder I am exporting like this:

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

The problem is that the Delphi host application always returns NULL with GetProcAddress when I use cdecl but works fine if I change it to stdcall.

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

I would also appreciate an example of the best way to handle the '_' that is suppose to prefix the exported function under OSX. Should I just use conditionals to add this at the front of all functions?

Thanks in advance. Martin

2
There is more than just a _ in the C++ library names, do that issue as another question - mmmmmm
Personally I think a .def file is the most effective way to specify your exports. Well, that's for Windows. Not sure about OSX. - David Heffernan

2 Answers

4
votes

The usual way of doing this is to use macros. declspec and cdecl/stdcall are Windows specific. The call in OSX(and other Unix) you want is

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

So the usual way is to define a macro e.g. DLL_EXPORT see the Boost libraries for examples e.g. from Serialisation or a simpler description from Tcl

Assuming WINDOWS is defined in your build for Windows libraries

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

Also you can make this define behave correctly for when building the DLL as here or calling the DLL when you need __declspec( dllimport )

2
votes

The way I handle such differences is always the same basic idea: look at how each compiler does it, and come up with a macro or a set of macros that can generate all the required forms without being too cumbersome to use.

For your _cdecl, a simple macro like "EXPORT_CDECL" would seem to suffice; you can then set this to expand to nothing, "_cdecl", or "stdcall" as required by the compiler.

You can also use something like this to add something to names, such as #define EXPORT_NAME(Name) _##Name

You can, of course, also make a "big" macro that takes the individual components (return type, function name, function parameters) and spits out the entire result-line.