2016-11-29 47 views
4

我需要构建一个静态库,其中包含一些用Ada编写的代码,这些代码可以用C/C++编写的代码调用。如何从Ada源代码构建一个可从C++代码调用的静态库?

我已经通过互联网搜索,并得到了一些关于gnatmake,gnatbindgnatlink的知识,但仍然无法正确完成工作。

另外,我读过有些工具依赖某种项目文件。 我对这些不感兴趣,我只需要一堆命令来编写Makefile

+0

可能并不那么简单。必须编写Ada代码来与C++代码进行交互。不只是任何Ada代码都可以与C++代码进行交互。甚至在Ada代码与C++代码交互之后,必须做些什么,这与编译器有关。你使用哪种Ada编译器? –

+0

这个问题提到gnatmake等,所以很有可能它是GCC。 –

+0

@Simon Wright:的确如此。Ada代码没有什么奇特的,所以我没有遇到任何绑定它的问题。虽然调用代码是用C++编写的,但我添加了一个纯C层,以使整个过程更加简单。 – crimsonking

回答

7

这个答案假定您使用的是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.adbs/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 
+0

只是一个问题。 是以下内容: 程序Impl 与 约定=> C, 导出, External_Name =>“foo”; 相当于: 程序Impl; pragma EXPORT(CONVENTION => C, ENTITY => Impl, EXTERNAL_NAME =>“impl_c”); – crimsonking

+0

是的;它是Ada2012版本,具有方面。但当然这会是'EXTERNAL_NAME =>“foo”',而不是'“impl_c”'。 –

2

谢谢您很大的帮助! 实际上,它与下面的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),而链接。

+0

如果你要创建一个共享库('library.so'),你可能想用'-fpic'编译Ada(或者你的系统需要)。 _gnatmake_似乎在这里采取'-fpic' ... –

+0

@Simon Wright:确实。我省略了一堆开关(其中包括-fPIC),其中一些开关不知道它的含义,我一直在复制一个makefile到另一个。 :)谢谢你对这个的解释。 – crimsonking