2016-11-29 99 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