You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构建无需GNAT工具链即可与C/C++链接的Ada静态库

报错原因

你遇到的未定义引用是因为Ada静态库默认没有打包GNAT运行时的依赖:

  • __gnat_rcheck_CE_Overflow_Check 属于GNAT运行时的运行时检查模块,负责Ada代码的溢出检查逻辑
  • ada__text_io__put_line__2 属于Ada标准库的Text_IO模块
    两类符号都没有被包含到你生成的libMy_Ada_Lib.a中,因此链接时会报缺失。
方案1:打包完整静态依赖,交付给无GNAT环境的开发者(推荐)

该方案可以生成无外部GNAT依赖的独立静态库,下游开发者不需要安装GNAT工具链即可直接使用。

步骤1:修改GPR项目配置

更新ada_lib_project.gpr内容:

library project ada_lib_project is
    for Languages use ("Ada");
    for Library_Name use "My_Ada_Lib";
    for Library_Dir use "my_generated_lib";
    for Library_Kind use "Static";
    -- 仅导出你声明的C接口,避免内部Ada符号冲突
    for Library_Interface use ("adatestpacket");
    -- 静态链接GCC和GNAT运行时
    for Library_Options use ("-static-libgcc", "-static-libgnat");
    package Compiler is
        -- 生成位置无关代码,适配C项目链接到可执行或动态库的需求
        for Default_Switches ("Ada") use ("-fPIC");
    end Compiler;
end ada_lib_project;

步骤2:补充Ada运行时初始化/销毁接口

Ada代码运行前需要初始化运行时环境,使用完成后需要销毁回收资源,因此需要在adatestpacket.ads中新增两个C可调用的接口:

with Interfaces.C; use Interfaces.C;
package adatestpacket is
  -- 运行时初始化,C代码调用任何Ada接口前必须先调用一次
  procedure init_ada_runtime with
    Export, Convention => C, External_Name => "init_ada_runtime";
  -- 运行时销毁,C代码用完所有Ada接口后调用
  procedure finalize_ada_runtime with
    Export, Convention => C, External_Name => "finalize_ada_runtime";

  procedure adatest with
    Export, Convention => C, External_Name => "adaTest";

  function add5(x: in int) return int with
    Export, Convention => C, External_Name => "add5";
end adatestpacket;

在adatestpacket.adb中实现这两个接口:

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;
package body adatestpacket is
  -- 导入GNAT自带的运行时初始化/销毁函数
  procedure adainit with Import, Convention => C, External_Name => "adainit";
  procedure adafinal with Import, Convention => C, External_Name => "adafinal";

  procedure init_ada_runtime is
  begin
    adainit;
  end init_ada_runtime;

  procedure finalize_ada_runtime is
  begin
    adafinal;
  end finalize_ada_runtime;

  procedure adatest is
  begin
    Put_Line("This is executed ADA/SPARK-Code...");
    null;
  end adatest;

  function add5(x: in int) return int is
  begin
    return x + 5;
  end add5;
end adatestpacket;

步骤3:修改C调用代码

调整main.c增加运行时初始化和销毁逻辑:

#include <stdio.h>

extern void init_ada_runtime();
extern void finalize_ada_runtime();
extern void adaTest();
extern int add5(int);

int main(){
  init_ada_runtime();
  adaTest();
  int b = add5(2);
  printf("--> %d \ndone.\n", b);
  finalize_ada_runtime();
  return 0;
}

步骤4:编译并合并所有依赖到静态库

执行以下命令编译并打包完整依赖:

# 编译C目标文件
gcc -c main.c -o main.o
# 编译Ada静态库
gprbuild -P ada_lib_project.gpr
# 查询GNAT运行时库路径
GNAT_LIB_PATH=$(gnatls -v | grep adalib | awk '{print $2}')
# 进入生成的库目录
cd my_generated_lib
# 提取GNAT运行时的目标文件
ar x ${GNAT_LIB_PATH}/libgnat.a
ar x ${GNAT_LIB_PATH}/libgnarl.a
# 合并所有目标文件到最终的静态库
ar rcs libMy_Ada_Lib.a *.o
# 清理临时文件
rm *.o
cd ..

最终链接

下游开发者无需安装GNAT,直接执行以下命令即可链接:

gcc main.o -L my_generated_lib -l My_Ada_Lib -o a.out
方案2:本机有GNAT环境时的临时测试方案

如果你只是在本机测试,不需要对外交付库,直接在链接时补充GNAT运行时依赖即可,无需修改Ada代码:

gcc main.o -L my_generated_lib -l My_Ada_Lib -lgnat -lgnarl -L $(gnatls -v | grep adalib | awk '{print $2}') -o a.out
额外优化建议

如果你的Ada代码不需要使用标准库、异常检查等功能,可以选择GNAT的零 footprint 运行时(ZFP),生成的静态库体积更小,几乎没有额外依赖,更适合嵌入式、高性能无依赖场景。

内容的提问来源于stack exchange,提问作者eX0r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 16:45:03