Загрузка общих объектов Ada в Perl с помощью DynaLoader.pm

Длительный прослушиватель, первый раз. Я знаю, что это несколько неясный вопрос, и не ожидайте слишком многого.: -)

У меня есть следующие файлы Ada:

greeter.ads

package Greeter is
    procedure Hello;
end Greeter;

greeter.adb

with Ada.Text_IO; use Ada.Text_IO;
package body Greeter is
    procedure Hello is
    begin
        Put_Line ("Hello, world!");
    end Hello;
end Greeter;

И скомпилируйте их в общий объект, подобный этому:

gnatmake -z -fPIC greeter.adb
gcc -shared -o libgreeter.so greeter.o

Это компилируется отлично. nm отображаются следующие символы:

$ nm -D libgreeter.so 
                 w _Jv_RegisterClasses
0000000000201028 A __bss_start
                 w __cxa_finalize
                 w __gmon_start__
                 U __gnat_eh_personality
0000000000201028 A _edata
0000000000201038 A _end
00000000000006a8 T _fini
0000000000000520 T _init
                 U ada__text_io__put_line__2
0000000000201018 D greeter_E
000000000000063c T greeter__hello

Теперь я пытаюсь загрузить этот общий объект в Perl:

#!/usr/bin/env perl

use 5.014;
use strict;
use warnings;

#BEGIN { $ENV{PERL_DL_DEBUG} = 1 };

package Greeter
{
    use constant ADADIR => '/usr/lib/gcc/x86_64-linux-gnu/4.4/rts-native/adalib/';
    use constant OURDIR => do { (my $f = __FILE__) =~ s{[^/]+$}//; $f || "." };

    require DynaLoader;
    our @ISA = 'DynaLoader';

    my $runtime = DynaLoader::dl_load_file(
        ADADIR.'/libgnat.so',
    ) or die DynaLoader::dl_error();

    my $gep = DynaLoader::dl_find_symbol(
        $runtime,
        '__gnat_eh_personality',
    ) or die DynaLoader::dl_error();

    my $libref = DynaLoader::dl_load_file(
        OURDIR.'/libgreeter.so',
        0x01,
    ) or die DynaLoader::dl_error();

    my $func = DynaLoader::dl_find_symbol(
        $libref,
        'greeter__hello',
    ) or die DynaLoader::dl_error();

    print $func, $/;
}

Но это бомбит со следующим сообщением:

./libgreeter.so: undefined символ: __gnat_eh_personality в строке. /greeter.pl 26.

Есть ли какие-нибудь намеки? Есть ли что-то лучше/проще, чем DynaLoader, что я должен использовать?

У меня есть репозиторий со всеми соответствующими файлами здесь:

Ответ 1

Я не могу помочь с Perl-стороной (вам нужно 5.14, Mac OS X - 5.12, Debian 6 - 5.10). Тем не менее, я могу помочь в создании библиотеки для основной и прямой связи C...

Процесс сборки GNAT достаточно сложный, поскольку для его поддержки есть два инструмента: gnatmake и gprbuild. Его вероятность (запись в сентябре 2015 года), что gnatmake потеряет способность создавать библиотеки, поэтому gprbuild является лучшим вариантом.

Мне кажется, вам нужен автономный проект библиотеки (т.е. один с операциями инициализации и завершения, которые контролируют разработку Ada, если вы не инициализируете библиотеку Ada, вы получите SEGV или другое плохое поведение). Вы найдете нижнюю часть создания здесь.

greeter.gpr Я написал

project Greeter is
   for Library_Name use "greeter";
   for Library_Kind use "relocatable";
   for Library_Dir use "lib";
   for Library_Interface use ("greeter");
   for Library_Auto_Init use "true"; -- the default, I think
   for Object_Dir use ".build"; -- to keep temp objects out of the way
end Greeter;

Атрибут Library_Name управляет именем библиотеки; libgreeter.dylib в Mac OS X, libgreeter.so в Linux.

Атрибут Library_Kind может альтернативно быть "static", и в этом случае имя будет libgreeter.a. Однако автономные библиотеки должны быть перемещены.

Атрибут Library_Dir, который вы должны предоставить (с двумя выше), чтобы создать библиотеку вообще, контролирует, где создается библиотека; в этом случае в lib/.

Вы должны указать атрибут Library_Interface, чтобы сделать его автономной библиотекой и создать операции инициализации и завершения, которые контролируют разработку Ada. Они называются library_name init и library_name final - здесь, greeterinit, greeterfinal.

Если Library_Auto_Init - "false", вы должны сами вызывать операции инициализации и завершения, если "true", они управляются автоматически.

ОК, постройте библиотеку

gprbuild -p -P greeter

(-p говорит "создайте любые необходимые выходные каталоги", -p указывает файл проекта).

Я построил greeter.c

#include <stdio.h>

extern void greeter_hello();

int main()
{
  greeter__hello();
  return 0;
}

используя

$ gcc greeter.c -o greeter -L lib -l greeter

и запустить (в Linux) с помощью

$ LD_LIBRARY_PATH=./lib ./greeter

Ответ 2

Я сделаю все, что в моих силах, учитывая небольшое количество знаний Perl.

Мне кажется, что Dynaloader в perl - это утилита, которая позволяет загружать динамически загружаемые библиотеки (lib *.so в Unix систем) в программу perl.

Для этого для работы с программой Ada вам нужно будет принять во внимание несколько вещей.

  • Вам необходимо создать свою программу Ada как правильную динамическую библиотеку. Похоже, ты это сделал. Однако я не эксперт в этом, поэтому, возможно, вы что-то пропустили. Я настоятельно рекомендую рассмотреть TFM на этом.
  • Вам нужно правильно назвать свой код Ada. Обычно программы Ada требуют, чтобы процесс, называемый "разработка", выполнялся до того, как какой-либо фактический код может быть запущен. Для этого большинство компиляторов Ada создают специальную точку входа в программу, вместо того, чтобы просто использовать ту, которая связана с вашей "основной" процедурой. Я думаю, что Gnat - это что-то вроде C_yourprogramname, но не держите меня в этом. Даже если вы реализуете какую-либо библиотеку, сначала нужно выполнить разработку (в некоторых особых случаях, которые здесь не применяются). Однако, если вы хотите, чтобы подпрограмма была библиотечной процедурой, вызываемой извне Ada, вам обычно не нужен "основной", поэтому есть дополнительные шаги. Как это сделать с Gnat, описано в их руководстве пользователя, но в целом это связано с сообщением компилятору не делать "главное", вызывая adainit перед запуском любой процедуры Ada извне и вызовите adafinal, когда все будет готово.