Ich versuche, ein statisches Objekt zu erstellen, das in Go to interface mit einem C-Programm (z. B. einem Kernelmodul oder etwas anderem) geschrieben wurde.
Ich habe Dokumentation zum Aufrufen von C-Funktionen von Go aus gefunden, aber ich habe nicht viel darüber gefunden, wie man in die andere Richtung geht. Was ich gefunden habe ist, dass es möglich, aber kompliziert ist.
Folgendes habe ich gefunden:
Blogbeitrag über Rückrufe zwischen C und Go
Hat jemand Erfahrung damit? Kurz gesagt, ich versuche ein PAM-Modul zu erstellen, das vollständig in Go geschrieben ist.
c
shared-libraries
go
dynamic-linking
Beatgammit
quelle
quelle
Antworten:
Sie können Go-Code von C aus aufrufen. Dies ist jedoch verwirrend.
Der Prozess wird in dem Blog-Beitrag beschrieben, auf den Sie verlinkt haben. Aber ich kann sehen, dass das nicht sehr hilfreich ist. Hier ist ein kurzer Ausschnitt ohne unnötige Bits. Es sollte die Dinge etwas klarer machen.
Die Reihenfolge, in der alles aufgerufen wird, ist wie folgt:
Der Schlüssel, an den Sie sich erinnern sollten, ist, dass eine Rückruffunktion mit dem
//export
Kommentar auf der Go-Seite und wieextern
auf der C-Seite gekennzeichnet sein muss. Dies bedeutet, dass jeder Rückruf, den Sie verwenden möchten, in Ihrem Paket definiert werden muss.Damit ein Benutzer Ihres Pakets eine benutzerdefinierte Rückruffunktion bereitstellen kann, verwenden wir genau den gleichen Ansatz wie oben, stellen jedoch den benutzerdefinierten Handler des Benutzers (der nur eine reguläre Go-Funktion ist) als Parameter bereit, der an C übergeben wird Seite als
void*
. Es wird dann vom Callbackhandler in unserem Paket empfangen und aufgerufen.Lassen Sie uns ein fortgeschritteneres Beispiel verwenden, mit dem ich gerade arbeite. In diesem Fall haben wir eine C-Funktion, die eine ziemlich schwere Aufgabe ausführt: Sie liest eine Liste von Dateien von einem USB-Gerät. Dies kann eine Weile dauern, daher möchten wir, dass unsere App über den Fortschritt informiert wird. Wir können dies tun, indem wir einen Funktionszeiger übergeben, den wir in unserem Programm definiert haben. Es zeigt dem Benutzer einfach einige Fortschrittsinformationen an, wenn er aufgerufen wird. Da es eine bekannte Signatur hat, können wir ihm einen eigenen Typ zuweisen:
Dieser Handler verwendet einige Fortschrittsinformationen (aktuelle Anzahl der empfangenen Dateien und Gesamtzahl der Dateien) sowie einen Wert für die Schnittstelle {}, der alles enthalten kann, was der Benutzer benötigt.
Jetzt müssen wir die C and Go-Installation schreiben, damit wir diesen Handler verwenden können. Glücklicherweise ermöglicht uns die C-Funktion, die ich aus der Bibliothek aufrufen möchte, die Übergabe einer Benutzerdatenstruktur vom Typ
void*
. Dies bedeutet, dass es alles aufnehmen kann, was wir wollen, ohne dass Fragen gestellt werden, und wir werden es so wie es ist wieder in die Go-Welt zurückbringen. Damit dies alles funktioniert, rufen wir die Bibliotheksfunktion nicht direkt von Go aus auf, sondern erstellen einen C-Wrapper dafür, den wir benennen werdengoGetFiles()
. Dieser Wrapper liefert unseren Go-Rückruf zusammen mit einem Benutzerdatenobjekt an die C-Bibliothek.Beachten Sie, dass die
goGetFiles()
Funktion keine Funktionszeiger für Rückrufe als Parameter verwendet. Stattdessen wird der von unserem Benutzer bereitgestellte Rückruf in eine benutzerdefinierte Struktur gepackt, die sowohl diesen Handler als auch den eigenen Benutzerdatenwert des Benutzers enthält. Wir übergeben diesgoGetFiles()
als Benutzerdatenparameter.Das war's für unsere C-Bindungen. Der Code des Benutzers ist jetzt sehr einfach:
Das alles sieht viel komplizierter aus als es ist. Die Anrufreihenfolge hat sich im Gegensatz zu unserem vorherigen Beispiel nicht geändert, aber wir erhalten zwei zusätzliche Anrufe am Ende der Kette:
Die Reihenfolge ist wie folgt:
quelle
Es ist keine verwirrende Aussage, wenn Sie gccgo verwenden. Das funktioniert hier:
foo.go
bar.c
Makefile
quelle
go package main func Add(a, b string) int { return a + b }
erhalte ich den Fehler "undefined _go_string_plus"cgo
undgo
stattgccgo
. Siehe golang.org/cmd/cgo . Wenn dies gesagt ist, ist es vollständig möglich, den Typ "string" in der .go-Datei zu verwenden und Ihre .c-Datei so zu ändern, dass sie eine__go_string_plus
Funktion enthält. Dies funktioniert: ix.io/dZBDie Antwort hat sich mit der Veröffentlichung von Go 1.5 geändert
Diese SO-Frage, die ich vor einiger Zeit gestellt habe, behebt das Problem angesichts der 1.5 hinzugefügten Funktionen erneut
Verwenden von Go-Code in einem vorhandenen C-Projekt
quelle
Für mich ist das nicht möglich:
Quelle: https://github.com/golang/go/wiki/cgo
quelle