スタティック ライブラリの作成には大きな問題があります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()
があり、ライブラリのすべての使用後に呼び出される必要があります (ほとんどの人は気にしません)。
最初の問題を回避する方法は、動的ライブラリを作成することです ( .dll
Windows、.so
Linux およびその他の Unix システム、.dylib
Mac 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.so
You'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_PATH
Linux の場合DYLD_LIBRARY_PATH
、Mac OS X の場合) を設定して、どこを参照するかをローダーに指示することです。
3 番目の方法は、リンカにパスを実行可能ファイルに保存するように指示することです。
gcc main.c -o main -Lproduct -ltest -lgnat -lgnarl -Wl,-rpath,$PWD/product
Mac OS X で動作し、おそらく Linux でも動作します。