質問

新しいで 行け 言語、C ++コードを呼び出すにはどうすればよいですか?言い換えれば、C ++クラスをどのようにラップしてGOで使用できますか?

役に立ちましたか?

解決

アップデート: 私は小さなテストC ++クラスをGOとリンクすることに成功しました

CインターフェイスでC ++コードをラップする場合、CGOでライブラリに電話することができるはずです(GMPの例を参照してください $GOROOT/misc/cgo/gmp).

C ++のクラスのアイデアがGOでは本当に表現可能であるかどうかはわかりません。

これが例です:

次のように定義されたC ++クラスがあります

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

Goで使用したい。 Cインターフェイスを使用します

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

(私はaを使用します void* コンパイラがfooのサイズを知っているので、c構造体の代わりに)

実装は次のとおりです。

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

すべてが完了すると、GOファイルは次のとおりです。

// 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は次のとおりです。

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

でテストしてみてください:

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

共有ライブラリをMakeインストールしてインストールしてから、Make Testを実行する必要があります。予想される出力は次のとおりです。

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

他のヒント

現在、Swigがこれに最適なソリューションであると思われます。

http://www.swig.org/doc2.0/go.html

継承をサポートし、Go structでサブクラスC ++クラスを許可することさえできるため、C ++コードでオーバーライドされたメソッドが呼び出されると、GOコードが起動されます。

GO FAQのC ++に関するセクション 更新されており、今ではSwigに言及していますが、もう言っていません。ゴーはゴミ収集であるため、少なくとも素朴にそうするのは賢明ではありません".

あなたは私が読んだものからまだまったくできません FAQで:

GOプログラムはC/C ++プログラムとリンクしていますか?

GC(6Gプログラムと友人)とGCCGOの2つのGOコンパイラ実装があります。 GCは異なる呼び出しコンベンションとリンカーを使用するため、同じ規則を使用してCプログラムにのみリンクできます。このようなCコンパイラはありますが、C ++コンパイラはありません。 GCCGOは、GCCコンパイルCまたはC ++プログラムとリンクできるGCCフロントエンドです。

CGOプログラムは、GOコードからCライブラリの安全な呼び出しを可能にする「外部関数インターフェイス」のメカニズムを提供します。 Swigは、この機能をC ++ライブラリに拡張します。

Go1.2+の時点で、CGOはC ++コードを自動的に組み込んでコンパイルします。

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

ゴランについての初期の質問の1つです。そして、同じ時間の答えは決して更新しません。これらの3〜4年の間に、あまりにも多くの新しいライブラリとブログ投稿が発表されました。以下は、私が便利だと感じたいくつかのリンクです。

スウィグと行きます

Go with SwigからC ++コードを呼び出します

言語を比較すると、c ++と行きます

goforcppprogrammers

I've created the following example based on Scott Wales' answer. I've tested it in macOS High Sierra 10.13.3 running go version go1.10 darwin/amd64.

(1) Code for library.hpp, the C++ API we aim to call.

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

(2) Code for library.cpp, the C++ implementation.

#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 for library-bridge.h the bridge needed to expose a C API implemented in C++ so that go can use it.

#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 for library-bridge.cpp, the implementation of the bridge.

#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) Finally, library.go, the go program calling the 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())
}

Using the following 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

I can run the example program as follows:

$ 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

The comments above import "C" in the go program are NOT OPTIONAL. You must put them exactly as shown so that cgo knows which header and library to load, in this case:

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

Link to GitHub repo with the full example.

There's talk about interoperability between C and Go when using the gcc Go compiler, gccgo. There are limitations both to the interoperability and the implemented feature set of Go when using gccgo, however (e.g., limited goroutines, no garbage collection).

You're walking on uncharted territory here. Here is the Go example for calling C code, perhaps you can do something like that after reading up on C++ name mangling and calling conventions, and lots of trial and error.

If you still feel like trying it, good luck.

The problem here is that a compliant implementation does not need to put your classes in a compile .cpp file. If the compiler can optimize out the existence of a class, so long as the program behaves the same way without it, then it can be omitted from the output executable.

C has a standardized binary interface. Therefore you'll be able to know that your functions are exported. But C++ has no such standard behind it.

Funny how many broader issues this announcement has dredged up. Dan Lyke had a very entertaining and thoughtful discussion on his website, Flutterby, about developing Interprocess Standards as a way of bootstrapping new languages (and other ramifications, but that's the one that is germane here).

You might need to add -lc++ to the LDFlags for Golang/CGo to recognize the need for the standard library.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top