Recap: I'm trying to use CGo to call a C library that then calls back
Go functions. I got past the minor problem with an out-of-date wiki
page providing code that doesn't build, and now I'm hopelessly hung up
in a thicket of function pointers. Either I am dumb or this is hard.
Too hard.
Here's the best advice I've got so far:
OK, sounds fine. But I can't get it to work.
Here's my foreign C library (not controlled by me, cannot change the
API):
// this is a C library that I cannot change; it knows nothing about
// Go, and it doesn't have a "void *userdata" hack that I can use to
// pass back-channel data in
void do_something(int (*callback)(int), int arg) {
printf("now in C do_something: callback=%p, arg=%d\n", callback, arg);
int r = callback(arg) + 5;
printf("do_something(): %d -> %d\n", arg, r);
}
Here's an example of a callback written in Go:
//export square
func square(arg C.int) C.int {
fmt.Printf("go square(%v)\n", arg)
return C.int(int(arg) * int(arg))
}
The goal: get do_something() to call square() and do something with
the result.
Attempt #1: write a wrapper, in C, for each Go callback. The C wrappers
are trivial:
int wrap_square(int arg) {
return square(arg);
}
(square() is a valid identifier because my C module has
#include "_cgo_export.h".)
Then in my Go main(), I try to pass the C wrapper to do_something():
func main() {
var cb func(C.int) C.int
var cbptr unsafe.Pointer
fmt.Println("main: calling do_something(csquare, 3)")
cb = C.wrap_square
cbptr = *(*unsafe.Pointer)(unsafe.Pointer(&cb))
C.do_something(cbptr, 3)
}
This doesn't even compile:
cb.go:30:10: must call C.wrap_square
OK, fine. You can't pass around C functions in Go. I guess that's a
limitation of CGo. Darn.
Attempt #2: write a wrapper for the unchangeable C API, pass Go
function pointers to it, and try to figure out the C function pointers
dynamically.
My Go main() now looks like this:
func main() {
var cb func(C.int) C.int
var cbptr unsafe.Pointer
fmt.Println("main: calling do_something(square, 3)")
cb = square
cbptr = *(*unsafe.Pointer)(unsafe.Pointer(&cb))
fmt.Printf(" square = %v, cb = %v, cbptr = %v\n", square, cb, cbptr)
C.wrap_do_something(cbptr, 3)
}
and the new C wrap_do_something() is:
void wrap_do_something(void *gocallback, int arg) {
int (*callback)(int);
printf("testing gocallback = %p against square = %p, triple = %p\n",
gocallback, square, triple);
if (gocallback == (void*)(square)) {
callback = wrap_square;
}
else if (gocallback == (void*)(triple)) {
callback = wrap_triple;
}
else {
fprintf(stderr,
"no C wrapper found for Go callback at %p\n", gocallback);
return;
}
do_something(callback, arg);
}
This at least compiles. But the attempt to match function pointers in
wrap_do_something() is a failure; here is the output of the resulting
program:
main: calling do_something(square, 3)
square = 0x400c00, cb = 0x400c00, cbptr = 0x400c00
testing gocallback = 0x400c00 against square = 0x4010c0, triple = 0x401110
no C wrapper found for Go callback at 0x400c00
So, back to my original question: is it actually possible to get a C
library *that has no knowledge of Go* and no "void *userdata" trick to
call Go callbacks? If, does anyone have example code that I can study?
(Someone [I believe minux] suggested misc/cgo/test/callback.go in the
Go source tree. Does not qualify: the C code there knows that it's
calling back to Go.)
Thanks --