How to Use C++ in Go

Call Go functions from C

You can call the Go code from C. It is a confusing proposition, though.

The process is outlined in the blog post you linked to. But I can see how that isn't very helpful. Here is a short snippet without any unnecessary bits. It should make things a little clearer.

package foo

// extern int goCallbackHandler(int, int);
//
// static int doAdd(int a, int b) {
// return goCallbackHandler(a, b);
// }
import "C"

//export goCallbackHandler
func goCallbackHandler(a, b C.int) C.int {
return a + b
}

// This is the public function, callable from outside this package.
// It forwards the parameters to C.doAdd(), which in turn forwards
// them back to goCallbackHandler(). This one performs the addition
// and yields the result.
func MyAdd(a, b int) int {
return int( C.doAdd( C.int(a), C.int(b)) )
}

The order in which everything is called is as follows:

foo.MyAdd(a, b) ->
C.doAdd(a, b) ->
C.goCallbackHandler(a, b) ->
foo.goCallbackHandler(a, b)

The key to remember here is that a callback function must be marked with the //export comment on the Go side and as extern on the C side. This means that any callback you wish to use, must be defined inside your package.

In order to allow a user of your package to supply a custom callback function, we use the exact same approach as above, but we supply the user's custom handler (which is just a regular Go function) as a parameter that is passed onto the C side as void*. It is then received by the callbackhandler in our package and called.

Let's use a more advanced example I am currently working with. In this case, we have a C function that performs a pretty heavy task: It reads a list of files from a USB device. This can take a while, so we want our app to be notified of its progress. We can do this by passing in a function pointer that we defined in our program. It simply displays some progress info to the user whenever it gets called. Since it has a well known signature, we can assign it its own type:

type ProgressHandler func(current, total uint64, userdata interface{}) int

This handler takes some progress info (current number of files received and total number of files) along with an interface{} value which can hold anything the user needs it to hold.

Now we need to write the C and Go plumbing to allow us to use this handler. Luckily the C function I wish to call from the library allows us to pass in a userdata struct of type void*. This means it can hold whatever we want it to hold, no questions asked and we will get it back into the Go world as-is. To make all this work, we do not call the library function from Go directly, but we create a C wrapper for it which we will name goGetFiles(). It is this wrapper that actually supplies our Go callback to the C library, along with a userdata object.

package foo

// #include <somelib.h>
// extern int goProgressCB(uint64_t current, uint64_t total, void* userdata);
//
// static int goGetFiles(some_t* handle, void* userdata) {
// return somelib_get_files(handle, goProgressCB, userdata);
// }
import "C"
import "unsafe"

Note that the goGetFiles() function does not take any function pointers for callbacks as parameters. Instead, the callback that our user has supplied is packed in a custom struct that holds both that handler and the user's own userdata value. We pass this into goGetFiles() as the userdata parameter.

// This defines the signature of our user's progress handler,
type ProgressHandler func(current, total uint64, userdata interface{}) int

// This is an internal type which will pack the users callback function and userdata.
// It is an instance of this type that we will actually be sending to the C code.
type progressRequest struct {
f ProgressHandler // The user's function pointer
d interface{} // The user's userdata.
}

//export goProgressCB
func goProgressCB(current, total C.uint64_t, userdata unsafe.Pointer) C.int {
// This is the function called from the C world by our expensive
// C.somelib_get_files() function. The userdata value contains an instance
// of *progressRequest, We unpack it and use it's values to call the
// actual function that our user supplied.
req := (*progressRequest)(userdata)

// Call req.f with our parameters and the user's own userdata value.
return C.int( req.f( uint64(current), uint64(total), req.d ) )
}

// This is our public function, which is called by the user and
// takes a handle to something our C lib needs, a function pointer
// and optionally some user defined data structure. Whatever it may be.
func GetFiles(h *Handle, pf ProgressFunc, userdata interface{}) int {
// Instead of calling the external C library directly, we call our C wrapper.
// We pass it the handle and an instance of progressRequest.

req := unsafe.Pointer(&progressequest{ pf, userdata })
return int(C.goGetFiles( (*C.some_t)(h), req ))
}

That's it for our C bindings. The user's code is now very straight forward:

package main

import (
"foo"
"fmt"
)

func main() {
handle := SomeInitStuff()

// We call GetFiles. Pass it our progress handler and some
// arbitrary userdata (could just as well be nil).
ret := foo.GetFiles( handle, myProgress, "Callbacks rock!" )

....
}

// This is our progress handler. Do something useful like display.
// progress percentage.
func myProgress(current, total uint64, userdata interface{}) int {
fc := float64(current)
ft := float64(total) * 0.01

// print how far along we are.
// eg: 500 / 1000 (50.00%)
// For good measure, prefix it with our userdata value, which
// we supplied as "Callbacks rock!".
fmt.Printf("%s: %d / %d (%3.2f%%)\n", userdata.(string), current, total, fc / ft)
return 0
}

This all looks a lot more complicated than it is. The call order has not changed as opposed to our previous example, but we get two extra calls at the end of the chain:

The order is as follows:

foo.GetFiles(....) ->
C.goGetFiles(...) ->
C.somelib_get_files(..) ->
C.goProgressCB(...) ->
foo.goProgressCB(...) ->
main.myProgress(...)

Use golang function inside C-program

There are a couple of issues here. First is the incompatibility of the types. Go will return a GoInt. Second issues is that the Add() function has to be exported to get the desired header file. If you don't want to change your Go code, then in C you have to use the GoInt which is a long long.

A complete example is:

test.go

package main

import "C"

//export Add
func Add() C.int {
var a = 23
return C.int(a)
}

func main() {}

test.c

#include "test.h"
#include <stdio.h>

int main() {
int number = Add();
printf("%d\n", number);
}

Then compile and run:

go build -o test.so -buildmode=c-shared test.go
gcc -o test test.c ./test.so &&
./test

23


A second example using the GoInt:
test.go

package main

import "C"

//export Add
func Add() int { // returns a GoInt (typedef long long GoInt)
var a = 23
return a
}

func main() {}

test.c

#include "test.h"
#include <stdio.h>

int main() {
long long number = Add();
printf("%lld\n", number);
}

Then compile and run:

go build -o test.so -buildmode=c-shared test.go
gcc -o test test.c ./test.so &&
./test

23

How to use extern c strings in cgo

Arrays in C are not transparently handled by cgo.

There is what is known as idiomatic Go to map C memory to something Go can naturally manipulate. Here is a working example (main.go):

package main

import (
"fmt"
"unsafe"
)

// #cgo LDFLAGS: -L${SRCDIR} -la
// #include "./a.h"
import "C"

func main() {
x := 1
fmt.Println(x)
fmt.Println(len(C.s)) // Note, Go has no idea so it says 0.

cStr := (*[1 << 30]*C.char)(unsafe.Pointer(&C.s))[x]

fmt.Println(C.GoString(cStr))
}

The key piece being (*[1 << 30]*C.char)(unsafe.Pointer(&C.s)). What this says is interpret &C.s as a very large constant size array ("large enough for anyone"...), but extract only the element of interest [x] from it.

The use of unsafe.Pointer() should be a warning that looking beyond the end of the actual C array will yield unpredictable results. Indeed, it might crash the program.

Using Go in C++

You have to use GoString rather than std::string in the C++ version. The error message you are getting is because of the type mismatch, manifesting as a link-time error.

See the cgo reference.

Here's a working example. There's a few differences from yours. The //export directive is needed to include the function in the generated header file, the argument is *C.char rather than string or GoString. The C++ code uses the header generated by cgo, and there has to be a const-removing cast from the static string (because go doesn't have C-like const).

libmylib.go

package main

import "C"

import (
"fmt"
)

//export say
func say(text *C.char) {
fmt.Println(C.GoString(text))
}

func main() {}

main.cpp

#include "libmylib.h"

int main(void) {
say(const_cast<char*>("hello world"));

return 0;
}

commands

This compiles to go file, generating libmylib.so and libmylib.h in the current directory.

go build -o libmylib.so -buildmode=c-shared libmylib.go

The compiles the C++ program, linking it to the shared library above:

g++ -L. main.cpp -lmylib -o hello_program

To run the program, LD_LIBRARY_PATH needs to be set to the current directory. That would be different if program was installed and the shared library put in a sensible place.

LD_LIBRARY_PATH=. ./hello_program

CGo doesn't compile C files

The heart of the problem is that your setup is wrong: your Go code should #include, in the Cgo prefix, only the headers for any C code you want compiled separately. For instance:

package main

/*
#include "pmdk.h"
*/
import "C"

func main() {
C.helloWorld()
}

You can put C code into the prefix:

package main

/*
#include <stdio.h>
void helloWorld() {
printf("hello world from C\n");
}
*/
import "C"

...

But if you put your C code into a separate file (prog.c, etc.), you should create a small header file that simply declares each function, and #include that header file from both the C code and the Go code.1

Running:

go build

will then compile the C code if it has changed, and build the Go code if it has changed, and link together the two as appropriate. If you #include the C code directly into the Go package, as you did, go build will both build the C code and build the Go code that includes the C code, which is why you get the duplicate definitions.

Whatever C code you embed in the Cgo header should appear nowhere else. This is a good place to put small "plumbing adapters", if you have some existing C code that mostly works with Go, but needs some tweaks.


1This is a general technique in C for making sure that the header file declarations of functions agree with the C source definition of the same functions. That is, the header fifth.h might say:

void func(int arg1, char *arg2);

and, separately, the C code will read:

#include "fifth.h"

void func(int zorg, char *evil) {
// ...
}

and the C compiler will check that the declaration matches the definition.

How to use C++ in Go

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


Related Topics



Leave a reply



Submit