tags:

views:

942

answers:

6

In the new Go language, how do I call C++ code? In other words, how can I wrap my C++ classes and use them in Go?

+12  A: 

You can't quite yet from what I read in the FAQ:

Do Go programs link with C/C++ programs?

There are two Go compiler implementations, 6g and friends, generically called gc, 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. However, because Go is garbage-collected it will be unwise to do so, at least naively.

There is a “foreign function interface” to allow safe calling of C-written libraries from Go code. We expect to use SWIG to extend this capability to C++ libraries. There is no safe way to call Go code from C or C++ yet.

Dirk Eddelbuettel
A: 

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.

Billy ONeal
+1  A: 

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.

Jurily
+1  A: 

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

fbrereto
1. Make a language with no facilities for manual memory management, 2. Remove garbage collection? Am I the only one scratching my head at this?
Jurily
+12  A: 

Update: I've succeeded in linking a small test c++ class with go

If you wrap you c++ code with a c interface you should be able to call your library with cgo (see the example of gmp in $GOROOT/misc/cgo/gmp).

I'm not sure if the idea of a class in c++ is really expressible in go, as it doesn't have inheritance.

Here's an example

I have a c++ class defined as

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

which I want to use in go. I'll use the c interface

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

(I use a void* instead of a c struct so the compiler knows the size of Foo)

The implementation is

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

with all that done, the go file is

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

The makefile I used to compile this was

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

Try testing it with

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

You'll need to install the shared library with make install, then run make test. Expected output is

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
Scott Wales
+1 Nice work. Could you wrap Qt for me? :P
Jurily
Be careful with this, I've got no idea what might happen to memory if you send it between the two languages.
Scott Wales
A: 

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

Don Wakefield