Andrew Gerrand 17 March 2011
Cgo lets Go packages call C code. Given a Go source file written with some special features, cgo outputs Go and C files that can be combined into a single Go package.
To lead with an example, here's a Go package that provides two functions - Random and Seed - that wrap C's random and srandom functions.
Random
Seed
random
srandom
package rand /* #include <stdlib.h> */ import "C" func Random() int { return int(C.random()) } func Seed(i int) { C.srandom(C.uint(i)) }
Let's look at what's happening here, starting with the import statement.
The rand package imports "C", but you'll find there's no such package in the standard Go library. That's because C is a "pseudo-package", a special name interpreted by cgo as a reference to C's name space.
rand
"C"
C
The rand package contains four references to the C package: the calls to C.random and C.srandom, the conversion C.uint(i), and the import statement.
C.random
C.srandom
C.uint(i)
import
The Random function calls the standard C library's random function and returns the result. In C, random returns a value of the C type long, which cgo represents as the type C.long. It must be converted to a Go type before it can be used by Go code outside this package, using an ordinary Go type conversion:
long
C.long
func Random() int { return int(C.random()) }
Here's an equivalent function that uses a temporary variable to illustrate the type conversion more explicitly:
func Random() int { var r C.long = C.random() return int(r) }
The Seed function does the reverse, in a way. It takes a regular Go int, converts it to the C unsigned int type, and passes it to the C function srandom.
int
unsigned int
func Seed(i int) { C.srandom(C.uint(i)) }
Note that cgo knows the unsigned int type as C.uint; see the cgo documentation for a complete list of these numeric type names.
C.uint
The one detail of this example we haven't examined yet is the comment above the import statement.
/* #include <stdlib.h> */ import "C"
Cgo recognizes this comment. Any lines starting with #cgo followed by a space character are removed; these become directives for cgo. The remaining lines are used as a header when compiling the C parts of the package. In this case those lines are just a single #include statement, but they can be almost any C code. The #cgo directives are used to provide flags for the compiler and linker when building the C parts of the package.
#cgo
#include
There is a limitation: if your program uses any //export directives, then the C code in the comment may only include declarations (extern int f();), not definitions (int f() { return 1; }). You can use //export directives to make Go functions accessible to C code.
//export
extern int f();
int f() { return 1; }
The #cgo and //export directives are documented in the cgo documentation.
Unlike Go, C doesn't have an explicit string type. Strings in C are represented by a zero-terminated array of chars.
Conversion between Go and C strings is done with the C.CString, C.GoString, and C.GoStringN functions. These conversions make a copy of the string data.
C.CString
C.GoString
C.GoStringN
This next example implements a Print function that writes a string to standard output using C's fputs function from the stdio library:
Print
fputs
stdio
package print // #include <stdio.h> // #include <stdlib.h> import "C" import "unsafe" func Print(s string) { cs := C.CString(s) C.fputs(cs, (*C.FILE)(C.stdout)) C.free(unsafe.Pointer(cs)) }
Memory allocations made by C code are not known to Go's memory manager. When you create a C string with C.CString (or any C memory allocation) you must remember to free the memory when you're done with it by calling C.free.
C.free
The call to C.CString returns a pointer to the start of the char array, so before the function exits we convert it to an unsafe.Pointer and release the memory allocation with C.free. A common idiom in cgo programs is to defer the free immediately after allocating (especially when the code that follows is more complex than a single function call), as in this rewrite of Print:
unsafe.Pointer
defer
func Print(s string) { cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) C.fputs(cs, (*C.FILE)(C.stdout)) }
To build cgo packages, just use go build or go install as usual. The go tool recognizes the special "C" import and automatically uses cgo for those files.
go build
go install
The cgo command documentation has more detail about the C pseudo-package and the build process. The cgo examples in the Go tree demonstrate more advanced concepts.
Finally, if you're curious as to how all this works internally, take a look at the introductory comment of the runtime package's cgocall.go.