196 votes

Comment utiliser C++ en Go

Dans le nouveau Allez sur comment puis-je appeler le code C++ ? En d'autres termes, comment puis-je envelopper mes classes C++ et les utiliser en Go ?

1 votes

Dans la présentation technique, SWIG a été très brièvement mentionné, quelque chose comme " jusqu'à ce que nous ayons terminé le swig ".

1 votes

@Matt : Il veut probablement utiliser une bibliothèque C++ existante sans avoir à la porter en C ou en Go. Je voulais la même chose.

0 votes

Je ne connais pas une seule bibliothèque décente disponible pour le C++ et pas pour le C. J'aimerais savoir ce que vous avez en tête.

174voto

Scott Wales Points 5217

Mise à jour : J'ai réussi à lier une petite classe C++ de test avec Go

Si vous enveloppez votre code C++ avec une interface C, vous devriez être en mesure d'appeler votre bibliothèque avec cgo (voir l'exemple de gmp dans $GOROOT/misc/cgo/gmp ).

Je ne suis pas sûr que l'idée d'une classe en C++ soit vraiment exprimable en Go, car il n'y a pas d'héritage.

Voici un exemple :

J'ai une classe C++ définie comme :

// foo.hpp
class cxxFoo {
public:
  int a;
  cxxFoo(int _a):a(_a){};
  ~cxxFoo(){};
  void Bar();
};

// foo.cpp
#include <iostream>
#include "foo.hpp"
void
cxxFoo::Bar(void){
  std::cout<<this->a<<std::endl;
}

que je veux utiliser dans Go. Je vais utiliser l'interface C

// foo.h
#ifdef __cplusplus
extern "C" {
#endif
  typedef void* Foo;
  Foo FooInit(void);
  void FooFree(Foo);
  void FooBar(Foo);
#ifdef __cplusplus
}
#endif

(J'utilise un void* au lieu d'un struct C pour que le compilateur connaisse la taille de Foo)

La mise en œuvre est :

//cfoo.cpp
#include "foo.hpp"
#include "foo.h"
Foo FooInit()
{
  cxxFoo * ret = new cxxFoo(1);
  return (void*)ret;
}
void FooFree(Foo f)
{
  cxxFoo * foo = (cxxFoo*)f;
  delete foo;
}
void FooBar(Foo f)
{
  cxxFoo * foo = (cxxFoo*)f;
  foo->Bar();
}

avec tout cela fait, le fichier Go est :

// foo.go
package foo
// #include "foo.h"
import "C"
import "unsafe"
type GoFoo struct {
     foo C.Foo;
}
func New()(GoFoo){
     var ret GoFoo;
     ret.foo = C.FooInit();
     return ret;
}
func (f GoFoo)Free(){
     C.FooFree(unsafe.Pointer(f.foo));
}
func (f GoFoo)Bar(){
     C.FooBar(unsafe.Pointer(f.foo));
}

Le makefile que j'ai utilisé pour compiler ceci était :

// makefile
TARG=foo
CGOFILES=foo.go
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
foo.o:foo.cpp
    g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<
cfoo.o:cfoo.cpp
    g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<
CGO_LDFLAGS+=-lstdc++
$(elem)_foo.so: foo.cgo4.o foo.o cfoo.o
    gcc $(_CGO_CFLAGS_$(GOARCH)) $(_CGO_LDFLAGS_$(GOOS)) -o $@ $^ $(CGO_LDFLAGS)

Essayez de le tester avec :

// foo_test.go
package foo
import "testing"
func TestFoo(t *testing.T){
    foo := New();
    foo.Bar();
    foo.Free();
}

Vous devrez installer la bibliothèque partagée avec make install, puis lancer make test. La sortie attendue est :

gotest
rm -f _test/foo.a _gotest_.6
6g -o _gotest_.6 foo.cgo1.go foo.cgo2.go foo_test.go
rm -f _test/foo.a
gopack grc _test/foo.a _gotest_.6  foo.cgo3.6
1
PASS

1 votes

Faites attention, je n'ai aucune idée de ce qui pourrait arriver à la mémoire si vous l'envoyez entre les deux langues.

14 votes

Je dois dire que cet exemple me rappelle pourquoi je veux écrire du Go pur. Regarde comme le côté C++ est plus gros et plus moche. Ick.

0 votes

@ScottWales est-il possible que vous ayez mis cela dans un dépôt sur Github ou autre ? J'adorerais voir un exemple fonctionnel

55voto

kolen Points 712

Il semble que SWIG soit actuellement la meilleure solution pour cela :

http://www.swig.org/Doc2.0/Go.html

Il prend en charge l'héritage et permet même de sous-classer une classe C++ avec une structure Go. Ainsi, lorsque des méthodes surchargées sont appelées dans le code C++, le code Go est activé.

Section sur le C++ dans la FAQ Go est mis à jour et mentionne maintenant SWIG et ne dit plus " parce que Go est un système de collecte de déchets, il ne sera pas judicieux de le faire, du moins naïvement. ".

9 votes

J'aimerais qu'il y ait un moyen de faire remonter cette information. Les autres réponses sont dépassées. De plus, SWIG a changé de version swig.org/Doc3.0/Go.html

35voto

Dirk Eddelbuettel Points 134700

Vous ne pouvez pas encore tout à fait d'après ce que j'ai lu. dans les FAQ :

Les programmes Go sont-ils liés aux programmes C/C++ ?

Il existe deux implémentations du compilateur Go, gc (le programme 6g et ses amis) et gccgo. Gc utilise une convention d'appel et un linker différents et ne peut donc être lié qu'à des programmes C utilisant la même convention. Il existe un tel compilateur C mais pas de compilateur C++. Gccgo est un frontal de GCC qui peut, avec précaution, être lié à des programmes C ou C++ compilés par GCC.

Le programme cgo fournit le mécanisme d'une "interface de fonction étrangère" permettant d'appeler en toute sécurité les bibliothèques C à partir du code Go. SWIG étend cette capacité aux bibliothèques C++.

34voto

Malcolm Points 450

À partir de go1.2+, cgo incorpore et compile automatiquement le code C++ :

http://golang.org/doc/go1.2#cgo_and_cpp

11voto

Pravin Mishra Points 2544

Il semble que ce soit l'une des premières questions posées sur Golang. Et en même temps les réponses ne sont jamais mises à jour. Au cours de ces trois ou quatre années, trop de nouvelles bibliothèques et de nouveaux articles de blog ont été publiés. Voici les quelques liens qui m'ont semblé utiles.

SWIG et Go

Appeler du code C++ depuis Go avec SWIG

Comparer les langages, C++ et Go

GoForCPPProgrammeurs

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X