J'essaye de créer un objet statique écrit dans Go to interface avec un programme C (disons, un module de noyau ou quelque chose).
J'ai trouvé de la documentation sur l'appel des fonctions C à partir de Go, mais je n'ai pas trouvé grand-chose sur la façon de procéder dans l'autre sens. Ce que j'ai trouvé, c'est que c'est possible, mais compliqué.
Voici ce que j'ai trouvé:
Article de blog sur les rappels entre C et Go
Message de la liste de diffusion Golang
Est-ce que quelqu'un a de l'expérience avec ça? Bref, j'essaye de créer un module PAM entièrement écrit en Go.
c
shared-libraries
go
dynamic-linking
beatgammit
la source
la source
Réponses:
Vous pouvez appeler le code Go à partir de C. c'est une proposition déroutante cependant.
Le processus est décrit dans l'article de blog auquel vous avez lié. Mais je peux voir à quel point cela n'est pas très utile. Voici un court extrait sans aucun élément inutile. Cela devrait rendre les choses un peu plus claires.
L'ordre dans lequel tout est appelé est le suivant:
La clé à retenir ici est qu'une fonction de rappel doit être marquée du
//export
commentaire sur le côté Go et commeextern
sur le côté C. Cela signifie que tout rappel que vous souhaitez utiliser doit être défini dans votre package.Afin de permettre à un utilisateur de votre package de fournir une fonction de rappel personnalisée, nous utilisons exactement la même approche que ci-dessus, mais nous fournissons le gestionnaire personnalisé de l'utilisateur (qui est juste une fonction Go régulière) en tant que paramètre qui est passé au C côté comme
void*
. Il est ensuite reçu par le callbackhandler dans notre package et appelé.Utilisons un exemple plus avancé avec lequel je travaille actuellement. Dans ce cas, nous avons une fonction C qui effectue une tâche assez lourde: elle lit une liste de fichiers à partir d'un périphérique USB. Cela peut prendre un certain temps, nous voulons donc que notre application soit informée de sa progression. Nous pouvons le faire en passant un pointeur de fonction que nous avons défini dans notre programme. Il affiche simplement des informations de progression à l'utilisateur chaque fois qu'il est appelé. Puisqu'il a une signature bien connue, nous pouvons lui attribuer son propre type:
Ce gestionnaire prend des informations de progression (nombre actuel de fichiers reçus et nombre total de fichiers) avec une valeur d'interface {} qui peut contenir tout ce que l'utilisateur a besoin de conserver.
Nous devons maintenant écrire la plomberie C and Go pour nous permettre d'utiliser ce gestionnaire. Heureusement, la fonction C que je souhaite appeler depuis la bibliothèque nous permet de passer une structure userdata de type
void*
. Cela signifie qu'il peut contenir tout ce que nous voulons qu'il contienne, aucune question posée et nous le ramènerons dans le monde de Go tel quel. Pour que tout cela fonctionne, nous n'appelons pas directement la fonction de bibliothèque depuis Go, mais nous créons un wrapper C pour cela que nous nommeronsgoGetFiles()
. C'est ce wrapper qui fournit en fait notre rappel Go à la bibliothèque C, avec un objet userdata.Notez que la
goGetFiles()
fonction ne prend aucun pointeur de fonction pour les rappels comme paramètres. Au lieu de cela, le rappel que notre utilisateur a fourni est emballé dans une structure personnalisée qui contient à la fois ce gestionnaire et la propre valeur userdata de l'utilisateur. Nous le transmettons engoGetFiles()
tant que paramètre userdata.C'est tout pour nos fixations C. Le code de l'utilisateur est désormais très simple:
Tout cela semble beaucoup plus compliqué qu'il ne l'est. L'ordre des appels n'a pas changé par rapport à notre exemple précédent, mais nous recevons deux appels supplémentaires à la fin de la chaîne:
L'ordre est le suivant:
la source
Ce n'est pas une proposition déroutante si vous utilisez gccgo. Cela fonctionne ici:
toto.go
bar.c
Makefile
la source
go package main func Add(a, b string) int { return a + b }
j'obtiens l'erreur "undefined _go_string_plus"cgo
et à lago
place degccgo
. Voir golang.org/cmd/cgo . Cela dit, il est tout à fait possible d'utiliser le type "chaîne" dans le fichier .go et de modifier votre fichier .c pour inclure une__go_string_plus
fonction. Cela fonctionne: ix.io/dZBLa réponse a changé avec la sortie de Go 1.5
Cette question SO que j'ai posée il y a quelque temps résout à nouveau le problème à la lumière des capacités supplémentaires de la version 1.5
Utilisation du code Go dans un projet C existant
la source
En ce qui me concerne, ce n'est pas possible:
source: https://github.com/golang/go/wiki/cgo
la source