Próbuję utworzyć obiekt statyczny napisany w Idź do interfejsu z programem C (powiedzmy, moduł jądra lub coś w tym rodzaju).
Znalazłem dokumentację dotyczącą wywoływania funkcji C z Go, ale nie znalazłem zbyt wiele na temat tego, jak przejść w drugą stronę. Odkryłem, że jest to możliwe, ale skomplikowane.
Oto co znalazłem:
Wpis na blogu dotyczący wywołań zwrotnych między C i Go
Post na liście mailingowej Golang
Czy ktoś ma z tym doświadczenie? Krótko mówiąc, próbuję stworzyć moduł PAM napisany w całości w Go.
c
shared-libraries
go
dynamic-linking
beatgammit
źródło
źródło
Odpowiedzi:
Możesz wywołać kod Go z C. jest to jednak myląca propozycja.
Proces jest opisany w poście na blogu, do którego prowadzi łącze. Ale widzę, że nie jest to zbyt pomocne. Oto krótki fragment bez zbędnych bitów. Powinno to trochę wyjaśnić.
Kolejność, w jakiej wszystko się nazywa, jest następująca:
Kluczem do zapamiętania jest tutaj to, że funkcja zwrotna musi być oznaczona
//export
komentarzem po stronie Go iextern
po stronie C. Oznacza to, że każde wywołanie zwrotne, którego chcesz użyć, musi być zdefiniowane w pakiecie.Aby umożliwić użytkownikowi twojego pakietu dostarczenie niestandardowej funkcji zwrotnej, używamy dokładnie tego samego podejścia, co powyżej, ale dostarczamy niestandardową procedurę obsługi użytkownika (która jest zwykłą funkcją Go) jako parametr, który jest przekazywany do C strona jak
void*
. Następnie jest odbierany przez callbackhandler w naszym pakiecie i wywoływany.Skorzystajmy z bardziej zaawansowanego przykładu, z którym obecnie pracuję. W tym przypadku mamy funkcję C, która wykonuje dość ciężkie zadanie: odczytuje listę plików z urządzenia USB. Może to chwilę potrwać, dlatego chcemy, aby nasza aplikacja była powiadamiana o postępach. Możemy to zrobić, przekazując wskaźnik funkcji, który zdefiniowaliśmy w naszym programie. Po prostu wyświetla użytkownikowi informacje o postępie, gdy zostanie wywołany. Ponieważ ma dobrze znaną sygnaturę, możemy przypisać jej własny typ:
Ten program obsługi pobiera informacje o postępie (aktualną liczbę otrzymanych plików i całkowitą liczbę plików) wraz z wartością interfejsu {}, która może przechowywać wszystko, czego potrzebuje użytkownik.
Teraz musimy napisać instalację wodno-kanalizacyjną C i Go, aby umożliwić nam użycie tego programu obsługi. Na szczęście funkcja C, którą chcę wywołać z biblioteki, pozwala nam przekazać strukturę typu userdata
void*
. Oznacza to, że może pomieścić wszystko, co chcemy, bez zadawania pytań i wrócimy do świata Go tak, jak jest. Aby to wszystko działało, nie wywołujemy funkcji biblioteki bezpośrednio z Go, ale tworzymy dla niej opakowanie C, które nazwiemygoGetFiles()
. To właśnie ta otoka faktycznie dostarcza wywołanie zwrotne Go do biblioteki C, wraz z obiektem userdata.Zauważ, że
goGetFiles()
funkcja nie przyjmuje żadnych wskaźników funkcji dla wywołań zwrotnych jako parametrów. Zamiast tego wywołanie zwrotne dostarczone przez naszego użytkownika jest pakowane w niestandardową strukturę, która przechowuje zarówno tę procedurę obsługi, jak i własną wartość userdata użytkownika. Przekazujemy togoGetFiles()
jako parametr userdata.To wszystko w przypadku naszych wiązań C. Kod użytkownika jest teraz bardzo prosty:
To wszystko wygląda na dużo bardziej skomplikowane niż w rzeczywistości. Kolejność wywołań nie zmieniła się w przeciwieństwie do poprzedniego przykładu, ale otrzymujemy dwa dodatkowe wywołania na końcu łańcucha:
Kolejność jest następująca:
źródło
Nie jest to myląca propozycja, jeśli używasz gccgo. Działa to tutaj:
foo.go
bar.c
Makefile
źródło
go package main func Add(a, b string) int { return a + b }
, pojawia się błąd „undefined _go_string_plus”cgo
igo
zamiastgccgo
. Zobacz golang.org/cmd/cgo . Kiedy to powiedziane, jest w pełni możliwe użycie typu „string” w pliku .go i zmiana pliku .c tak, aby zawierał__go_string_plus
funkcję. To działa: ix.io/dZBOdpowiedź uległa zmianie wraz z wydaniem wersji Go 1.5
To SO pytanie, które zadałem jakiś czas temu, ponownie rozwiązuje ten problem w świetle dodatkowych możliwości 1.5
Używanie kodu Go w istniejącym projekcie C.
źródło
Jeśli o mnie chodzi, nie jest to możliwe:
źródło: https://github.com/golang/go/wiki/cgo
źródło