在新的Go语言中,我如何调用c++代码?换句话说,我如何包装我的c++类并在Go中使用它们?
当前回答
在使用gcc Go编译器gccgo时,我们讨论了C和Go之间的互操作性。然而,当使用gccgo时,Go的互操作性和实现的特性集都有限制(例如,有限的goroutines,没有垃圾收集)。
其他回答
从我在FAQ中读到的内容来看,你还不能确定:
Do Go programs link with C/C++ programs? There are two Go compiler implementations, gc (the 6g program and friends) and gccgo. Gc uses a different calling convention and linker and can therefore only be linked with C programs using the same convention. There is such a C compiler but no C++ compiler. Gccgo is a GCC front-end that can, with care, be linked with GCC-compiled C or C++ programs. The cgo program provides the mechanism for a “foreign function interface” to allow safe calling of C libraries from Go code. SWIG extends this capability to C++ libraries.
这里的问题是,兼容的实现不需要将类放在compile .cpp文件中。如果编译器可以优化一个类的存在,只要程序在没有它的情况下也能以同样的方式运行,那么它就可以从输出可执行文件中删除。
C语言有一个标准的二进制接口。因此,您将能够知道您的函数被导出了。但是c++背后并没有这样的标准。
更新:我已经成功地将一个小型测试c++类与Go连接起来
如果你用C接口包装c++代码,你应该能够用cgo调用你的库(参见$GOROOT/misc/cgo/gmp中的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;
}
我想在围棋中使用它。我将使用C接口
// foo.h
#ifdef __cplusplus
extern "C" {
#endif
typedef void* Foo;
Foo FooInit(void);
void FooFree(Foo);
void FooBar(Foo);
#ifdef __cplusplus
}
#endif
(我使用void*代替C结构体,以便编译器知道Foo的大小)
实现为:
//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 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
你正走在一个未知的领域。这里是调用C代码的Go示例,也许在阅读了c++命名混乱和调用约定以及大量的试验和错误之后,您可以做一些类似的事情。
如果你还想尝试,祝你好运。
您可能需要向Golang/CGo的LDFlags添加-lc++来识别对标准库的需求。