197

新しいGo言語では、C++ コードをどのように呼び出すのですか? つまり、C++ クラスをラップして Go で使用するにはどうすればよいでしょうか?

4

12 に答える 12

176

更新:小さなテスト 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

(void*コンパイラが Foo のサイズを認識できるように、C 構造体の代わりに a を使用します)

実装は次のとおりです。

//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
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 install で共有ライブラリをインストールしてから、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
于 2009-11-12T10:12:05.653 に答える
55

現在SWIGがこれに対する最良の解決策であるように思われます:

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

継承をサポートし、Go構造体を使用してC ++クラスをサブクラス化することもできるため、オーバーライドされたメソッドがC ++コードで呼び出されると、Goコードが起動されます。

GoFAQのC++に関するセクションが更新され、SWIGについて言及され、「Goはガベージコレクションされるため、少なくとも単純にそうするのは賢明ではない」とはなくなりました。

于 2012-03-29T19:00:54.647 に答える
35

FAQ で読んだことからはまだできません。

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

Go コンパイラの実装には、gc (6g プログラムとその仲間) と gccgo の 2 つがあります。Gc は異なる呼び出し規則とリンカーを使用するため、同じ規則を使用する C プログラムとのみリンクできます。そのような C コンパイラはありますが、C++ コンパイラはありません。Gccgo は、GCC でコンパイルされた C または C++ プログラムと慎重にリンクできる GCC フロントエンドです。

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

于 2009-11-11T05:30:30.713 に答える
35

go1.2 以降では、cgo は C++ コードを自動的に組み込み、コンパイルします。

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

于 2014-04-23T20:17:38.817 に答える
3

gcc Go コンパイラー gccgo を使用する場合の C と Go 間の相互運用性についての話があります。ただし、gccgo を使用する場合、相互運用性と Go の実装された機能セットの両方に制限があります (例: goroutine の制限、ガベージ コレクションなし)。

于 2009-11-11T17:47:27.277 に答える
2

あなたはここで未知の領域を歩いています。これは、C コードを呼び出すための Go の例です。おそらく、C++ の名前マングリングと呼び出し規約を読み、多くの試行錯誤を行った後に、そのようなことを行うことができます。

それでも試してみたいと思うなら、頑張ってください。

于 2009-11-11T05:59:01.713 に答える
1

-lc++標準ライブラリの必要性を認識するために、LDFlagsfor Golang/CGo に追加する必要がある場合があります。

于 2017-01-12T14:10:48.980 に答える
1

ここでの問題は、準拠した実装ではクラスをコンパイル .cpp ファイルに入れる必要がないことです。コンパイラがクラスの存在を最適化できる場合、プログラムがクラスなしで同じように動作する限り、出力実行可能ファイルから省略できます。

C には、標準化されたバイナリ インターフェイスがあります。したがって、関数がエクスポートされたことを知ることができます。しかし、C++ にはそのような標準はありません。

于 2009-11-11T05:35:14.897 に答える
0

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

于 2009-11-13T00:14:58.607 に答える