Notes on cgo
Referencing c from go.
Basic operation
import “C” imports the C namespace into go, the comment just above this statement is treated as C.
/*
#include "add.h"
*/
"C" import
Everything you exported from c library is available in the C namespace.
func main() {
.Println(
fmt.add_two_numbers(3,4)
C)
}
Building code is as easy as go build
Accessing standard types are easy as C.char
, C.int
. For complex types, prepend the type name with an underscore at end – e.g C.struct_stat
.
Pointers and memory operations
Go provides an unsafe
module. Go’s GC cannot manage the memory allocated in C code, you should call C.free(unsafe.Pointer)
(free
is defined in <stdlib.h>
ensure that this library is imported) to deallocate.
There are some special functions which convert Go types to C types and vice versa. (lifted from cgo documentation)
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char
// C string to Go string
func C.GoString(*C.char) string
// C string, length to Go string
func C.GoStringN(*C.char, C.int) string
// C pointer, length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
Accessing complex objects
Accessing structs from Go
/*
struct person {
int age;
*/
// this can be used in go as
var p C.struct_person
.age = 23 p
You can also pass pointers
.function_accepts_ptr_to_struct(&p) C
Accessing Unions : No native counterpart, instead of converting it to a type, go treats them as a block of memory represented as byte array. Accessing data is done by casting unsafe.Pointer
/*
union quant {
float weight;
int count;
};
*/
var q C.union_quant
:= (*float32)(unsafe.Pointer(&q))
ptr *ptr = 3.14
Extra goodies
Compiler Flags
Compiler flags can be set using the #cgo
directive. (CFLAGS
, LDFLAGS
etc)
/*
#cgo: LDFLAGS: -lmath
#include <math.h>
*/
import "C"
Restricting building
In many cases using cgo breaks the portability of your app, use build constraints to specify compatibility in source. Build constraints are comments which begin with
// +build
Now, build comment must appear before package clause and should be followed by a blank line To restrict building just to Linux with cgo,
// +build linux,cgo !darwin
package main
These are evaluated as OR
of each constraint so the above line becomes (linux AND cgo) OR (NOT darwin)
, also multiple build tags can be embedded in file.
There are other methods to restrict builds, see references.