8

私は ada ライブラリを作成しようとしていますが、いくつかの異なることを試しました。makefile を使用してプロジェクトをコンパイルし、すべての .o ファイルからライブラリを作成しようとしましたが、期待どおりに動作しないようです。次に、adacore サポートに問い合わせたところ、ada プロジェクトと c プロジェクトの両方に .gpr ファイルを使用し、ライブラリを作成する必要がある ada.gpr を使用する方向を示してくれました。これはほとんど機能しましたが、ada をコンパイルしようとすると、未定義の参照が発生します。

私が試したこと: コマンドライン:

ar rc libmy_lib.a *.o

libにあるものを読み込もうとすると

ld libmy_lib.a

このエラー ld: warning: cannot find entry symbol _start; が表示されます。開始アドレスを設定しない

プロジェクト ファイル: 私の ada プロジェクト ファイル prj.gpr

project Prj is
for Source_Dirs use ("source1/", "source2", ....);
for Object_Dir use ".";

for Languages use ("Ada");
for Library_Name use "test";
for Library_Dir use "lib";
for Library_Interface use (
 --All my ada packages
        );

package Naming is
      for Spec_Suffix ("ada") use ".1.ada";
      for Body_Suffix ("ada") use ".2.ada";
      for Separate_Suffix use ".2.ada";
      for Dot_Replacement use ".";
   end Naming;

   package Compiler is
      for Default_Switches ("ada") use ("-v", "-g", "-gnato", "-gnatwa", "-gnatQ", "-gnat05");
   end Compiler;

   package Builder is
      for Global_Compilation_Switches ("Ada") use ("-gnat95");
   end Builder;

   package Ide is
  end Ide;

end Prj;

私のCプロジェクトファイル c_main.gpr

with "prj.gpr";
project C_Main is
for Source_Dirs use ("source_c_1/", "source_c_2/");
for Languages use ("C");
for Main use ("source_c_1/main.c");
end C_Main;

コマンド gprbuild c_main.gpr を実行すると

2 つの異なるエラーが発生しました。最初は、ADA コードの一部であるいくつかのパッケージへの未定義の参照であり、存在を知らなかった gnat .adb ファイルで発生しました。壊れたライブラリだと思います。2 つ目は、コードが正常にコンパイルされて実行されても、特定のパッケージのフィールドが見つからない/存在しないことです。フィールドがADAコードに存在しないというエラーが表示されます。

TLDR: 3 つの異なるディレクトリに ada プロジェクトがあり、それらからライブラリを作成したいと考えています。次に、C テスト プログラムにリンクします。最終的には、ライブラリ ファイルを配信するだけです。コマンドラインが最適です。プロジェクトファイルを扱いたくありません。

4

1 に答える 1

10

スタティック ライブラリの作成には大きな問題がありますlibtest.a

まず、Ada コードは Ada ランタイム システム (RTS) で呼び出される可能性が非常に高くなります。静的ライブラリを作成する場合、あなた (またはあなたのユーザー) は、使用するかどうかにかかわらず、Ada RTS を明示的に呼び出す必要がありますgprbuild。だからどちらでもない

gcc main_c.c -ltest

または

gprbuild -P c_main

十分でしょう。次のような(さらに悪い)失敗が発生します。

$ gcc main.c -Lada/lib -ltest
Undefined symbols for architecture x86_64:
  "_ada__calendar__delays__delay_for", referenced from:
      _Hello in libtest.a(hello.o)
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

第 2 に、Ada コードは、プログラムの開始時に行われる精緻化を必要とするかもしれません (そうなるでしょう!)。ライブラリを作成するgprbuildと、関数が追加さtestinit()れます。これは、C コードがライブラリのインターフェイスを呼び出す前に呼び出す必要testfinal()があり、ライブラリのすべての使用後に呼び出される必要があります (ほとんどの人は気にしません)。

最初の問題を回避する方法は、動的ライブラリを作成することです ( .dllWindows、.soLinux およびその他の Unix システム、.dylibMac OS X)。これを行うために、あなたは言いfor Library_Kind use "dynamic";ます。(動的ライブラリは必要な他のライブラリを認識していますが、それらの場所を認識していない可能性があるため、ローダーのライブラリ検索パス上に配置する必要があることに注意してください)。

2 番目の問題を回避する方法は、AdaCore がスタンドアロン ダイナミック ライブラリと呼ぶものを作成し、それを自動的に初期化することです。

これを行うには、2 つの属性を追加する必要があります。

  • for Library_Interface use (...);ライブラリの外に表示したいユニットの名前のリストを指定します。その結果、指定されたユニットのソースと.aliファイルのみがライブラリに含まれます。唯一の呼び出し元が C からのものである場合、おそらく 1 つだけ名前を付ける必要があります。
  • for Library_Auto_Init use "true";- これは実際にはデフォルトだと思います。

ちょっとした例を設定しました (Mac OS X、GNAT GPL 2014)。

サブディレクトリada

プロジェクトファイル、

library project Prj is
   for Languages use ("ada");
   for Library_Name use "test";
   for Library_Kind use "dynamic";
   for Library_Interface use ("hello");
   for Library_Auto_Init use "true";
   for Library_Src_Dir use "include";
   for Library_Dir use "lib";
   for Source_Dirs use (".");
   for Object_Dir use ".build";
end Prj;

こんにちは。

function Hello return Integer;
pragma Export (C, Hello, "Hello");

こんにちは。

with Number;
function Hello return Integer is 
begin
   delay 0.001;            -- so the tasking runtime gets called in
   return Number.Value;
end Hello;

number.ads、

package Number is
   pragma Elaborate_Body;
   Value : Integer := 0;   -- before elaboration
end Number;

およびnumber.adb

package body Number is
begin
   Value := 42;            -- after elaboration
end Number;

親ディレクトリ

プロジェクトファイル、

with "ada/prj";
project C_Main is
   for Source_Dirs use (".");
   for Languages use ("c");
   for Main use ("main.c");
   for Exec_Dir use ".";
   for Object_Dir use ".build";
end C_Main;

およびmain.c

#include <stdio.h>

extern int Hello(void);

int main() {
  int hello = Hello();
  printf("Hello returned %d.\n", hello);
  return 0;
}

ビルド

$ gprbuild -p -P c_main
gcc -c main.c
gcc -c -fPIC number.adb
gcc -c -fPIC hello.adb
gprlib test.lexch
gnatbind -n -o b__test.adb -Ltest -a /Users/simon/tmp/crychair/ada/.build/number.ali ...
gcc -c -x ada -gnatA -gnatws b__test.adb -o b__test.o ...
gcc -dynamiclib -shared-libgcc -o /Users/simon/tmp/crychair/ada/lib/libtest.dylib ... /Users/simon/tmp/crychair/ada/.build/number.o ...
ar cr libc_main.a ...
ranlib -c libc_main.a
gcc main.o -o main

そして実行:

$ ./main
Hello returned 42.

ライブラリを別のコンピューターの C ユーザーに配布するには、Ada ランタイムがまだインストールされていない場合、必要な Ada 共有ライブラリをパッケージ化libtest.so(または.dylib、または) する必要があります。.dll

Unix システムでは、ldd libtest.soYou're looking forlibgnat*.soとを使用してこれを見つけることができますlibgnarl*.so。これらは、コンパイラのオブジェクト検索パス (通常は、の出力のオブジェクト検索パス セクションの最後の行) で見つける必要がありますgnatls -v。通常、シンボリック リンクがあります。

libgnat.so       ->      libgnat.1.so
libgnat.1.so     ->      libgnat.1.0.0.so
libgnat.1.0.0.so         (the real thing)

共有ライブラリとシンボリックリンクをlibtest.so、たとえばのディレクトリに配置するとproduct/、ユーザーは次のようにリンクできるはずです

gcc main.c -o main -Lproduct -ltest

または多分

gcc main.c -o main -Lproduct -ltest -lgnat -lgnarl

OS によっては、生成された実行可能ファイルが実行時に共有ライブラリを見つけられない場合があります。

これを回避する 1 つの方法は、たとえば、ローダーが既に見える場所にライブラリを配置する/usr/local/libことです (この場合、 は必要ありません-Lproduct)。

もう 1 つの方法は、環境変数 ( LD_LIBRARY_PATHLinux の場合DYLD_LIBRARY_PATH、Mac OS X の場合) を設定して、どこを参照するかをローダーに指示することです。

3 番目の方法は、リンカにパスを実行可能ファイルに保存するように指示することです。

gcc main.c -o main -Lproduct -ltest -lgnat -lgnarl -Wl,-rpath,$PWD/product

Mac OS X で動作し、おそらく Linux でも動作します。

于 2014-11-08T19:33:02.357 に答える