Comment utiliser C++ dans Go?

dans le nouveau langage Go , comment appeler le code C++? En d'autres termes, comment puis-je envelopper mes cours de C++ et les utiliser dans Go?

137
demandé sur Frank 2009-11-11 08:25:13

11 réponses

mise à Jour: j'ai réussi à lier à un petit test de la classe C++ 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 expressible dans Go, car elle n'a pas d'héritage.

voici un exemple:

j'ai un c++ classe 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'une structure 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 ce qui est 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 aurez besoin d'installer la bibliothèque partagée avec make install, puis lancer make test. Résultats escomptés:

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
118
répondu Scott Wales 2016-08-02 07:00:02

semble que SWIG est actuellement la meilleure solution pour cela:

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

il supporte l'héritage et permet même de sous-Classe C++ Classe avec GO struct donc quand les méthodes dépassées sont appelées en code C++, le code Go est déclenché.

section À propos de C++ dans Go FAQ est mis à jour et mentionne maintenant SWIG et ne dit plus " parce que Go est ramassage des ordures il ne sera pas sage de le faire, au moins naïvement ".

31
répondu kolen 2012-03-29 19:00:54

vous ne pouvez pas encore de ce que je lis dans la FAQ :

Faire Passer des programmes de lien avec les programmes C/C++?

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

le programme cgo fournit le mécanisme pour une" interface de fonction étrangère " pour permettre l'appel sûr des bibliothèques C à partir du code Go. SWIG étend cette capacité aux bibliothèques C++.

30
répondu Dirk Eddelbuettel 2013-08-06 13:24:26

dès go1.2+, cgo incorpore et compile automatiquement le code C++:

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

20
répondu Malcolm 2014-04-23 20:17:38

semble être l'une des premières questions posées sur Golang . Et le même temps répond à ne jamais mettre à jour . Au cours de ces trois à quatre années , trop de nouvelles bibliothèques et de billets de blog ont été publiés . Voici les quelques liens que j'ai senti utile .

GORGÉE et Aller

Appeler du Code C++ à Partir de Aller Avec SWIG

Sur la comparaison des langues, C++ et Aller

GoForCPPProgrammers

8
répondu Pravin Mishra 2014-06-10 19:14:13

j'ai créé l'exemple suivant basé sur réponse de Scott Wales . Je l'ai testé dans macOS High Sierra 10.13.3 en lançant go version go1.10 darwin/amd64 .

(1) Code pour library.hpp , L'API C++ que nous voulons appeler.

#pragma once
class Foo {
 public:
  Foo(int value);
  ~Foo();
  int value() const;    
 private:
  int m_value;
};

(2) Code pour library.cpp , l'implémentation C++.

#include "library.hpp"
#include <iostream>

Foo::Foo(int value) : m_value(value) {
  std::cout << "[c++] Foo::Foo(" << m_value << ")" << std::endl;
}

Foo::~Foo() { std::cout << "[c++] Foo::~Foo(" << m_value << ")" << std::endl; }

int Foo::value() const {
  std::cout << "[c++] Foo::value() is " << m_value << std::endl;
  return m_value;
}

(3) Code pour library-bridge.h le pont nécessaire pour exposer un C API implémentée dans C++ pour que go puisse l'utiliser.

#pragma once
#ifdef __cplusplus
extern "C" {
#endif

void* LIB_NewFoo(int value);
void LIB_DestroyFoo(void* foo);
int LIB_FooValue(void* foo);

#ifdef __cplusplus
}  // extern "C"
#endif

(4) Code pour library-bridge.cpp , la mise en œuvre du pont.

#include <iostream>

#include "library-bridge.h"
#include "library.hpp"

void* LIB_NewFoo(int value) {
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ")" << std::endl;
  auto foo = new Foo(value);
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ") will return pointer "
            << foo << std::endl;
  return foo;
}

// Utility function local to the bridge's implementation
Foo* AsFoo(void* foo) { return reinterpret_cast<Foo*>(foo); }

void LIB_DestroyFoo(void* foo) {
  std::cout << "[c++ bridge] LIB_DestroyFoo(" << foo << ")" << std::endl;
  AsFoo(foo)->~Foo();
}

int LIB_FooValue(void* foo) {
  std::cout << "[c++ bridge] LIB_FooValue(" << foo << ")" << std::endl;
  return AsFoo(foo)->value();
}

(5) Enfin, library.go , le programme go appelant L'API C++.

package main

// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"
import "unsafe"
import "fmt"

type Foo struct {
    ptr unsafe.Pointer
}

func NewFoo(value int) Foo {
    var foo Foo
    foo.ptr = C.LIB_NewFoo(C.int(value))
    return foo
}

func (foo Foo) Free() {
    C.LIB_DestroyFoo(foo.ptr)
}

func (foo Foo) value() int {
    return int(C.LIB_FooValue(foo.ptr))
}

func main() {
    foo := NewFoo(42)
    defer foo.Free() // The Go analog to C++'s RAII
    fmt.Println("[go]", foo.value())
}

utilisant le Makefile suivant

liblibrary.so: library.cpp library-bridge.cpp
    clang++ -o liblibrary.so library.cpp library-bridge.cpp \
    -std=c++17 -O3 -Wall -Wextra -fPIC -shared

je peux exécuter le programme d'exemple comme suit:

$ make
clang++ -o liblibrary.so library.cpp library-bridge.cpp \
    -std=c++17 -O3 -Wall -Wextra -fPIC -shared
$ go run library.go
[c++ bridge] LIB_NewFoo(42)
[c++] Foo::Foo(42)
[c++ bridge] LIB_NewFoo(42) will return pointer 0x42002e0
[c++ bridge] LIB_FooValue(0x42002e0)
[c++] Foo::value() is 42
[go] 42
[c++ bridge] LIB_DestroyFoo(0x42002e0)
[c++] Foo::~Foo(42)

Important

Les commentaires ci-dessus import "C" dans le go programme PAS une OPTION . Vous devez les mettre exactement comme indiqué pour que cgo sache quel en-tête et quelle bibliothèque charger, dans ce cas:

// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"

Lien pour le dépôt GitHub avec l'exemple complet .

6
répondu Escualo 2018-02-27 20:27:09

Il y a en parler l'interopérabilité entre C et lors de l'utilisation de la ccg Aller compilateur, gccgo. Il y a toutefois des limites à l'interopérabilité et à L'ensemble des fonctionnalités mises en œuvre de Go lors de l'utilisation de gccgo (p. ex. goroutines limitées, pas de collecte des ordures).

2
répondu fbrereto 2009-11-11 17:47:27

vous marchez en territoire inconnu ici. ici est L'exemple de Go pour appeler le code C, peut-être que vous pouvez faire quelque chose comme ça après avoir lu sur nom c++ mangeant et appelant conventions, et beaucoup d'essai et d'erreur.

si vous avez encore envie d'essayer, bonne chance.

1
répondu György Andrasek 2009-11-11 05:59:01

le problème ici est qu'une implémentation conforme n'a pas besoin de mettre vos classes dans une compilation .fichier cpp. Si le compilateur peut optimiser l'existence d'une classe, tant que le programme se comporte de la même façon sans elle, alors il peut être omis de la sortie de l'exécutable.

C a une interface binaire standardisée. Par conséquent, vous serez en mesure de savoir que vos fonctions sont exportées. Mais C++ n'a pas de telle norme derrière lui.

0
répondu Billy ONeal 2009-11-11 05:35:14

Drôle combien de questions plus larges cette annonce a dragué. Dan Lyke a eu une discussion très divertissante et réfléchie sur son site Web, Flutterby, à propos du développement de Interprocess Standards comme un moyen de bootstrapping de nouvelles langues (et d'autres ramifications, mais c'est celui qui est pertinent ici).

0
répondu Don Wakefield 2009-11-13 00:14:58

vous pourriez avoir besoin d'ajouter -lc++ au LDFlags pour Golang/CGo pour reconnaître le besoin de la bibliothèque standard.

0
répondu ggobieski 2017-01-12 14:50:28