我需要构建一个静态库,其中包含一些用Ada编写的代码,这些代码可以用C/C++编写的代码调用。如何从Ada源代码构建一个可从C++代码调用的静态库?
我已经通过互联网搜索,并得到了一些关于gnatmake
,gnatbind
和gnatlink
的知识,但仍然无法正确完成工作。
另外,我读过有些工具依赖某种项目文件。 我对这些不感兴趣,我只需要一堆命令来编写Makefile
。
我需要构建一个静态库,其中包含一些用Ada编写的代码,这些代码可以用C/C++编写的代码调用。如何从Ada源代码构建一个可从C++代码调用的静态库?
我已经通过互联网搜索,并得到了一些关于gnatmake
,gnatbind
和gnatlink
的知识,但仍然无法正确完成工作。
另外,我读过有些工具依赖某种项目文件。 我对这些不感兴趣,我只需要一堆命令来编写Makefile
。
这个答案假定您使用的是GCC工具链。
最大的障碍是Ada代码需要细化(大致相当于在C++中调用文件级构造函数)。 gnatbind是做这个的工具,并使用该标志-L
:
-Lxyz Library build: adainit/final renamed to xyzinit/final, implies -n
[...]
-n No Ada main program (foreign main routine)
作为一个例子,考虑阿达源foo.ads
,
package Foo is
procedure Impl
with
Convention => C,
Export,
External_Name => "foo";
end Foo;
,或者,如果使用阿达之前Ada2012,
package Foo is
procedure Impl;
pragma Export (Convention => C, Entity => Impl, External_Name => "foo");
end Foo;
和foo.adb
,
with Ada.Text_IO;
package body Foo is
procedure Impl is
begin
Ada.Text_IO.Put_Line ("I am foo");
end Impl;
begin
Ada.Text_IO.Put_Line ("foo is elaborated");
end Foo;
和一对类似的文件bar.ads
,bar.adb
(s/foo/bar/g
全文)。
编译这些:
gnatmake foo bar
绑定:
gnatbind -Lck -o ck.adb foo.ali bar.ali
(这实际上会产生ck.ads
以及命名ck.adb
;这些是不拟订的代码)。
编译阐述代码:
gnatmake ck.adb
生成库:
ar cr ck.o foo.o bar.o
和你差不多准备推出。
的C主程序看起来像
#include <stdio.h>
void ckinit(void);
void foo(void);
void bar(void);
int main()
{
ckinit();
printf("calling foo:\n");
foo();
printf("calling bar:\n");
bar();
return 0;
}
(你的主要是C++,所以你需要extern "C" {
...,当然)。
你会认为
gcc main.c libck.a
会做的伎俩。但是,在Ada运行时中调用libck
。这里(MacOS的),这意味着我说
gcc main.c libck.a /opt/gnat-gpl-2016/lib/gcc/x86_64-apple-darwin14.5.0/4.9.4/adalib/libgnat.a
生成的可执行文件运行(您可以使用gcc --print-libgcc-file-name
找到路径):
$ ./a.out
bar is elaborated
foo is elaborated
calling foo:
I am foo
calling bar:
I am bar
只是一个问题。 是以下内容: 程序Impl 与 约定=> C, 导出, External_Name =>“foo”; 相当于: 程序Impl; pragma EXPORT(CONVENTION => C, ENTITY => Impl, EXTERNAL_NAME =>“impl_c”); – crimsonking
是的;它是Ada2012版本,具有方面。但当然这会是'EXTERNAL_NAME =>“foo”',而不是'“impl_c”'。 –
谢谢您很大的帮助! 实际上,它与下面的Makefile工作:
ada_libs := -lgnat -lgnarl
cpp_src := ...
ada_src := ...
library.so : $(cpp_src:.cc=.o) adalib.a
g++ -o [email protected] $^ $(ada_libs)
$(cpp_src:.cc=.o) : %.o : %.cc
g++ -c -o [email protected] $<
$(cpp_src:.cc=.d) : %.d : %.cc
g++ -MM -MF [email protected] $^
$(addprefix objects/,$(ada_src:.adb=.o)) : objects/%.o : %.adb
gnatmake -c -D objects $^
adabind.adb : $(addprefix objects/,$(ada_src:.adb=.o))
gnatbind -n -o [email protected] $(^:.o=.ali)
adabind.ali : adabind.adb
gnatmake -c -D objects $^
adalib.a : adabind.ali
ar cur [email protected] $(^:.ali=.o) objects/*.o
include $(cpp_src:.cc=.d)
除此之外,我不得不宣布我的功能在我的C++文件的extern“C”。
非常感谢您,我几乎在那里,但错过了包含ada运行时库(-lgnat -lgnarl),而链接。
如果你要创建一个共享库('library.so'),你可能想用'-fpic'编译Ada(或者你的系统需要)。 _gnatmake_似乎在这里采取'-fpic' ... –
@Simon Wright:确实。我省略了一堆开关(其中包括-fPIC),其中一些开关不知道它的含义,我一直在复制一个makefile到另一个。 :)谢谢你对这个的解释。 – crimsonking
可能并不那么简单。必须编写Ada代码来与C++代码进行交互。不只是任何Ada代码都可以与C++代码进行交互。甚至在Ada代码与C++代码交互之后,必须做些什么,这与编译器有关。你使用哪种Ada编译器? –
这个问题提到gnatmake等,所以很有可能它是GCC。 –
@Simon Wright:的确如此。Ada代码没有什么奇特的,所以我没有遇到任何绑定它的问题。虽然调用代码是用C++编写的,但我添加了一个纯C层,以使整个过程更加简单。 – crimsonking