如何在Go中使用C ++?
在新的Go语言中,如何调用C ++代码? 换句话说,如何包装我的C ++类并在Go中使用它们?
更新:我成功地将一个小的testingC ++类与Go联系起来
如果你用C接口包装你的C ++代码,你应该可以用cgo调用你的库(请参阅$ GOROOT / misc / cgo / gmp中的gmp示例)。
我不确定C ++中的类是否可以用Go来expression,因为它没有inheritance。
这是一个例子:
我有一个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*
而不是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)
尝试用以下方法testing
// 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
你还不能从我在FAQ中读到的内容中find答案 :
Do Go程序是否与C / C ++程序链接?
有两个Go编译器实现,gc(6g程序和朋友)和gccgo。 Gc使用不同的调用约定和链接器,因此只能使用相同的约定与C程序链接。 有这样一个C编译器,但没有C ++编译器。 Gccgo是一个GCC前端,可以小心地与GCC编译的C或C ++程序链接。
cgo程序提供了一个“外部函数接口”机制,允许从Go代码安全地调用C库。 SWIG将此function扩展到C ++库。
似乎目前SWIG是最好的解决scheme:
http://www.swig.org/Doc2.0/Go.html
它支持inheritance,甚至允许使用Go结构来inheritanceC ++类,所以当在C ++代码中调用重写的方法时,Go代码被激发。
有关Go的FAQ中的C ++部分已经更新,现在提到SWIG,不再说“ 因为Go是垃圾收集,所以这样做是不明智的,至less天真 ”。
截至go1.2 +,cgo自动合并和编译C ++代码:
看起来这是关于Golang的早期问题之一。 而同一时间的答案永远不会更新。 在这三四年的时间里,新的图书馆和博客太多了。 以下是我觉得有用的几个链接。
SWIG和Go
用SWIG调用C ++代码
比较语言,C ++和Go
GoForCPPProgrammers
在使用gcc Go编译器gccgo时,会谈到C和Go之间的互操作性 。 (例如,有限的goroutines,没有垃圾收集),使用gccgo时Go的互操作性和实现的function集都存在限制。
你走在这个未知的领域。 下面是调用C代码的Go示例,也许你可以在阅读完C ++名称调用和调用约定以及大量的试验和错误之后做类似的事情。
如果你仍然想尝试,祝你好运。
这里的问题是一个兼容的实现不需要把你的类放在一个编译的.cpp文件中。 如果编译器可以优化一个类的存在,只要没有它的程序行为相同,那么它可以从输出可执行文件中省略。
C有一个标准化的二进制接口。 因此,您将能够知道您的function已导出。 但是C ++没有这样的标准。
有趣的是,这个公告已经挖掘了多less更广泛的问题。 Dan Lyke在他的网站Flutterby上进行了一个非常有趣和深思熟虑的讨论,关于将进程间标准 ( Interprocess Standards)作为引导新语言(以及其他分支,但是这里是密切相关的)的一种方式。
您可能需要将-lc++
添加到Golang / CGo的LDFlags中,以识别标准库的需求。