-
Notifications
You must be signed in to change notification settings - Fork 17.7k
cgo
First, http://golang.org/cmd/cgo is the primary cgo documentation.
There is also a good introduction article at http://golang.org/doc/articles/c_go_cgo.html.
If a Go source file imports "C"
, it is using cgo. The Go file will have access to anything appearing in the comment immediately preceding the line import "C"
, and will be linked against all other cgo comments in other Go files, and all C files included in the build process.
Note that there must be no blank lines in between the cgo comment and the import statement.
To access a symbol originating from the C side, use the package name C
. That is, if you want to call the C function printf()
from Go code, you write C.printf()
. Since variable argument methods like printf aren't supported yet (issue 975), we will wrap it in the C method "myprint":
package cgoexample
/*
#include <stdio.h>
#include <stdlib.h>
void myprint(char* s) {
printf("%s", s);
}
*/
import "C"
import "unsafe"
func Example() {
cs := C.CString("Hello from stdio\n")
C.myprint(cs)
C.free(unsafe.Pointer(cs))
}
It is possible to call both top-level Go functions and function variables from C code invoked from Go code using cgo.
Go makes its functions available to C code through use of a special //export
comment.
Note: you can't define any C functions in preamble if you're using exports.
For example, there are two files, foo.c and foo.go: foo.go contains:
package gocallback
import "fmt"
/*
#include <stdio.h>
extern void ACFunction();
*/
import "C"
//export AGoFunction
func AGoFunction() {
fmt.Println("AGoFunction()")
}
func Example() {
C.ACFunction()
}
foo.c contains:
#include "_cgo_export.h"
void ACFunction() {
printf("ACFunction()\n");
AGoFunction();
}
The following code shows an example of invoking a Go callback from C code. Go passes the function variable to the CGo code by calling CallMyFunction()
. CallMyFunction()
invokes the callback by sending it back into the Go code, with the desired parameters, for unpacking and calling.
package gocallback
import (
"fmt"
"unsafe"
)
/*
extern void go_callback_int(void* foo, int p1);
// normally you will have to define function or variables
// in another separate C file to avoid the multiple definition
// errors, however, using "static inline" is a nice workaround
// for simple functions like this one.
static inline void CallMyFunction(void* pfoo) {
go_callback_int(pfoo, 5);
}
*/
import "C"
//export go_callback_int
func go_callback_int(pfoo unsafe.Pointer, p1 C.int) {
foo := *(*func(C.int))(pfoo)
foo(p1)
}
func MyCallback(x C.int) {
fmt.Println("callback with", x)
}
// we store it in a global variable so that the garbage collector
// doesn't clean up the memory for any temporary variables created.
var MyCallbackFunc = MyCallback
func Example() {
C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc))
}
C code can call exported Go functions with their explicit name. But if a C-program wants a function pointer, a gateway function has to be written. This is because we can't take the address of a Go function and give that to C-code since the cgo tool will generate a stub in C that should be called. The following example shows how to integrate with C code wanting a function pointer of a give type.
Place these source files under $GOPATH/src/ccallbacks/. Compile and run with:
$ gcc -c clibrary.c
$ ar cru libclibrary.a clibrary.o
$ go build ccallbacks
$ ./ccallbacks
Go.main(): calling C function with callback to us
C.some_c_func(): calling callback with arg = 2
C.callOnMeGo_cgo(): called with arg = 2
Go.callOnMeGo(): called with arg = 2
C.some_c_func(): callback responded with 3
goprog.go
package main
/*
#cgo CFLAGS: -I .
#cgo LDFLAGS: -L . -lclibrary
#include "clibrary.h"
int callOnMeGo_cgo(int in); // Forward declaration.
*/
import "C"
import (
"fmt"
"unsafe"
)
//export callOnMeGo
func callOnMeGo(in int) int {
fmt.Printf("Go.callOnMeGo(): called with arg = %d\n", in)
return in + 1
}
func main() {
fmt.Printf("Go.main(): calling C function with callback to us\n")
C.some_c_func((C.callback_fcn)(unsafe.Pointer(C.callOnMeGo_cgo)))
}
cfuncs.go
package main
/*
#include <stdio.h>
// The gateway function
int callOnMeGo_cgo(int in)
{
printf("C.callOnMeGo_cgo(): called with arg = %d\n", in);
return callOnMeGo(in);
}
*/
import "C"
clibrary.h
#ifndef CLIBRARY_H
#define CLIBRARY_H
typedef int (*callback_fcn)(int);
void some_c_func(callback_fcn);
#endif
clibrary.c
#include <stdio.h>
#include "clibrary.h"
void some_c_func(callback_fcn callback)
{
int arg = 2;
printf("C.some_c_func(): calling callback with arg = %d\n", arg);
int response = callback(2);
printf("C.some_c_func(): callback responded with %d\n", response);
}
Go strings and C strings are different. Go strings are the combination of a length and a pointer to the first character in the string. C strings are just the pointer to the first character, and are terminated by the first instance of the null character, '\0'
.
Go provides means to go from one to another in the form of the following three functions:
func C.CString(goString string) *C.char
func C.GoString(cString *C.char) string
func C.GoStringN(cString *C.char, length C.int) string
One important thing to remember is that C.CString()
will allocate a new string of the appropriate length, and return it. That means the C string is not going to be garbage collected and it is up to you to free it. A standard way to do this follows.
// #include <stdlib.h>
import "C"
import "unsafe"
...
var cmsg *C.char = C.CString("hi")
defer C.free(unsafe.Pointer(cmsg))
// do something with the C string
Of course, you aren't required to use defer
to call C.free()
. You can free the C string whenever you like, but it is your responsibility to make sure it happens.
C arrays are typically either null-terminated or have a length kept elsewhere.
Go provides the following function to make a new Go byte slice from a C array:
func C.GoBytes(cArray unsafe.Pointer, length C.int) []byte
To create a Go slice backed by a C array (without copying the original data), one needs to acquire this length at runtime and use reflect.SliceHeader
.
import "C"
import "unsafe"
...
var theCArray *C.YourType = C.getTheArray()
length := int(C.getTheArrayLength())
hdr := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(theCArray)),
Len: length,
Cap: length,
}
goSlice := *(*[]C.YourType)(unsafe.Pointer(&hdr))
// now goSlice is a Go slice backed by the C array
It is important to keep in mind that the Go garbage collector will not interact with this data, and that if it is freed from the C side of things, the behavior of any Go code using the slice is nondeterministic.
Another simpler solution is casting the pointer to a pointer to a very big array and then slice it to the length that you want (also remember to set the cap if you're using Go 1.2 or later), for example (see http://play.golang.org/p/XuC0xqtAIC for a runnable example):
import "C"
import "unsafe"
...
var theCArray *C.YourType = C.getTheArray()
length := C.getTheArrayLength()
slice := (*[1 << 30]C.YourType)(unsafe.Pointer(theCArray))[:length:length]
As Go doesn't support packed struct (e.g., structs where maximum alignment is 1 byte), you can't use packed C struct in Go. Even if you program passes compilation, it won't do what you want. To use it, you have to read/write the struct as byte array/slice.
Another problem is that some types has lower alignment requirement than their counterpart in Go, and if that type happens to be aligned in C but not in Go rules, that struct simply can't be represented in Go. An example is this (issue 7560 (on Google Code)):
struct T {
uint32_t pad;
complex float x;
};
Go's complex64 has an alignment of 8-byte, where as C has only 4-byte (because C treats the
complex float internally as a struct { float real; float imag; }
, not a basic type), this T struct simply
doesn't have a Go representation. For this case, if you control the layout of the struct, move the
complex float so that it is also aligned to 8-byte is better, and if you're not willing to move it,
use this form will force it to align to 8-byte (and waste 4-byte):
struct T {
uint32_t pad;
__attribute__((align(8))) complex float x;
};
However, if you don't control the struct layout, you will have to define accessor C functions for that struct because cgo won't be able to translate that struct into equivalent Go struct.
If a Go source file uses any //export
directives, then the C code in the comment may only include declarations (extern int f();
), not definitions (int f() { return 1; }
or int n;
).
Note: you can use static inline
trick to work around this restriction for tiny functions defined
in the preamble (see above for a complete example).
In order to use cgo on Windows, you'll also need to first install a gcc compiler (for instance, mingw-w64) and have gcc.exe (etc.) in your PATH environment variable before compiling with cgo will work.