我正在尝试创建一个ada库并尝试了一些不同的东西。 我尝试使用makefile编译项目并尝试从所有.o文件创建一个库 这似乎没有按预期工作。 然后我问了adacore的支持,他们指出了我为ada和c项目使用.gpr文件的方向,以及应该创建一个库的ada.gpr文件。这几乎起作用,但是当它试图编译ada时,我得到了未定义的引用。
我尝试过: 命令行:
ar rc libmy_lib.a *.o
当我尝试阅读lib中的内容时
ld libmy_lib.a
我收到此错误 ld:警告:找不到入口符号_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文件,我不知道存在。我这么破坏的图书馆。 其次是某些包的字段无法找到/不存在,即使代码编译正常并运行。它给出了错误,指出字段在ada代码中不存在。
TLDR: 我在3个不同的目录中有一个ada项目,我想从它们创建一个库。然后链接到C测试程序。最终我只需要提供库文件。命令行是最好的。我不想处理项目文件。
答案 0 :(得分:7)
创建静态库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
其次,Ada代码可能(将!)需要详细说明,在程序启动时完成。当gprbuild
创建库时,它会添加函数testinit()
,在调用库的任何接口之前,您的C代码必须调用,并且testfinal()
将被调用图书馆的使用(大多数人都不打扰)。
解决第一个问题的方法是在Windows上创建动态库(.dll
,在Linux和其他Unix系统上创建.so
,在Mac OS X上创建.dylib
。为此,您说for Library_Kind use "dynamic";
。 (注意,尽管动态库知道它需要哪些其他库,但它可能不知道在哪里找到它们,所以你必须安排它们在加载器的库搜索路径上) 的
解决第二个问题的方法是创建AdaCore调用standalone dynamic library的内容,并让它自动初始化。
要执行此操作,您需要添加两个属性:
for Library_Interface use (...);
指定您希望在库外可见的单位名称列表。效果是仅包括指定的单位'库中的源文件和.ali
文件;如果只有来自C的呼叫者,你可能只需要命名一个。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;
hello.ads,
function Hello return Integer;
pragma Export (C, Hello, "Hello");
hello.adb,
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运行时,您需要打包libtest.so
(或.dylib
或.dll
)和需要Ada共享库。
在Unix系统上,您可以使用ldd libtest.so
找到它。您正在寻找libgnat*.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
根据您的操作系统,生成的可执行文件可能无法在运行时找到共享库。
这方面的一个方法是将库放在加载器已经看到的位置,例如/usr/local/lib
(在这种情况下,您不需要-Lproduct
)。
另一种方法是通过在Linux上设置环境变量LD_LIBRARY_PATH
,在Mac OS X上设置DYLD_LIBRARY_PATH
来告诉加载程序在哪里查看。
第三种方法是告诉链接器将路径保存在可执行文件中:
gcc main.c -o main -Lproduct -ltest -lgnat -lgnarl -Wl,-rpath,$PWD/product
适用于Mac OS X,可能适用于Linux。