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"
 */
 import "C"

Everything you exported from c library is available in the C namespace.

func main() {
   fmt.Println(
     C.add_two_numbers(3,4)
   )
}

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
p.age = 23

You can also pass pointers

C.function_accepts_ptr_to_struct(&p)

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
ptr := (*float32)(unsafe.Pointer(&q))
*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.

Reference