delphi — C ++ Builder, экспортирующий cdecl для кроссплатформенного использования

У меня есть библиотека (dll), изначально написанная на MSVS, которая мне нужна для кроссплатформенности (Mac / Win). Я начал использовать XCode, но с новым сборщиком Embarcadero C ++ XE3 я думаю, что одной средой разработки будет лучший путь.
Хост-приложение написано на Delphi, поэтому больше оснований для его переноса в один набор инструментов.

Для моего существующего кода все cdecl, но я не могу заставить это работать на C ++ builder. Если я конвертирую его в stdcall, то он работает нормально, но, насколько я понимаю, мне нужно использовать cdecl при использовании библиотеки под OSX.

В 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)

Проблема в том, что хост-приложение Delphi всегда возвращает NULL с GetProcAddress, когда я использую cdecl, но работает нормально, если я изменяю его на stdcall.

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

Я также был бы признателен за пример наилучшего способа обработки ‘_’, который предполагает префикс экспортируемой функции в OSX. Должен ли я просто использовать условные выражения, чтобы добавить это в начале всех функций?

Заранее спасибо.
Мартин

0

Решение

Обычный способ сделать это — использовать макросы. declspec и cdecl / stdcall являются специфичными для Windows.
Вызов в OSX (и другой Unix) вы хотите

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

Таким образом, обычным способом является определение макроса, например DLL_EXPORT см. В примерах библиотек Boost
например от Сериализация или более простое описание из Tcl

Предполагая, что WINDOWS определен в вашей сборке для библиотек Windows

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

Также вы можете сделать так, чтобы это определение вело себя корректно при сборке DLL как здесь или при вызове DLL, когда вам нужно __declspec( dllimport )

4

Другие решения

То, как я справляюсь с такими различиями, — это всегда одна и та же основная идея: посмотрите, как это делает каждый компилятор, и придумайте макрос или набор макросов, которые могут генерировать все необходимые формы, не будучи слишком громоздкими для использования.

Для вашего _cdecl, казалось бы, достаточно простого макроса, такого как EXPORT_CDECL; затем вы можете установить его так, чтобы он расширился до «_cdecl» или «stdcall», как того требует компилятор.

Вы также можете использовать что-то вроде этого, чтобы добавить что-то к именам, например, #define EXPORT_NAME(Name) _##Name

Конечно, вы также можете создать «большой» макрос, который принимает отдельные компоненты (тип возвращаемого значения, имя функции, параметры функции) и выплевывает всю строку результата.

2