cgo static linking

2,010 views
Skip to first unread message

wermut

unread,
Jun 23, 2013, 4:13:33 PM6/23/13
to golan...@googlegroups.com
Today I used for the first time the net/http module and unfortunately the resulting binary was dynamically linked against libc.so etc. http://pastebin.com/1i1741x1

I have found the following topic and understand that under certain cases cgo1 links dynamically: https://groups.google.com/forum/#!msg/golang-nuts/ZHJV1H99Uzs/z6cvEKwdFCwJ

Is there any progress within cgo regarding static linking?

Regards
wermut

Carlos Castillo

unread,
Jun 24, 2013, 5:47:50 AM6/24/13
to golan...@googlegroups.com, ke...@bortis.ch
First of all, the libraries in question (libc.so, which imports the others), are essentially guaranteed to exist on just about any linux machine, so you should be fine if those are your app's only needed dynamic libraries. In darwin (Mac OS X) not only are the equivalent libraries (libSystem.B.dylib, and its dependencies) guaranteed to exist, but AFAIK, it is impossible to find equivalent static libraries. On Windows, the OS doesn't provide a single statically linked library at all, so all binaries must be dynamically linked there. Essentially, if your only dynamic links are against system libraries, which is the case for the net package (imported by net/http), then there isn't a dependency issue as the library you need should always be there.

As far as your second question goes, go1.1 suports what is called "external" linking, where the system linker is invoked after the go-provided one (6l, 8l, or 5l) to actually perform the final link, and thus supports the full range of features needed to statically link most code properly. As an example, the SQLite package at http://code.google.com/p/go-sqlite provides the source code for SQLite and statically links the produced library into your binaries, something that couldn't be done in go 1.0 with the "internal" linker. The "external" linking method should be enabled automatically if you use CGO, although a recent bug has been discovered in the binary distribution of go1.1.1 on darwin (https://code.google.com/p/go/issues/detail?id=5726). Note: the "external" linking mode doesn't enforce static linking, it is just better supported; Go will still link to dynamic libraries if any are specified by the cgo arguments, and in the case of the above, there may not be statically linked versions of the libraries it uses.

It is possible to build the go environment without using CGO at all; by setting CGO_ENABLED=0 before building go from source. The packages that use cgo in the std library (net and os/user) will still build, but have limited functionality then. For the net package, name resolution (net.Lookup*) is normally handled by cgo code because it will then use the same C code that every other program on the system uses and thus produce the same results. If cgo is disabled, a mechanism written in go will be used instead, and it will most likely produce different and fewer results. For os/user, the non-cgo code always returns an error.

A recent update in tip adds the build tag netgo, which builds the net package to not use cgo without disabling cgo entirely, or needing to rebuild go. So you can build you program using the following command: "go build -tags netgo -a", and it will build your binary, and rebuild all needed packages with the netgo build tag set. You need the build all flag "-a" since the go tool doesn't (yet) rebuild a package if it was built with different build tags than are currently set. 

Ian Lance Taylor

unread,
Jun 24, 2013, 8:28:14 AM6/24/13
to wermut, golan...@googlegroups.com
Try

go build -ldflags "-linkmode external -extldflags -static"

Ian

Aram Hăvărneanu

unread,
Jun 24, 2013, 8:47:40 AM6/24/13
to Ian Lance Taylor, wermut, golang-nuts
> go build -ldflags "-linkmode external -extldflags -static"

Just remember that glibc uses dlopen(3), and you can't have a truly
statically compiled binary anyway.

--
Aram Hăvărneanu

ke...@bortis.ch

unread,
Jun 24, 2013, 10:47:27 AM6/24/13
to golan...@googlegroups.com, Ian Lance Taylor, wermut
What about using a smaller embedded libc like musl (musl-libc.org) or bionic? How would I do that? At least it would allow cgo to fully stattically link, at least on *nix like systems. Glibc is anyway to bloated for static linking.
Reply all
Reply to author
Forward
0 new messages