Jak korzystać z C++ w Go?

W nowym języku Go Jak nazwać kod C++? Innymi słowy, jak Mogę zawijać moje klasy C++ i używać ich w Go?

 137
Author: Frank, 2009-11-11

11 answers

Update: udało mi się połączyć małą testową klasę C++ z Go

Jeśli owijasz kod C++ interfejsem C, powinieneś być w stanie wywołać bibliotekę za pomocą cgo (zobacz przykład gmp w $GOROOT/misc/CGO/gmp).

Nie jestem pewien, czy idea klasy w C++ jest naprawdę expressible w Go, ponieważ nie ma dziedziczenia.

Oto przykład:

Mam klasę C++ zdefiniowaną jako:

// 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;
}

Które chcę wykorzystać w Go. Użyję C interfejs

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

(używam void* zamiast struktury C, aby kompilator znał rozmiar Foo)

Realizacja to:

//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();
}

Z tym wszystkim, plik Go to:

// 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));
}

Makefile, którego użyłem do kompilacji to było:

// 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)

Spróbuj przetestować go za pomocą:

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

Musisz zainstalować bibliotekę współdzieloną za pomocą make install, a następnie uruchomić make test. Oczekiwany wynik to:

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
Author: Scott Wales,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 07:00:02

Wydaje się, że obecnie SWIG jest najlepszym rozwiązaniem na to:

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

Obsługuje dziedziczenie, a nawet pozwala na podklasowanie klasy C++ za pomocą struktury Go, więc gdy nadpisane metody są wywoływane w kodzie C++, kod Go jest wywoływany.

Sekcja o C++ w Go FAQ została zaktualizowana i teraz wspomina SWIG i nie mówi już " ponieważ Go jest śmieciowy, byłoby nierozsądnie to zrobić, przynajmniej naiwnie ".

 31
Author: kolen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-29 19:00:54

Z tego co przeczytałem w FAQ nie można jeszcze do końca:

Czy Go programy łączą się z programami C / C++?

Istnieją dwie implementacje kompilatora Go, gc (program 6g I przyjaciele) i gccgo. Gc używa innej konwencji wywołania i linkera i dlatego może być połączony tylko z programami C używającymi tej samej konwencji. Istnieje taki kompilator C, ale nie ma kompilatora C++. Gccgo to front-end GCC, który można ostrożnie połączyć ze skompilowanym przez GCC C lub c++ programy.

Program CGO dostarcza mechanizm "foreign function interface" pozwalający na bezpieczne wywołanie bibliotek C z kodu Go. SWIG rozszerza tę możliwość o biblioteki C++.

 30
Author: Dirk Eddelbuettel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-06 13:24:26

Począwszy od go1.2+, cgo automatycznie Zawiera i kompiluje kod C++:

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

 20
Author: Malcolm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-23 20:17:38

Wygląda na to, że to jedno z pierwszych pytań o Golanga . I w tym samym czasie odpowiedzi na Nigdy nie aktualizować . W ciągu tych trzech do czterech lat pojawiło się zbyt wiele nowych bibliotek i blogów. Poniżej kilka linków, które uznałem za przydatne .

SWIG and Go

Wywołanie kodu C++ Z Go za pomocą SWIG

On comparing languages, C++ and Go

GoForCPPProgrammers

 8
Author: Pravin Mishra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-10 19:14:13

Stworzyłem poniższy przykład na podstawie odpowiedzi Scotta Wales ' a. Testowałem go w macOS High Sierra 10.13.3 z uruchomieniem go wersja go1.10 darwin/amd64.

(1) kod dla library.hpp, interfejsu API C++, który chcemy wywołać.

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

(2) Kod dla library.cpp, implementacji 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) kod dla library-bridge.h mostek musiał ujawnić C API zaimplementowane w C++, Aby go mógł z niego korzystać.

#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) kod dla library-bridge.cpp, implementacja mostek.

#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) Wreszcie, library.go, Program go wywołujący C++ API.

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())
}

Używając następującego pliku Makefile

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

Mogę uruchomić przykładowy program w następujący sposób:

$ 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)

Ważne

Powyższe Komentarze import "C" w programie go nie opcjonalne . Musisz umieścić je dokładnie tak, jak pokazano, aby cgo wiedział, który nagłówek i bibliotekę załadować, w tym przypadku:

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

Link do GitHub repo z pełnym przykład .

 6
Author: Escualo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-27 20:27:09

Mówi się o interoperacyjności pomiędzy C i Go Podczas korzystania z kompilatora GCC Go, gccgo. Istnieją jednak ograniczenia zarówno dla interoperacyjności, jak i zaimplementowanego zestawu funkcji Go podczas korzystania z gccgo (np. ograniczone goroutines, brak garbage collection).

 2
Author: fbrereto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 17:47:27

Chodzisz po niezbadanym terytorium tutaj. Tutaj {[2] } jest przykład do wywołania kodu C, być może możesz zrobić coś takiego po przeczytaniu C++ name mangling i wywołaniu konwencji, i wielu prób i błędów.

Jeśli nadal masz ochotę spróbować, powodzenia.

 1
Author: György Andrasek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 05:59:01

Problem polega na tym, że zgodna implementacja nie musi umieszczać klas w kompilacji .plik cpp. Jeśli kompilator może zoptymalizować istnienie klasy, tak długo, jak program zachowuje się bez niej tak samo, to może zostać pominięta w pliku wykonywalnym wyjścia.

C ma standardowy interfejs binarny. Dzięki temu będziesz mógł wiedzieć, że twoje funkcje są eksportowane. Ale C++ nie ma za sobą takiego standardu.

 0
Author: Billy ONeal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 05:35:14

Zabawne, ile szerszych kwestii to ogłoszenie się pogłębiło. Dan Lyke przeprowadził bardzo interesującą i przemyślaną dyskusję na swojej stronie internetowej, Flutterby, na temat rozwijania standardów Interprocesowych jako sposobu na bootstrapowanie nowych języków (i innych konsekwencji, ale to tutaj jest germańskie).

 0
Author: Don Wakefield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-13 00:14:58

Może być konieczne dodanie -lc++ do LDFlags, Aby Golang / CGo rozpoznał potrzebę biblioteki standardowej.

 0
Author: ggobieski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-12 14:50:28