July 15, 2015

Building shared libraries in Go: Part 1

Posted in Software at 03:22 by graham

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)

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.


  1. Dylan Hicks said,

    March 14, 2017 at 20:30

    How would Ctypes, in Python, deal with Go’s multiple return values?

  2. graham said,

    August 24, 2015 at 23:12

    @Marko, @Gabriel, thanks, yes it is missing import "C", I have added it. It was working without it in the beta of Go 1.5, but doesn’t in 1.5 final. Apologies.

  3. Marko said,

    August 23, 2015 at 12:26

    Ok, I have figured it out. You have import “C” missing.

  4. Marko said,

    August 23, 2015 at 12:23

    I am doing everything you did, but my library does not have DobleIt symbol:

    $ nm -D libdoubler.so | grep “DoubleIt” $

    Any ideas?

  5. Gabriel Adumitrachioaiei said,

    August 18, 2015 at 23:14

    Doesn’t export anything unless I also import C: import “C”

  6. Gabriel said,

    July 17, 2015 at 04:07

    Thanks Graham! This was a good read! Keep ’em coming! :)

  7. Juquinha said,

    July 15, 2015 at 13:41

    “… makes Go a first-class language on Unix.” Yes, this will be great!

  8. graham said,

    July 24, 2015 at 22:16

    @Ivan Part 1 intentionally had only the simplest possible example. I just posted Part 2, which answers your questions. It’s the same as with cgo: Passing pointers from C to Go is fine, Go’s GC will not reclaim that memory. Passing pointers from Go to C is not OK.

  9. Ivan said,

    July 15, 2015 at 11:02

    How does C interact with Go’s garbage collection? What happens if you pass a string or return a C buffer?

Leave a Comment

Note: Your comment will only appear on the site once I approve it manually. This can take a day or two. Thanks for taking the time to comment.