gpt4 book ai didi

c - 如何创建 ada lib.a 并链接到 C

转载 作者:太空狗 更新时间:2023-10-29 17:21:18 25 4
gpt4 key购买 nike

我正在尝试创建一个 ada 库并尝试了一些不同的东西。我尝试使用 makefile 编译项目并尝试从所有 .o 文件创建一个库这似乎没有按预期工作。然后我询问了 adacore 支持,他们向我指出了为 ada 和 c 项目使用 .gpr 文件以及在 ada.gpr 中应该创建一个库的方向。这几乎成功了,但是当它尝试编译 ada 时,我得到了 undefined reference 。

我尝试过的:命令行:

ar rc libmy_lib.a *.o

当我尝试读取库中的内容时

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 个不同的错误:首先是对一些包的 undefined reference ,这些包是我的 ada 代码的一部分,然后出现在我不知道存在的 gnat .adb 文件中。我觉得图书馆太破了。其次是某些包的字段无法找到/不存在,即使代码可以正常编译并运行。它给我错误,指出 ada 代码中不存在这些字段。

总而言之:我在 3 个不同的目录中有一个 ada 项目,我想从它们创建一个库。然后链接到 C 测试程序。最终我只需要提供库文件。最好是命令行。我不想处理项目文件。

最佳答案

创建静态库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 代码必须在调用库的任何接口(interface)之前调用该函数,并且testfinal() 在库的所有使用之后调用(大多数人不会打扰)。

解决第一个问题的方法是创建一个动态库(.dll 在 Windows 上,.so 在 Linux 和其他 Unix 系统上,.dylib 在 Mac OS X 上)。为此,您说 for Library_Kind use "dynamic";(注意,虽然动态库知道它需要什么其他库,但它可能不知道在哪里可以找到它们,因此您必须将它们安排在加载程序的库搜索路径上)。

解决第二个问题的方法是创建 AdaCore 所称的 standalone dynamic library , 并让它自动初始化。

为此,您需要添加两个属性:

  • for Library_Interface use (...); 指定您希望在图书馆外可见的单位名称列表。效果是在库中只包含命名单元的源文件和 .ali 文件;如果只有来自 C 的来电者,您可能只需要说出一个。
  • Library_Auto_Init 使用“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");

你好.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*.solibgnarl*.so 。您应该在编译器的对象搜索路径中找到它们(通常是 gnatls -v 输出的对象搜索路径部分的最后一行)。通常会有符号链接(symbolic link):

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

将共享库和符号链接(symbolic link)放在带有 libtest.so 的目录中,例如 product/,然后您的用户应该能够链接到

gcc main.c -o main -Lproduct -ltest

或者也许

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

根据您的操作系统,生成的可执行文件可能无法在运行时找到共享库。

解决这个问题的一种方法是将库放在加载程序已经找到的地方,例如 /usr/local/lib(在这种情况下你不需要 -Lproduct).

另一种方法是通过设置环境变量(LD_LIBRARY_PATH 在 Linux 上,DYLD_LIBRARY_PATH 在 Mac OS X 上)告诉加载程序在哪里查找。

第三种方法是告诉链接器将路径保存在可执行文件中:

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

适用于 Mac OS X,可能适用于 Linux。

关于c - 如何创建 ada lib.a 并链接到 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26805533/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com