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

 手机用户2502931303 发布于 2022-12-12 16:34

我正在尝试创建一个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测试程序.最终我只需要提供库文件.命令行是最好的.我不想处理项目文件.

1 个回答
  • 创建静态库存在很大问题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()在所有库使用后调用(大多数人都不打扰).

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

    解决第二个问题的方法是创建AdaCore称为独立动态库的内容,并使其自动初始化.

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

    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)和所需的阿达共享库.

    在Unix系统上,你会发现这一点正在使用ldd libtest.so你正在寻找libgnat*.solibgnarl*.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).

    另一种方法是通过设置环境变量(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.

    2022-12-12 16:36 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有