从 Ada 代码构建静态库,无需 GNAT 即可链接

2024-04-11

我正在尝试从 Ada 代码创建一个静态库,该库可以与一些 C 代码链接,而无需使用 GNAT 工具进行最终链接。我的用例是,我正在尝试将一个用 Ada 编写的库交付给一个为嵌入式目标构建的 C 代码库。为目标构建最终二进制文件的工具链不包含 GNAT 工具,因此需要能够在没有 GNAT 的情况下链接库。

当我尝试链接该库时,我收到很多有关未定义引用的错误。

这是一个最小的代码示例。C_Ada_Cross.gpr file:

project C_Ada_cross is
   for Library_Name use "MathFunc";
   for Source_Dirs use ("src", ".");
   for Object_Dir use "obj";
   for Library_Kind use "static";
   for Library_Interface use ("MathFunc_Ada");
   for Library_Src_Dir use "include";
   for Library_Dir use "lib";
end C_Ada_cross;

MathFunc_Ada.ads file:

with Interfaces.C; use Interfaces.C;

function MathFunc_Ada(a: C_Float; b: C_Float) return C_Float
    with 
        Export      => True,
        Convention  => C,
        External_Name => "MathFunc_Ada";

MathFunc_Ada.adb file:

with Ada.Numerics.Elementary_Functions; 
function MathFunc_Ada(a: C_Float; b: C_Float) return C_Float is
    use Ada.Numerics.Elementary_Functions;
begin
    return C_Float(sin(Float(a)) + cos(Float(b)));
end MathFunc_Ada;

main.c file:

#include <stdio.h>

extern float MathFunc_Ada(float a, float b);
extern void MathFuncinit();
extern void MathFuncfinal();

void main() {
  MathFuncinit();

  float a = 10.2;
  float b = 20.6;
  float c = MathFunc_Ada(a, b);
  
  printf("%f\n", c);
  MathFuncfinal();
}

为了构建,我执行了以下操作:

gprbuild -P C_Ada_cross.gpr # libMathFunc.a 
gcc main.c -L./lib -lMathFunc

这会产生大量错误,如下所示:

/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libMathFunc.a(p__MathFunc_0.o):MathFunc_Ada.a:(.text+0x20): undefined reference to `ada__numerics__elementary_functions__sin'
./lib/libMathFunc.a(p__MathFunc_0.o):MathFunc_Ada.a:(.text+0x20): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `ada__numerics__elementary_functions__sin'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libMathFunc.a(p__MathFunc_0.o):MathFunc_Ada.a:(.text+0x2f): undefined reference to `ada__numerics__elementary_functions__cos'
./lib/libMathFunc.a(p__MathFunc_0.o):MathFunc_Ada.a:(.text+0x2f): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `ada__numerics__elementary_functions__cos'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libMathFunc.a(p__MathFunc_0.o):b__mathfunc.ad:(.text+0x118): undefined reference to `system__secondary_stack__ss_stackIP'
./lib/libMathFunc.a(p__MathFunc_0.o):b__mathfunc.ad:(.text+0x118): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `system__secondary_stack__ss_stackIP'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libMathFunc.a(p__MathFunc_0.o):b__mathfunc.ad:(.text+0x14e): undefined reference to `__gnat_runtime_finalize'
./lib/libMathFunc.a(p__MathFunc_0.o):b__mathfunc.ad:(.text+0x14e): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__gnat_runtime_finalize'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libMathFunc.a(p__MathFunc_0.o):b__mathfunc.ad:(.text+0x265): undefined reference to `__gnat_runtime_initialize'
./lib/libMathFunc.a(p__MathFunc_0.o):b__mathfunc.ad:(.text+0x265): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__gnat_runtime_initialize'

和更多...

我也尝试过:

gcc main.c -L./lib -lMathFunc -lgnat -lgnarl -ldl

这会给出不同的未定义参考错误:

/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: /usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: DWARF error: can't find .debug_ranges section.
./lib/libgnat.a(adaint.o):adaint.c:(.text+0x38): undefined reference to `__imp__wsplitpath'
./lib/libgnat.a(adaint.o):adaint.c:(.text+0x38): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__imp__wsplitpath'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libgnat.a(adaint.o):adaint.c:(.text+0x480): undefined reference to `__mingw_vsprintf'
./lib/libgnat.a(adaint.o):adaint.c:(.text+0x480): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__mingw_vsprintf'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libgnat.a(adaint.o):adaint.c:(.text+0x4d5): undefined reference to `__imp__time64'
./lib/libgnat.a(adaint.o):adaint.c:(.text+0x4d5): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__imp__time64'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libgnat.a(adaint.o):adaint.c:(.text+0x4ec): undefined reference to `__imp__time64'
./lib/libgnat.a(adaint.o):adaint.c:(.text+0x4ec): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__imp__time64'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libgnat.a(adaint.o):adaint.c:(.text+0x4fc): undefined reference to `__imp__localtime64'
./lib/libgnat.a(adaint.o):adaint.c:(.text+0x4fc): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__imp__localtime64'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: ./lib/libgnat.a(adaint.o):adaint.c:(.text+0x54f): undefined reference to `__imp__gmtime64'

和更多...

最后一种方法与此处介绍的方法非常相似:https://stackoverflow.com/a/70036096/3979564 https://stackoverflow.com/a/70036096/3979564,但这对我不起作用。事实上,我什至尝试了那里提供的完全相同的代码和命令,但这给了我类似的错误。

我在寻找解决方案时发现了这个选项:http://www.white-elephant.ch/articles/AUJ%2042-3.pdf http://www.white-elephant.ch/articles/AUJ%2042-3.pdf,但是复制并重写原始 Ada 源文件似乎非常复杂。

鉴于 Ada 专注于嵌入式应用程序,在许多情况下静态链接是唯一的选择,我觉得必须有一种更简单的方法来构建静态库。

我错过了什么吗?有没有更简单的方法在 Ada 中构建静态库?


我认为您的目标 CPU 均受 Alire 支持gnat_arm_elf编译器:-mcpu=cortex-r5, cortex-a72;英飞凌 CPU(即使是价格超过 1 万英镑的 CPU!)都是 ARM Cortex。

毫无疑问,您的客户为 C 程序提供运行时支持,但这也有其局限性;例如,它是否提供printf?你如何进行日志记录?

您的客户对认证有什么要求? (好吧,可证明性)。如果问题很严重,您可能需要 AdaCore 支持合同。

你很可能不想提出例外;异常需要 Ada 运行时支持。另一方面,如果有人尝试,例如,该怎么办?除以零?你可以编译-gnatp抑制所有检查(实际上,我不确定例如越界数组访问检查是否会被抑制)。

我尝试从light-cortex-m4运行时,使用后alr toolchain --select安装gnat_arm_elf编译器。

第一次尝试mathfunc.gpr(Alire 坚持小写)可能是

project mathfunc is  -- alr insists on lower-case

   for Library_Name use "MathFunc";
   for Source_Dirs use ("src/");
   for Object_Dir use "obj";
   for Create_Missing_Dirs use "True";
   for Library_Interface use ("MathFunc_Ada");
   for Library_Src_Dir use "include";
   for Library_Dir use "lib";

   for Target use "arm-eabi";
   for Runtime ("ada") use "light-cortex-m4";

   package Compiler is
      for Default_Switches ("Ada") use ("-O2", "-gnatp", "-g");
   end Compiler;

   package Binder is
      for Switches ("Ada") use ("-n"); -- C main program
   end Binder;

end mathfunc;

(我不确定我们是否需要 Binder 开关-n).

以此构建,符号lib/libMathFunc.a are

$ arm-eabi-nm lib/libMathFunc.a

mathfunc_ada.o:
00000000 T MathFunc_Ada
         U __aeabi_fadd
         U ada__numerics__elementary_functions__cos
         U ada__numerics__elementary_functions__sin
00000000 D mathfunc_ada_E

b__mathfunc.o:
0000002c T MathFuncinit
         U __gnat_binder_ss_count
         U __gnat_default_ss_pool
         U __gnat_default_ss_size
00000014 R mathfunc_adaB
00000010 R mathfunc_adaS
         U mathfunc_ada_E
00000000 D mathfuncmain_E
00000000 T mathfuncmain__Tsec_default_sized_stacksBIP
00000068 T mathfuncmain___elabb
00000000 b mathfuncmain__sec_default_sized_stacks

所以你可以看到运行时需要__aeabi_fadd(可能来自 GCC 支持而不是 Ada)和很多东西b__mathfunc.o,它是由活页夹生成的,以支持我们请求的“独立库”支持,包括Library_Interface在探地雷达中。其中一部分与精细化有关。您也许无需任何详细说明就可以摆脱困境,但要付出一些可支持的 Ada 功能的代价。

建筑main,在子目录中main,用这个alire.toml

name = "main"

(omitted)

[[depends-on]]
mathfunc = "*"

[[pins]]
mathfunc = { path='..' }

还有这个探地雷达:

with "mathfunc";
project Main is

   for Languages use ("c");
   for Main use ("main.c");
   for Exec_Dir use ".";
   for Source_Dirs use (".");
   for Object_Dir use "obj";
   for Create_Missing_Dirs use "true";

   for Target use "arm-eabi";
   for Runtime ("ada") use "light-cortex-m4";

end Main;

由于未定义的引用,构建失败printf and MathFuncfinal;后者没有创建,但假设您不打算卸载静态库,这并不重要。

评论这些呼吁,我们得到

$ alr build
ⓘ Building main=0.1.0-dev/main.gpr...
Compile
   [c]            main.c
Link
   [archive]      libmain.a
   [index]        libmain.a
   [link]         main.c
/Users/simon/.cache/alire/dependencies/gnat_arm_elf_12.2.1_f4bfd822/bin/../lib/gcc/arm-eabi/12.2.0/../../../../arm-eabi/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000008000
Build finished successfully in 0.75 seconds.

失踪者在哪里_start这将是您和您的客户之间的问题(必须有一种方式让 C 程序启动!)。

Sizes:

$ arm-eabi-size main
   text    data     bss     dec     hex filename
  18024      42     674   18740    4934 main

对我来说,这看起来仍然很大,需要更多的调查。


在我的机器(Mac)上,运行时位于

$HOME/.cache/alire/dependencies/gnat_arm_elf_12.2.1_f4bfd822/arm-eabi/lib/gnat/light-cortex-m4

我不确定你需要ada_target_properties.

Ada 源码位于gnat/.

runtime.xml指定用于处理代码的编译器和链接器选项(也在重建库时使用)。

两个 GPR 用于构建运行时。


希望有点帮助!我意识到有很多东西需要消化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 Ada 代码构建静态库,无需 GNAT 即可链接 的相关文章

  • Ada 中的自定义“图像属性”?

    所以我有一件事 type Thing is new record elements end record 我有一个将其字符串化的函数 function ToString t Thing returns string 我希望能够告诉 Ada
  • “在此上下文中需要子类型标记”到底是什么?

    I get Subtype mark required in this context at 子类型掩码到底是什么 为什么它在这里抱怨 main adb Open Route Route 1 3 others gt new Location
  • 在 Ada 中创建子类型而不指定范围有什么意义?

    在Ada中 我经常看到这样的东西 type Number is new Integer 这有什么意义呢 难道你就不能快乐吗 Integer 我还看到过这样的代码 type Small Number is range 1 5 这对我来说是有道
  • 从 Ada 调用 scanf

    如何从 Ada 调用 scanf 也就是说 大概有一个适当的 pragma import 声明 但是声明会是什么样子呢 我感兴趣的是如何从 Ada 调用更难以驾驭的 C 函数 而不是如何解析字符串本身 所以我不是在寻找纯粹的 Ada 解决方
  • Ada:gnat gprbuild 如何链接到库中?

    在我正在处理的这个多语言 GPRBuild 项目中 我有一些 C 库文件 a 我需要链接到我的可执行文件中 是否有 gpr 属性告诉它链接什么或无论如何将 l L 开关传递给链接器 或者甚至更好 Project my library is
  • Ada 与 Netbeans

    我下载了 Netbeans 插件 用于使用 Ada 进行编程 但是 我不知道如何将Eclipse链接到Ada平台库 什么应该链接到 IDE lib 等 bin 我不知道该怎么办 安装后Ada 插件模块 http wiki netbeans
  • 是否可以声明具有无限上限的 Ada 范围?

    我想在 Ada 中声明记录类型的速度范围 下面的方法行不通 但是有没有办法让它工作呢 Speed in knots range 0 to unlimited Speed float Range 0 0 unlimited 我只想要这个数字的
  • 如何在 Ada 中从其他字符串构建字符串?

    我想在日志文件中输出标题行 然后在数据之前输出一行 为此 我创建了一个标题字符串 然后输出相同数量的 但下面的代码总是失败并出现 CONSTRAINT ERROR 因为生成的字符串不是 1024 个字符 在 Ada 中 字符串赋值需要完全相
  • 将从 C 例程分配的数组传递给 Ada

    将结构 记录数组从 Ada 传递到 C 例程是一回事 在本例中 内存管理是在 Ada 中完成的 但是在与第三方库接口时经常会出现这样的问题 内存管理是在C部分完成的 例如 对于 C 结构 typedef struct MYREC int n
  • 如何从 Ada 源构建可从 C++ 代码调用的静态库?

    我需要使用一堆用 Ada 编写的代码构建一个静态库 可以从用 C C 编写的代码中调用这些代码 我通过互联网搜索并了解了一些知识gnatmake gnatbind and gnatlink 但仍然无法正确完成工作 另外 我读到有些工具依赖于
  • 为什么字符串需要用初始值初始化?

    我有一根绳子lx String我想稍后在代码中设置该值 但出现错误unconstrained subtype not allowed need initialization provide initial value or explicit
  • 在 Ada 中实现具有访问类型的抽象函数

    我有一个名为 Statements 的包 其中包含一个名为 Statement 的抽象类型和一个名为execute 的抽象函数 在另一个包中 我有一个CompoundStatement 类型 它是一个Statement 类型 它实现了exe
  • 标准 ada 包含路径是什么

    我在使用 apt get 安装的 Ubuntu 上使用 gnat 4 6 我需要知道在哪里安装下载的库 例如APQ http sourceforge net projects apq 我应该设置什么ADA INCLUDE PATH and
  • 从 Ada 访问 c 常量

    我有一个带有这样类型定义的头文件 ifndef SETSIZE define SETSIZE 32 endif typedef struct set unsigned array SETSIZE set t 要使用相应的 C 函数 我需要在
  • Ada95 中的线程和信号量

    如何在 Ada95 中使用线程 我可以使用哪些函数来创建 销毁 停止和启动它们 我如何在这种语言中使用信号量 并发性内置于该语言中 因此您可以为任务 即线程 和受保护对象 即比信号量 互斥体 条件变量更强大 使用特定的 Ada 语法 这使得
  • Ada T'Class 的基础知识

    虽然有点不好意思问这个问题 但我知道这是最好的 我已经使用 Ada 编程很多年了 并且几乎可以流利地理解该语言的每个部分 然而 我似乎始终无法完全理解 T Class 借用别人的话 有人可以 像我五岁一样解释一下吗 编辑 我买它只是为了拥有
  • 使用 SPARK 证明选择排序算法

    我试图证明我在 Ada 中的选择排序实现是正确的 我尝试了一些循环不变量 但使用 gnatprove 只能证明内部循环的不变量 package body Selection with SPARK Mode is procedure Sort
  • 如何在 Ada 中直接访问内存地址?

    所以我是 Ada 的新手 我正在尝试在其中编写内核 但我似乎找不到任何关于如何正确执行此操作的好信息 在 C 语言中 我会这样写 unsigned char videoram char 0xB8000 videoram 0 65 直接访问视
  • ‘access’参数模式有什么用处?

    Ada 中有三种传递参数的 正常 模式 in out and in out 但还有第四种模式 access 有什么需要它们的吗 即 否则不可能实现的事情 现在 我确实知道 GNAT JVM Ada 编译器在导入的 库 规范中大量使用了它们
  • 在 Ada 中定义通用标量类型包

    我想通过制作一个用于操作多项式的 Ada 包来测试编写 Ada 包的水 可以为多种代数结构定义多项式 因此为了反映这一点 我想使该包通用 以便它可以与浮点数 整数或其他数字子类型一起使用 我现在想说 我对 Ada 的类型系统如何工作或者它的

随机推荐

  • MATLAB - 相关属性和计算

    假设我有以下类来计算二次方程的解 classdef MyClass lt handle properties a b c end properties Dependent true x end methods function x get
  • Multer文件上传错误,请求挂起

    我以前从未写过问题 因为我总是在提问之前在这里找到问题的答案 然而 我在 Express 上的文件上传 POST 路由上的 fileFilter 函数上遇到了困难 我在路由中使用了 multer 上传功能 也作为中间件 后面有一个错误处理中
  • httrack wget 卷曲抓取和获取

    互联网上有许多工具可用于下载网站的静态副本 例如 HTTrack 还有许多工具 其中一些是商业工具 用于从网站 抓取 内容 例如 Mozenda 还有一些显然内置于 PHP 和 nix 等程序中的工具 您可以在其中 file get con
  • 如何获取多个输入Python [重复]

    这个问题在这里已经有答案了 我正在用 Python 编写一个程序 我想在其中执行以下操作 我通过写作要求特定的输入 x int input 现在 给定我分配给该输入的数字 N 我将获得 N 行请求新输入 例如 如果我输入数字 3 我希望程序
  • 在正方形内绘制 geom_tile 边框以防止重叠

    我希望能够绘制边界geom tile它们不重叠 因此边界可以传达自己的信息 而不会因边界消失而使观看者感到困惑 library ggplot2 state lt data frame p runif 100 x 1 10 y rep 1 1
  • 如何在 Windows 10 上为 conda 初始化 shell?

    当我跑步时conda init cmd exe在正常或管理模式下 我收到以下错误 WARNING Cannot install xonsh wrapper without a python interpreter in prefix C U
  • 如何在 git 的另一个分支上创建一个分支中的快照副本(提交)?

    当我开始使用 Git 时 我首先了解到的一件事是 Git 并不将信息存储为基于文件的更改 补丁 列表 而是存储为快照流 提交是所有存储库的快照 考虑我们在存储库中有两个分支 Branch A 和 Branch B 无论它们之间的关系如何 它
  • 具有链接到同一主键的多个外键的表 (2)

    只是为了扩展我的上一期 我的数据库中有两个表 我想提取某些信息 下表 player player id primary playerName match match id primary playerID1 playerID2 player
  • 计算一组的比例

    我正在尝试计算数据帧中组总数中每条记录的分数 我的数据如下 我有车站 月份和 PHylum 的因素 然后是总数 我想将总数显示为相对百分比 因此基本上是按车站和月份对总数进行求和 然后应用原始表格 在 R 中 我得到了 bn phyla g
  • Material UI - 更改焦点上文本字段的颜色

    我正在尝试更改文本字段中标签文本的颜色 但我似乎无法弄清楚 这是我正在尝试的
  • 如何在 tkinter 中显示 markdown 格式文本?

    In python 3 x with tkinterGUI 我开发了一个带有常规简单窗口的程序 我想展示一个markdown格式字符串保存在名为的字符串中markdownText在程序窗口上 markdownText italic or b
  • UISegmentedControl 颜色问题 - 颜色在模拟器上显示正常,但在设备上显示不正常

    FIXED 你不会相信它 这是一个 Winterboard 主题搞乱了它 混蛋 禁用主题瞧 效果完美 对于任何感兴趣的人来说 所讨论的主题是 Ayecorn 不酷 希望这对遇到同样问题的其他人有所帮助 抱歉各位 感谢您的所有投入 这里很棒的
  • 如何将复杂的 HTML 表单发布为 JSON?

    我的网页中有一个非常复杂的表单 用户实际上构建了一个复杂的对象 UI 使用 jQuery 进行处理 显示 隐藏部分 复制和删除子表单 尽管可能 但简单地在用户提交时发布表单似乎并不是最好的解决方案 为字段 可以有对象数组 创建唯一的名称并在
  • 将 UINavigationController 添加到现有的 UIViewController

    如何将现有的 UIViewController 使用presentModalViewController 呈现 添加到 UINavigationController 当用户点击按钮时 需要推送我的详细视图的新副本 换句话说 pushView
  • 计算数组属性的内存语义?

    这是一个允许用户标记事物的应用程序 标签只是字符串 一个数组TagHolder对象保存应用程序中使用的所有标签的列表 并用一个布尔值告诉是否选择了该标签 但这是一个实现细节 外部接口调用两个方法 selectedTags and setSe
  • 将属性和值从第 4 个父节点填充到 XML 文件的所有父节点

    我是 XSLT 新手 希望将相同的属性和值添加到从第二个父节点开始的所有父节点 这里的逻辑应该是 如果存在主节点 则属性 Mainattribute 应该是一次 并且对于主节点下的所有父节点的其余部分应该具有不同的属性 childattri
  • 创建二进制 PBM/PGM/PPM

    我试图了解如何创建二进制 PBM PGM PPM 文件 据我所知 每种格式有两种类型 普通格式和原始格式 例如 黑色 PBM 5x5 的结构如下所示 P1 This is a comment 5 5 1 1 1 1 1 1 1 1 1 1
  • Visual Studio 2015 如何禁用异常输出

    我正在制作一个带有更新和绘制的 C 应用程序 我发现更新确实很慢 尽管没有任何沉重的表达 在独立于 Visual Studio 启动我的应用程序后 我发现它的速度快了 100 倍 问题是 对于每个 try catch VStudio 都会在
  • 使用 asp:Button 将参数传递到函数中

    我正在尝试将参数传递给函数onClick of an asp Button
  • 从 Ada 代码构建静态库,无需 GNAT 即可链接

    我正在尝试从 Ada 代码创建一个静态库 该库可以与一些 C 代码链接 而无需使用 GNAT 工具进行最终链接 我的用例是 我正在尝试将一个用 Ada 编写的库交付给一个为嵌入式目标构建的 C 代码库 为目标构建最终二进制文件的工具链不包含