如何使用C++;围棋 在新的语言中,我怎么称呼C++代码?换句话说,我如何包装我的C++类并在GO中使用它们?< /P> < P>你不能从我读到的: Go程序是否与C/C++程序链接?

如何使用C++;围棋 在新的语言中,我怎么称呼C++代码?换句话说,我如何包装我的C++类并在GO中使用它们?< /P> < P>你不能从我读到的: Go程序是否与C/C++程序链接?,c++,wrapper,go,C++,Wrapper,Go,有两种Go编译器实现,gc(6g程序和朋友)和gccgo。Gc使用不同的调用约定和链接器,因此只能与使用相同约定的C程序链接。有这样一个C编译器,但没有C++编译器。GCGO是一个GCC前端,可以小心地与GCC编译的C或C++程序连接。 cgo程序提供了一种“外部函数接口”机制,允许从Go代码安全调用C库。SWIG将此能力扩展到C++库。 你还不能完全从我读到的: Go程序是否与C/C++程序链接? 有两种Go编译器实现,gc(6g程序和朋友)和gccgo。Gc使用不同的调用约定和链接器,因此只

有两种Go编译器实现,gc(6g程序和朋友)和gccgo。Gc使用不同的调用约定和链接器,因此只能与使用相同约定的C程序链接。有这样一个C编译器,但没有C++编译器。GCGO是一个GCC前端,可以小心地与GCC编译的C或C++程序连接。 cgo程序提供了一种“外部函数接口”机制,允许从Go代码安全调用C库。SWIG将此能力扩展到C++库。
你还不能完全从我读到的:

Go程序是否与C/C++程序链接? 有两种Go编译器实现,gc(6g程序和朋友)和gccgo。Gc使用不同的调用约定和链接器,因此只能与使用相同约定的C程序链接。有这样一个C编译器,但没有C++编译器。GCGO是一个GCC前端,可以小心地与GCC编译的C或C++程序连接。 cgo程序提供了一种“外部函数接口”机制,允许从Go代码安全调用C库。SWIG将此能力扩展到C++库。
这里的问题是,兼容实现不需要将类放在compile.cpp文件中。如果编译器可以优化类的存在性,那么只要程序在没有类的情况下以相同的方式运行,就可以从输出可执行文件中忽略它


C有一个标准化的二进制接口。因此,您将能够知道您的函数已导出。但是C++背后没有这样的标准。

这里的问题是,一个兼容的实现不需要将类放入编译的.CPP文件中。如果编译器可以优化类的存在性,那么只要程序在没有类的情况下以相同的方式运行,就可以从输出可执行文件中忽略它


C有一个标准化的二进制接口。因此,您将能够知道您的函数已导出。但C++背后没有这样的标准。

< p>你在这里行走在未知的领域。是调用C代码的Go示例,也许在阅读并调用约定以及大量尝试和错误之后,您可以这样做


如果你还想尝试,祝你好运。

你正在这片未知的土地上行走。是调用C代码的Go示例,也许在阅读并调用约定以及大量尝试和错误之后,您可以这样做


如果您仍然想尝试,祝您好运。

关于使用gcc Go编译器gccgo的话题。但是,在使用gccgo时,Go的互操作性和实现的功能集都有限制(例如,有限的Goroutine,没有垃圾收集)。

在使用gcc Go编译器gccgo时,会有讨论。使用GCGO时,GO的互操作性和实现的特征集都有局限性,但是(例如,限制GORDOTIN,没有垃圾回收)。

<强>更新:< /强>我成功地将一个小的测试C++类与GO

链接起来。

如果你用C++接口包你C++代码,你应该能够用CGO调用你的库(参见GMP在代码中的例子)$GOOOT/MISC/CGO/GMP < /代码>。p>

我不确定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;
}
(我使用
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)
您需要使用makeinstall安装共享库,然后运行maketest。预期产出为:

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

<强> Update:我成功地将一个小的测试C++类与GO

链接起来

如果你用C++接口包你C++代码,你应该能够用CGO调用你的库(参见GMP在代码中的例子)$GOOOT/MISC/CGO/GMP < /代码>。p>

我不确定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;
}
(我使用
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)
您需要使用makeinstall安装共享库,然后运行maketest。预期产出为:

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

有趣的是,这一声明涉及到了许多更广泛的问题。Dan Lyke在他的网站Flatterby上进行了一次非常有趣和深思熟虑的讨论,讨论的内容是如何将开发作为一种引导新语言的方式(以及其他分支,但这正是一个密切相关的分支)。

有趣的是,这一声明挖掘了许多更广泛的问题。Dan Lyke在他的网站Flatterby上进行了一次非常有趣和深思熟虑的讨论,讨论了如何将开发作为引导新语言的一种方式(以及其他分支,但这是一个密切相关的分支)。

似乎目前SWIG是解决这一问题的最佳方案:

支持继承,甚至允许用GO结构将C++类分为类,因此当在C++代码中调用重写方法时,GO代码被启动。
更新后,现在提到了SWIG,不再说“因为Go是垃圾收集的,所以这样做是不明智的,至少是天真的。”

似乎目前SWIG是解决这一问题的最佳方案:

支持继承,甚至允许用GO结构将C++类分为类,因此当在C++代码中调用重写方法时,GO代码被启动。 更新,现在提到SWIG,不再说“因为Go是g
#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();
}
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())
}
liblibrary.so: library.cpp library-bridge.cpp
    clang++ -o liblibrary.so library.cpp library-bridge.cpp \
    -std=c++17 -O3 -Wall -Wextra -fPIC -shared
$ 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)
// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"
// #include <stdio.h>
// #include <errno.h>
import "C"