2016-11-29 3 views
4

Ich muss eine statische Bibliothek mit einer Reihe von Code in Ada geschrieben, die aus Code in C/C++ geschrieben aufgerufen werden können.Wie erstellt man eine statische Bibliothek von Ada-Quelle, die aus C++ - Code aufgerufen werden kann?

Ich habe über das Internet gesucht und etwas Wissen über gnatmake, gnatbind und gnatlink bekommen, aber immer noch kann die Arbeit nicht richtig erledigt werden.

Außerdem habe ich gelesen, dass es Werkzeuge gibt, die auf einer Art Projektdatei beruhen. Ich bin nicht daran interessiert, ich brauche nur eine Reihe von Befehlen in eine Makefile schreiben.

+0

Es mag nicht so einfach sein. Der Ada-Code muss für die Schnittstelle mit C++ - Code geschrieben werden. Nicht jeder Ada-Code kann mit C++ - Code interagieren. Was getan werden muss, selbst nachdem der Ada-Code zur Schnittstelle mit C++ - Code gemacht wurde, ist etwas vom Compiler abhängig. Welchen Ada Compiler benutzen Sie? –

+0

Die Frage erwähnt Gnatmake etc, also gibt es eine gute Chance, dass es GCC ist. –

+0

@Simon Wright: Genau. Der Ada-Code ist nichts Besonderes, also habe ich kein Problem damit verbunden. Obwohl der aufrufende Code in C++ geschrieben ist, habe ich eine reine C-Ebene hinzugefügt, um den gesamten Prozess zu vereinfachen. – crimsonking

Antwort

7

In dieser Antwort wird davon ausgegangen, dass Sie die GCC-Toolchain verwenden.

Die große Hürde ist, dass Ada-Code Ausarbeitung benötigt (etwa das Äquivalent zum Aufrufen von Konstruktoren auf Dateiebene in C++). gnatbind ist das Werkzeug, das dies tut, und Sie die Flagge -L:

-Lxyz  Library build: adainit/final renamed to xyzinit/final, implies -n 
[...] 
-n  No Ada main program (foreign main routine) 

Als Beispiel betrachten wir foo.ads Ada Quelle,

package Foo is 
    procedure Impl 
    with 
    Convention => C, 
    Export, 
    External_Name => "foo"; 
end Foo; 

oder, bei Verwendung von Ada vor Ada2012,

package Foo is 
    procedure Impl; 
    pragma Export (Convention => C, Entity => Impl, External_Name => "foo"); 
end Foo; 

und 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; 

und ein ähnliches Paar Dateien bar.ads, bar.adb (s/foo/bar/g überall).

diese Kompilieren:

gnatmake foo bar 

Bind:

gnatbind -Lck -o ck.adb foo.ali bar.ali 

(dies wird ck.ads tatsächlich generieren sowie die Namen ck.adb, das sind der Code, der die Ausarbeitung der Fall ist).

die Ausarbeitung Code kompilieren:

gnatmake ck.adb 

die Bibliothek generieren:

ar cr ck.o foo.o bar.o 

und du bist fast bereit zu rollen.

Das Hauptprogramm C könnte wie

aussehen
#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; 
} 

(Haupt ist in C++, so dass Sie extern "C" { ..., natürlich benötigen).

Sie würden denken, dass

gcc main.c libck.a 

den Trick tun würde. In der Ada-Laufzeit ruft jedoch libck auf.Hier (macOS), das heißt, ich sage

gcc main.c libck.a /opt/gnat-gpl-2016/lib/gcc/x86_64-apple-darwin14.5.0/4.9.4/adalib/libgnat.a 

(Sie können diesen Weg finden mit gcc --print-libgcc-file-name)

Die resultierenden ausführbaren Datei ausgeführt wird:

$ ./a.out 
bar is elaborated 
foo is elaborated 
calling foo: 
I am foo 
calling bar: 
I am bar 
+0

Nur eine Frage. Ist das Folgende: Verfahren Impl mit Konvention => C, Export, External_Name => "foo"; Entspricht: Verfahren Impl; pragma EXPORT (ÜBEREINSTIMMUNG => C, ENTITY => Impl, EXTERNAL_NAME => "impl_c"); – crimsonking

+0

Ja; Es ist die Ada2012-Version mit Aspekten. Aber das wäre natürlich 'EXTERNAL_NAME =>" foo "', nicht '" impl_c "'. –

2

Vielen Dank für Ihre große Hilfe! Eigentlich ist es mit dem folgende Makefile gearbeitet:

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) 

Außerdem hatte ich meine Funktion als extern „C“ in meiner C++ Datei zu erklären.

Vielen Dank, ich war fast da, aber verpasst, um die Ada-Laufzeitbibliotheken (-lgnat -lgnarl) während der Verknüpfung enthalten.

+0

Wenn Sie eine gemeinsam genutzte Bibliothek ('library.so') erstellen möchten, können Sie die Ada mit' -fpic' (oder was auch immer Ihr System benötigt) kompilieren. _gnatmake_ scheint hier "-fpic" zu nehmen ... –

+0

@Simon Wright: In der Tat. Ich habe eine Reihe von Schaltern weggelassen (-fPIC unter ihnen), einige davon kopiere ich von einem Makefile zu einem anderen, ohne seine Bedeutung zu kennen. :) Danke für die Erklärung von diesem. – crimsonking

Verwandte Themen