我需要構建一個靜態庫,其中包含一些用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