Go & cgo: integrating existing C code with Go

Andreas Krennmair <ak@synflood.at>

Golang User Group Berlin

Twitter: @der_ak

Introduction

cgo: Basic Steps

  1. start a new .go source file
  2. import "C"
  3. embed the C code you want to interface as comment (e.g. #include <foo.h>) prior to the import
  4. Imported C functions, types and global variables are available under the virtual "C" package
  5. Add CGOFILES=foo.go to your Makefile
  6. optional: #cgo preprocessor instructions to set C defines and linker flags

Yes, it's that simple.

First Example

package pwnam
/*
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
*/
import ( "C" ; "unsafe" )

type Passwd struct {
	Uid uint32 ; Gid uint32 ; Dir string ; Shell string
}

func Getpwnam(name string) *Passwd {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))
	cpw := C.getpwnam(cname)
	return &Passwd{
		Uid: uint32(cpw.pw_uid), Gid: uint32(cpw.pw_uid),
		Dir: C.GoString(cpw.pw_dir), Shell: C.GoString(cpw.pw_shell)}
}

Linking

Linking Examples

Mapping the C namespace to Go

Conversion between C and Go strings

// Go string to C string; result must be freed with C.free
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

Calling Go code from C (1)

package foo

/*
extern void myprint(int i);

void dofoo(void) {
	int i;
	for (i=0;i<10;i++) {
		myprint(i);
	}
}
*/
import "C"

Calling Go code from C (2)

//export myprint
func myprint(i C.int) {
	fmt.Printf("i = %v\n", uint32(i))
}

func DoFoo() {
	C.dofoo()
}

Questions?

Useful Links: