11

長年のリスナー、初めての発信者。これはややあいまいな質問であることは承知しており、あまり期待しないでください。:-)

次の Ada ファイルがあります。

グリーター広告

package Greeter is
    procedure Hello;
end 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: 未定義のシンボル: ./greeter.pl 行 26 の __gnat_eh_personality。

誰にもヒントはありますか?私が使用すべきDynaLoaderよりも優れた/簡単なものはありますか??

ここにすべての関連ファイルを含むリポジトリがあります。

4

2 に答える 2

10

Perl 側のサポートはできません (5.14 が必要です。Mac OS X には 5.12 があり、Debian 6 には 5.10 があります)。そうは言っても、C メインと直接リンク用のライブラリの構築を手伝うことができます...

GNAT ビルド プロセスは非常に複雑であるため、それをサポートする 2 つのツールがありgnatmakegprbuild. gnatmakeライブラリをビルドする機能が失われる可能性が高いため (2015 年 9 月に執筆) 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.dylibMac OS Xlibgreeter.so上、Linux 上。

Library_Kind属性を にすることもできます。"static"その場合、名前は になりますlibgreeter.a。ただし、スタンドアロン ライブラリは再配置可能でなければなりません

ライブラリを作成するために(上記Library_Dirの2つとともに)指定する必要がある属性は、ライブラリが作成される場所を制御します。この場合、 でlib/

Library_Interfaceスタンドアロン ライブラリにする属性を指定し、Ada エラボレーションを制御する初期化およびファイナライズ操作を生成する必要があります。それらはlibrary_nameinitおよびlibrary_namefinalと呼ばれます- ここではgreeterinit, greeterfinal.

の場合Library_Auto_Init"false"、初期化操作とファイナライズ操作を自分で呼び出す必要があります。 の場合"true"、それらは自動的に管理されます。

OK、ライブラリをビルドします

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
于 2013-01-18T16:35:23.957 に答える
4

Perlの知識があまりないので、これでできる限りのことをします。

perl のDynaloaderは、動的にロード可能なライブラリ (Unix システムでは lib*.so) を perl プログラムにロードできるユーティリティのように思えます。

これを Ada プログラムで機能させるには、考慮しなければならないことがいくつかあります。

  1. Ada プログラムを適切な動的ライブラリとしてビルドする必要があります。あなたはそれをしたようです。ただし、私はこれについての専門家ではないため、何かを見落としている可能性があります。これについては、TFM を調べることを強くお勧めします。
  2. Ada コードを適切に呼び出す必要があります。Ada プログラムでは、通常、実際のコードを実行する前に「精緻化」と呼ばれるプロセスを実行する必要があります。これを実現するために、ほとんどの Ada コンパイラは、「メイン」ルーチンに関連付けられたエントリ ポイントを使用するだけでなく、プログラムへの特別なエントリ ポイントを作成します。Gnat's は のようなものだと思いますがC_yourprogramname、それにとらわれないでください。ある種のライブラリを実装している場合でも、最初に作成を実行する必要があります (ここでは当てはまらない特別な状況では例外です)。ただし、ルーチンを Ada の外部から呼び出されるライブラリ ルーチンにしたい場合は、通常、「メイン」は必要ないため、いくつかの追加の手順があります。Gnat でこれを行う方法は、ユーザー ガイドに記載されています。adainit外部から Ada ルーチンを実行する前に、adafinalすべて完了したら呼び出します。
于 2013-01-18T15:32:48.120 に答える