Как связать пользовательскую dll в Аде?

Итак, это простой проект, который я собрал только для тестирования, прежде чем делать с ним кое-что интересное позже. Конечная цель состоит в том, чтобы сделать программу способной обрабатывать модульность с помощью удивительного кунг-фу DLL.

Но, детские шаги. Прямо сейчас я просто хочу сделать ссылку на вещь.

Вот у меня Adder.ads:

package Adder is

    function Add(A : Integer; B : Integer) return Integer;

end Adder;

И соответствующий Adder.adb:

package body Adder is

    function Add(A : Integer; B : Integer) return Integer is
    begin
        return A + B;
    end Add;

end Adder;

Захватывающе, я знаю.

Я видел несколько разных руководств о том, как это сделать, и ни один из них не согласен, но я беру пример из этот, я придумал следующие команды:

gnatmake -c Adder.adb
gcc -shared -shared-libgcc -o Adder.dll Adder.o

По крайней мере, это создает a dll. Я не знаю, генерирует ли он тот, который действительно будет работать, или проблема связана с основным исполняемым файлом.

Теперь главный исполняемый файл, я сохранил все в отдельном каталоге, чтобы gnat не пытался обмануть и использовать файлы .ali и .o. Затем вы копируете dll в каталог перед попыткой сборки. Я пробовал эту настройку множеством разных способов и получил несколько разных ошибок, но вот что у меня есть прямо сейчас.

Основной.adb:

with Adder_Spec; use Adder_Spec;
with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
begin
    Put_Line(Integer'Image(Add(3,4)));
end Main;

Ура, самая бесполезная программа. Теперь, зная, что у меня должна быть спецификация для dll, я придумал вышеупомянутый Adder_Spec.ads:

package Adder_Spec is

    function Add(A : Integer; B : Integer) return Integer;

private

    pragma Import(Ada, Add, "Add");

end Adder_Spec;

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

gnatmake Main.adb -bargs -shared -largs -lAdder

С этой конкретной командой он выдает ошибку «Неопределенная ссылка на« Добавить »». Если я добавлю флаг -v, это не даст гораздо больше полезной информации.

Проверка gnatmake --help показывает мне, что режим по умолчанию — gnat 2012, если это имеет значение. Вероятно, не должно, поскольку я пробовал компилировать с флагами для 2005 и 95 годов.

Итак... может ли кто-нибудь достаточно сообразительный определить проблему? Заранее спасибо.


person Devsman    schedule 24.03.2017    source источник
comment
Технически это вопрос GNAT, а не вопрос Ada (но я думаю, что в любом случае наиболее рационально сохранить тег ada).   -  person Jacob Sparre Andersen    schedule 24.03.2017
comment
Когда вы говорите gcc -shared -shared-libgcc -o Adder.dll -Adder.o, я думаю, вы должны иметь в виду только Adder.o?   -  person Simon Wright    schedule 24.03.2017
comment
@SimonWright да, хороший улов.   -  person Devsman    schedule 24.03.2017


Ответы (2)


Если вы хотите сказать

package Adder_Spec is
    function Add(A : Integer; B : Integer) return Integer;
private
    pragma Import(Ada, Add, "Add");
end Adder_Spec;

при импорте DLL вы должны сказать

package Adder is
    function Add(A : Integer; B : Integer) return Integer;
    pragma Export (Ada, Add, "Add");
end Adder;

при его построении.

Имя компоновщика по умолчанию GNAT для сгенерированного Add будет (я думаю) adder__add; вы должны увидеть, что он использует nm Adder.o.

person Simon Wright    schedule 24.03.2017
comment
Насколько мне известно, экспорт прагмы должен быть объявлен сразу после определения импортированного контракта: не остается никакой двусмысленности в отношении его объема. С экспортом, объявленным в частной части, и контрактом в публичной части, каким в любом случае будет ожидаемое поведение? И зачем нужна такая конструкция? - person LoneWanderer; 25.03.2017
comment
@LoneWanderer — если вы отметите ARM05 B .1(51) вы увидите экспорт, объявленный в приватной части. Я полагаю, что может возникнуть проблема, если вы использовали подпрограмму до того, как увидели прагму, возможно, объявив переменную, инициализированную результатом вызова функции; идея здесь и в приведенном выше примере должна заключаться в том, чтобы скрыть беспорядочные детали от глаз тех, кому действительно не нужно знать. В настоящее время, конечно, аспекты Convention, Export и External_Name прямо вам в лицо! - person Simon Wright; 25.03.2017

Я предлагаю вам следовать инструкциям в разделе «Подключаемые модули и общие библиотеки Ada» (часть 1, часть 2) из AdaCore.

Я использовал технику, описанную там, и она работала очень хорошо.

person Jacob Sparre Andersen    schedule 24.03.2017