Zuvor, als die Codebasis in C ++ war, hatte ich C ++ - Wrapper-Dateien, die mit der Codebasis verlinkten, und ich würde swig
(Version 3 für C ++ 11-Unterstützung) ausführen, um die Schnittstellendateien für das Ziel zu generieren Sprache (Python, JavaScript, C # usw.). Dann werden natürlich alle diese Dateien und Bibliotheken in ein gemeinsames Objekt kompiliert und aus den benötigten Sprachen aufgerufen. Jetzt wird die Codebasis in Rost geändert. Also zum Schlucken zur Arbeit habe ich folgendes:
no_mangle
- und extern
-Syntax für FFI
verwendet und in eine staticlib kompiliert. Jetzt benutze ich swig
für die C-Datei, erhalte die Schnittstellendatei für die Zielsprache, kombiniere alle Dateien (Schritte zwei und drei) und die SWIG-Schnittstellendatei) in ein gemeinsames Objekt und rufe aus der Zielsprache an.
Also:
Ist der Ansatz in Ordnung?
Ich kann freie Funktionen zum Arbeiten bekommen. Ich bin jedoch verwirrt darüber, wie man Mitgliedsfunktionen (Methoden) zum Laufen bringt. In C ++ ist der erste Parameter der Member-Funktionen der implizite this
-Zeiger. Also könnte ich ein void*
handle an die Klasse oder struct an die C-Schnittstelle zurückgeben, das es an andere weitergeben würde, die es speichern wollten (zB jsctypes für Firefox) und dann wieder reinterpret_cast
it an das konkrete / tatsächliche erhalten Geben Sie die Elementfunktion ein und rufen Sie sie auf. Wie mache ich das mit Rust?
z.B. für
%Vor% Wie greife ich dann auf diese Memberfunktionen auf ein Objekt von A
(sollte nicht verwaltet werden und auf dem Heap, denke ich?) von Zielsprachen (Python, C, etc.) oder einfach nur von einer C-Schnittstelle?
Nun, Methoden sind nur normale Funktionen, und wie Chris sagte, self
Argument hat eine implizite Verbindung mit Self
type. Mit Ihrem Beispiel (leicht modifiziert) mit Funktionen aus C-Code sollte einfach sein:
Beachten Sie, dass ich extern
hinzugefügt habe, um die Aufrufkonvention zu ändern, und #[no_mangle]
, um Namensfehlern und #[repr(C)]
in der Struktur zu vermeiden. Letzteres ist nicht notwendig, wenn Ihr Code Box
es der Struktur erzeugt und diese als rohe Zeiger an C übergeben. Ich bin mir jedoch nicht sicher, wie #[no_mangle]
die Trait-Methoden beeinflussen könnte, wenn es mehr als einen Trait-Implementierer gibt - wenn beide #[no_mangle]
haben, muss es einen Namenskonflikt geben.
Jetzt ist es einfach, diesen Typ und seine Funktionen aus C zu verwenden:
%Vor%Dieses Programm kompiliert und funktioniert:
%Vor% Wenn Methoden akzeptiert &mut self
:
Sie müssten const
weglassen:
Wenn Methoden akzeptiert self
:
Sie müssten die Struktur nach Wert übergeben:
%Vor%Wenn Sie die Struktur jedoch durch einen undurchsichtigen Zeiger verwenden, kann es schwierig sein, Funktionen aufzurufen, die diesen Wert annehmen, da C die genaue Größe der Struktur kennen muss. Nicht dass es mit undurchsichtigen Zeigern so üblich ist, glaube ich.
Ok, als ich in der akzeptierten Antwort bemerkte, dass ich diesen Ansatz nicht verwenden konnte, endete ich damit, etwas für andere zu kommentieren:
Der Backend-Rost-Code, der nach rlib
kompiliert wird:
Der Rost-Wrapper darüber, der auf die obige rlib
verweist und in staticlib
kompiliert (dh, .a
in Linux usw.):
Der C-Wrapper ( api.h & api.c
), der mit der obigen staticlib
verknüpft ist und bei Bedarf zu einem gemeinsamen Objekt kompiliert:
Führe jetzt einfach SWIG
über die C-Datei (ich habe nur die .c
-Datei veröffentlicht - du kannst die .h
erraten, über die SWIG läuft) für die Zielsprache, bekomme eine interface_wrap.c
generiert ( Standardname) und kompiliert diese Quellcode-Links, die gegen den staticlib
gerichtet sind, um ein Shared-Objekt zu erhalten.
ZB für Python:
%Vor%Rufen Sie jetzt einfach Python an und das Ganze funktioniert:
%Vor%Ich hoffe, dass jemand das nützlich findet und / oder Verbesserungsvorschläge machen kann. Ich habe dieses Ding auch an meinem github Repo arbeiten lassen: Ссылка