Graham King

Solvitas perambulum

Building shared libraries in Go: Part 1

software go
Summary
Since version 1.5, I can create C-style shared libraries (.so) in Go that are usable from C, C++, and most other languages that support C shared libraries. To demonstrate, I wrote a simple Go program that exports a function, `DoubleIt`, which doubles an integer. I saved this in my `GOPATH` as `doubler/main.go` and built it using the command `go build -o libdoubler.so -buildmode=c-shared doubler`. After confirming it was a valid shared library with the `file` and `nm` commands, I called `DoubleIt` from Python using the `ctypes` library, successfully returning 42. This capability elevates Go's status as a first-class language on Unix, and I plan to explore more complex examples with C++ and SWIG in the future.

Since 1.5, we can write C-style shared libraries (.so) in Go. These can be used directly from C and C++, but also from any language that can use a C shared library, which is most languages. Here’s the original design document. Let’s do a very simple example and call it from Python. In Part 2 we’ll do a more complex example and call it from C++.

Calling Go from Python

package main

import "C"

//export DoubleIt
func DoubleIt(x int) int {
        return x * 2
}

func main() {}

Save that in your GOPATH as doubler/main.go. The exported symbols (the functions the shared library provides) must be in a main package, with a required but ignored main function. They must be marked with magic comment //export <name> (no space), because go build will call cgo.

go build -o libdoubler.so -buildmode=c-shared doubler

This puts libdoubler.so in your current directory. Let’s check we really have a dynamic shared library:

$ file libdoubler.so
libdoubler.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked ...

$ nm -D libdoubler.so | grep "T DoubleIt"
000000000005d230 T DoubleIt

Well that looks good. Let’s call it from Python, because Python’s ctypes makes this incredibly easy:

>>> import ctypes
>>> lib = ctypes.CDLL("libdoubler.so")
>>> lib.DoubleIt(21)
42

Ta da!

For me this ability to build normal shared libraries makes Go a first-class language on Unix. In later posts we’ll do a more complex example with C++, and time permitting a SWIG example with Ruby.