cgo and static linking a lib ("*.a" archive) file

3,157 views
Skip to first unread message

Mitchell Hashimoto

unread,
Mar 25, 2014, 7:35:51 PM3/25/14
to golang-nuts
Hi,

I'm trying to statically link an ar archive file "libfoo.a" using cgo.
I tried this in the header of one my files:

// #cgo: LDFLAGS: libfoo.a
import "C"

And this actually makes "go build", "go test", etc. to all work fine
from that directory.

But when another library depends on that Go library, running `go test`
is getting me an error about clang not being able to find "libfoo.a".
Why is it even looking for that if I statically linked? (I clearly
didn't).

Also, I tried adding "-static" to the LDFLAGS but then I get errors
about libcrt0.a not being found, which looks like a weird gcc error to
me, and not sure why its looking for the runtime with Go.

Any tips?

Thanks,
Mitchell

Ian Lance Taylor

unread,
Mar 25, 2014, 9:18:05 PM3/25/14
to Mitchell Hashimoto, golang-nuts
On Tue, Mar 25, 2014 at 4:35 PM, Mitchell Hashimoto
<mitchell....@gmail.com> wrote:
>
> I'm trying to statically link an ar archive file "libfoo.a" using cgo.
> I tried this in the header of one my files:
>
> // #cgo: LDFLAGS: libfoo.a
> import "C"
>
> And this actually makes "go build", "go test", etc. to all work fine
> from that directory.
>
> But when another library depends on that Go library, running `go test`
> is getting me an error about clang not being able to find "libfoo.a".
> Why is it even looking for that if I statically linked? (I clearly
> didn't).

The static linking occurs at, well, link time. It does not occur when
you build the package itself, but when you build your main package.
At link time your main package is going to look for libfoo.a, and not
find it.

If possible, an easy workaround should be to use an absolute path to
libfoo.a.


> Also, I tried adding "-static" to the LDFLAGS but then I get errors
> about libcrt0.a not being found, which looks like a weird gcc error to
> me, and not sure why its looking for the runtime with Go.

I don't know what went wrong here, but libcrt0.a does not sound right.

Ian

Mitchell Hashimoto

unread,
Mar 26, 2014, 12:20:34 AM3/26/14
to Ian Lance Taylor, golang-nuts
Ian,

Thanks for the quick response. A real quick question below:

On Tue, Mar 25, 2014 at 6:18 PM, Ian Lance Taylor <ia...@golang.org> wrote:
> On Tue, Mar 25, 2014 at 4:35 PM, Mitchell Hashimoto
> <mitchell....@gmail.com> wrote:
>>
>> I'm trying to statically link an ar archive file "libfoo.a" using cgo.
>> I tried this in the header of one my files:
>>
>> // #cgo: LDFLAGS: libfoo.a
>> import "C"
>>
>> And this actually makes "go build", "go test", etc. to all work fine
>> from that directory.
>>
>> But when another library depends on that Go library, running `go test`
>> is getting me an error about clang not being able to find "libfoo.a".
>> Why is it even looking for that if I statically linked? (I clearly
>> didn't).
>
> The static linking occurs at, well, link time. It does not occur when
> you build the package itself, but when you build your main package.
> At link time your main package is going to look for libfoo.a, and not
> find it.
>
> If possible, an easy workaround should be to use an absolute path to
> libfoo.a.

Extremely obvious in retrospect, thanks!

One question: can I use env vars or something in that LDFLAGS param?
It'd be great if I could do `LDFLAGS: $GOPATH/blah`

Best,
Mitchell

Ian Lance Taylor

unread,
Mar 26, 2014, 1:48:21 AM3/26/14
to Mitchell Hashimoto, golang-nuts
On Tue, Mar 25, 2014 at 9:20 PM, Mitchell Hashimoto
<mitchell....@gmail.com> wrote:
>
> One question: can I use env vars or something in that LDFLAGS param?
> It'd be great if I could do `LDFLAGS: $GOPATH/blah`

You can't.

On the other hand, you can set CGO_LDFLAGS in the environment.

Ian

Bob Hemington

unread,
Mar 26, 2014, 1:49:57 AM3/26/14
to golan...@googlegroups.com, Ian Lance Taylor
I don't think so. I believe this is all related to relative paths not working in cgo LDFLAGS (issue 5428).

Stephen

Drew Wells

unread,
Dec 26, 2014, 9:11:34 AM12/26/14
to golan...@googlegroups.com
libcrt0.a is because OS X does not make available static libs for gcc (or static libs for any system level libraries).  I also am not getting static compiled libs using this mechanism.  The output bin is definitely larger when specifying libfoo.a, but I still get dynamic link errors from the output binary when dynamic libs are removed from system folder.

Marvin Humphrey

unread,
Dec 26, 2014, 12:21:22 PM12/26/14
to Drew Wells, golang-nuts
Hi,

Note: this thread has been revived from 9 months ago.

I'll comment below on one aspect of the original post which was never
addressed.

On Fri, Dec 26, 2014 at 6:11 AM, Drew Wells <drew.w...@gmail.com> wrote:
> libcrt0.a is because OS X does not make available static libs for gcc
> (or static libs for any system level libraries).

Indeed.

https://developer.apple.com/library/mac/qa/qa1118/_index.html

Apple does not support statically linked binaries on Mac OS X. A
statically linked binary assumes binary compatibility at the kernel
system call interface, and we do not make any guarantees on that
front. Rather, we strive to ensure binary compatibility in each
dynamically linked system library and framework.

> On Tuesday, March 25, 2014 6:35:51 PM UTC-5, Mitchell Hashimoto wrote:

>> I'm trying to statically link an ar archive file "libfoo.a" using
>> cgo. I tried this in the header of one my files:
>>
>> // #cgo: LDFLAGS: libfoo.a
>> import "C"
>>
>> And this actually makes "go build", "go test", etc. to all work fine
>> from that directory.
>>
>> But when another library depends on that Go library, running `go
>> test` is getting me an error about clang not being able to find
>> "libfoo.a". Why is it even looking for that if I statically linked?
>> (I clearly didn't).

This is a side effect of a subtle but documented behavior.

Let's say that the Go package which incorporates `libfoo.a` is named
`gofoo`. That "cgo: LDFLAGS" directive present in the `gofoo/gofoo.go`
source code gets added to the linker flags for **any** program which
incorporates `gofoo` -- such as the tests for that downstream package
which depends on `gofoo`.

http://golang.org/cmd/cgo/#hdr-Using_cgo_with_the_go_command

All the CPPFLAGS and CXXFLAGS directives in a package are
concatenated and used to compile C++ files in that package. All the
LDFLAGS directives in any package in the program are concatenated
and used at link time.

If you examine the `gofoo.a` file which gets installed under $GOPATH/pkg
as a result of `go build gofoo`, you will see that it does not contain
`libfoo.a`. (Interesting commands include `otool -L libfoo.a`,
`otool -t -v libfoo.a`, and `nm libfoo.a`.)

Since `libfoo.a` was not embedded in `gofoo.a` when `gofoo.a` was built,
`libfoo.a` must continue to remain available for as long as other
programs need to be built which `import "gofoo"`. However, at least
`libfoo.a` won't need to be present at runtime.

Marvin Humphrey
Reply all
Reply to author
Forward
0 new messages