如何构建无需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
相关产品推荐
相关产品推荐

