最近 Ada の学習を始めました。Ada と C オブジェクト ファイルをリンクして多言語プログラムまたはライブラリを構築できることを知っています。XS を使用して Perl から Ada コードを呼び出すことは可能ですか?
1 に答える
はい!
実際、C から呼び出せる言語は、XS を使用して Perl からも使用できます。Ada モジュールと ExtUtils::MakeMaker を使用してそれを行う方法の解決策を次に示します。
セットアップ
モジュールツリー
を使用してモジュールツリーを作成することから始めましょうh2xs
:
$ h2xs -A -n MyAdaModule
次に、Ada ファイルを保持するサブディレクトリを作成しましょう。
$ cd MyAdaModule
$ mkdir src
モジュールの仕様は次のとおりです: src/hello.ads
procedure hello;
...そして本文: src/hello.adb
with Ada.Text_IO;
use Ada.Text_IO;
procedure hello is
begin
Put_Line("Hi from Ada!");
end;
MANIFEST を更新することを忘れないでください。
XS ファイルの作成
MyAdaModule.xs の本体を書きましょう。これは、C ライブラリの関数を使用するのとほとんど同じです。
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
extern void adainit();
extern void adafinal();
MODULE = MyAdaModule PACKAGE = MyAdaModule
void say_hello()
CODE:
adainit();
hello();
adafinal();
ブヨのドキュメントから、adainit()
andを呼び出しadafinal()
て初期化してからクリーンアップする必要があることがわかります。これらの呼び出しはここで囲みhello()
ますが、XS ファイル内の他の関数内のより適切な場所にある可能性があります。これらは、Perl モジュールの BEGIN および END ブロックから呼び出されます。
コンパイルする時間です!
エイダ図書館
まず、すべての魔法のリンクとバインドを MakeMaker に委任したくないので、src/ ディレクトリに Ada コードをコンパイルして静的ライブラリにする makefile を作成しましょう。
このライブラリを作成するhello.a
には、ブヨのドキュメントに従うだけです。
- および
gnatmake -c
を生成するために使用します。hello.ali
hello.o
- スイッチで使用
hello.ali
します。これにより、バインド コードを含むとが生成されます。gnatbind
-n
b~hello.adb
b~hello.ads
b~hello.adb
オブジェクトファイルにコンパイルします:b~hello.o
.- グループ化し
hello.o
、b~hello.o
一緒にアーカイブにar
要するに、次の makefile を使用します。
all: hello.a
hello.a: hello.o b~hello.o
ar rcs $@ $^
hello.o: hello.adb hello.ads
gnatmake -c -o $@ $<
b~hello.o: b~hello.adb b~hello.ads
gnatmake -c -o $@ $<
b~hello.adb: hello.ali
gnatbind -n $<
hello.ali: hello.o
clean:
rm -rf *.o *.ali *.a b~*
MANIFEST を更新することを忘れないでください。
Makefile.PL
最後に、MakeFile.PL ファイルを編集する必要があります。上記の makefile を呼び出してライブラリをビルドし、最終的なリンク フェーズで使用する必要があります。これは、セクションにルールを設定MYEXTLIB
して追加することによって行われます。src/hello.a
postamble
Ada.Text_IO
この場合、システムのどこかにあるlibgnat (for ) とリンクする必要もあります。これは編集によって行われますLIBS
。この例では、パスはハードコーディングされていますが、libgnat を見つけるためのより移植性の高い方法を見つける必要があります。
use 5.018001;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
NAME => 'MyAdaModule',
VERSION_FROM => 'lib/MyAdaModule.pm', # finds $VERSION
PREREQ_PM => {}, # e.g., Module::Name => 1.1
($] >= 5.005 ? # Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'lib/MyAdaModule.pm', # retrieve abstract from module
AUTHOR => 'A. U. Thor <author@nonet>') : ()),
DEFINE => '', # e.g., '-DHAVE_SOMETHING'
INC => '-I.', # e.g., '-I. -I/usr/include/other'
LIBS => ['-L/usr/lib/gcc/i686-pc-linux-gnu/4.8.2/adalib/ -lgnat'],
MYEXTLIB => 'src/hello.a',
);
sub MY::postamble {
join("\n",
"\$(MYEXTLIB)::",
"\tmake -C src/",
"",
"clean::",
"\tmake -C src/ clean",
);
}
今すぐ試してください
$ perl Makefile.PL
$ make
$ make test
そして驚いたことに、テストに合格しませんでした! hello()
シンボルが存在しません。MyAdaLib.so
ツールを使用して make によって生成されたファイルを調べると、nm
一部のシンボルの名前が変更されていることがわかります。私の場合、プレフィックスは_ada_
. _ada_hello()
そのため、代わりにを呼び出す必要がありhello()
ます。これは、プラグマsrc/ada.ads
を使用して修正できます。Export
pragma Export
(Convention => C,
Entity => hello,
External_Name => "hello" );
私が理解したことから、これは、型、レコードなどの表現が C プログラムから理解されるようにするため、すべてのパブリック シンボルに対して行う必要があります。
hello()
これで、XSUBから呼び出すことができるはずです。楽しみ!