July 15, 2015
Building shared libraries in Go: Part 1
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.
Dylan Hicks said,
March 14, 2017 at 20:30
How would Ctypes, in Python, deal with Go’s multiple return values?
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.Marko said,
August 23, 2015 at 12:26
Ok, I have figured it out. You have import “C” missing.
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?
Gabriel Adumitrachioaiei said,
August 18, 2015 at 23:14
Doesn’t export anything unless I also import C: import “C”
Gabriel said,
July 17, 2015 at 04:07
Thanks Graham! This was a good read! Keep ’em coming! :)
Juquinha said,
July 15, 2015 at 13:41
“… makes Go a first-class language on Unix.” Yes, this will be great!
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.
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?