#windows #dll #ada #gnat #gnat-gps
#Windows #dll #ada #gnat #gnat-gps
Вопрос:
Мне нужно, чтобы библиотека DLL Visual Studio C могла вызывать функцию в моей основной строке Ada. Код Ada имеет спецификацию функции, например
package offset is
function GET_OFFSET return integer;
pragma Export (Stdcall, GET_OFFSET, "fnAdaOffset");
end offset;
Затем функция C вызовет метод Ada следующим образом:
typedef int (*tdAdaOffset)(void);
tdAdaOffset _ptAdaOffset = NULL;
int AdaOffset()
{
if (_ptAdaOffset == NULL)
{
_ptAdaOffset = (tdAdaOffset)GetProcAddress(GetModuleHandle(NULL), "fnAdaOffset@0");
if (_ptAdaOffset == NULL)
throw "Function not found";
}
return (*_ptAdaOffset)();
}
Я считаю, что это сработает. Проблема, с которой я сталкиваюсь, заключается в том, что Ada отказывается помечать функцию GET_OFFSET как внешнюю в исполняемом файле, т.Е. Выполнять выгрузку / экспорт ada.exe не показывает мне никаких экспортированных функций.
Я читал различные решения, такие как —version-script для компоновщика, но мой компоновщик кажется слишком старым, чтобы знать об этом переключателе.
Другим многообещающим вариантом было добавить -shared к шагу ссылки, но, хотя это теперь предоставляет функции, это также изменяет выходной файл на DLL (с .EXE как его расширение (!)), так что это тоже бесполезно.
Прежде чем я обновлю свой набор инструментов, могу ли я попробовать другой переключатель компоновщика или какие-либо другие предложения?
Комментарии:
1. Я считаю, что вам нужно
-Wl,--export-dynamic
экспортировать функцию из исполняемого файла, но я никогда этого не делал.2. Также вы не должны использовать
Stdcall
в Ada, если вы не указали__stdcall
в C .3. Один вопрос, который у меня есть, который может повлиять на ответы на этот вопрос, заключается в том, какую роль в этом играет инициализация / завершение. Обычно при использовании библиотеки DLL Ada в C вам приходится связывать и использовать процедуру инициализации перед вызовом подпрограмм Ada, а иногда вызывать связанную процедуру завершения после. Я чувствую, что это может быть применимо здесь, но не уверен, как конкретно, поскольку автор не указал, является ли это Ada, вызывающим c DLL, вызывающим Ada routine против C , вызывающего C DLL, вызывающего Ada routine
4. @flyx, вы были почти на месте: правильный переключатель при создании EXE был
-Wl,-export-all-symbols
. Мне пришлось перейти на более новую версию GNATGPL, чтобы использовать ее. Отправьте в качестве ответа, и я пометлю его как правильный.5. @Jere, поскольку моя основная строка написана на Ada, вся доработка будет выполнена к тому времени, когда я вызову подпрограмму Visual C , которая, в свою очередь, обратится к Ada. Спасибо за напоминание.
Ответ №1:
Вам нужно указать компоновщику экспортировать символы из исполняемого файла. ld
однако есть опция --export-dynamic
, которая работает только с целями ELF:
Обратите внимание, что эта опция специфична для целевых портов ELF. Цели PE поддерживают аналогичную функцию для экспорта всех символов из DLL или EXE; см. Описание —export-all-symbols ниже.
Поэтому в Windows вам необходимо использовать --export-all-symbols
.
В зависимости от того, как вы компилируете свой код Ada, вам может потребоваться передать эту опцию через команду компилятора ( gcc
). Чтобы указать gcc
, что компоновщик должен использовать параметр, вы добавляете к нему префикс, -Wl
а затем указываете параметры компоновщика через запятую. В этом случае вы получите -Wl,--export-all-symbols
.
Если вы используете GPRBuild, соответствующая часть вашего .gpr
файла будет выглядеть следующим образом:
package Linker is
for Default_Switches ("Ada") use ("-Wl,--export-all-symbols");
end Linker;
Примечания:
- Имейте в виду, что C
int
не обязательно совпадает с AdaInteger
, и вместо этого вы должны использоватьInterfaces.C.int
для возвращаемого типа в Ada. - Соглашения о вызовах должны совпадать.
Stdcall
в Ada соответствует явному__stdcall
в C . Если у вас нет__stdcall
в коде C , вместо этого используйте соглашение оC
вызовах в Ada.