функция экспорта pragma не является внешней в исполняемом файле Ada

#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 не обязательно совпадает с Ada Integer , и вместо этого вы должны использовать Interfaces.C.int для возвращаемого типа в Ada.
  • Соглашения о вызовах должны совпадать. Stdcall в Ada соответствует явному __stdcall в C . Если у вас нет __stdcall в коде C , вместо этого используйте соглашение о C вызовах в Ada.