У меня есть библиотека (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. Должен ли я просто использовать условные выражения, чтобы добавить это в начале всех функций?
Заранее спасибо.
Мартин
Обычный способ сделать это — использовать макросы. 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 )
То, как я справляюсь с такими различиями, — это всегда одна и та же основная идея: посмотрите, как это делает каждый компилятор, и придумайте макрос или набор макросов, которые могут генерировать все необходимые формы, не будучи слишком громоздкими для использования.
Для вашего _cdecl, казалось бы, достаточно простого макроса, такого как EXPORT_CDECL; затем вы можете установить его так, чтобы он расширился до «_cdecl» или «stdcall», как того требует компилятор.
Вы также можете использовать что-то вроде этого, чтобы добавить что-то к именам, например, #define EXPORT_NAME(Name) _##Name
Конечно, вы также можете создать «большой» макрос, который принимает отдельные компоненты (тип возвращаемого значения, имя функции, параметры функции) и выплевывает всю строку результата.