The status with static linking

739 views
Skip to first unread message

Petar Maymounkov

unread,
Apr 3, 2013, 12:29:50 PM4/3/13
to golan...@googlegroups.com

I haven't seen much speak about CGO static linking *.a files lately.

That said, I few months ago I started being able to link libzookeeper_mt.a into Go programs that us gozk, statically!

Simply by setting: LDFLAGS=..../libzookeeper_mt.a

I would have assumed that static linking works now, but then I lately had a problem
linking libleveldb.a (for levigo) in a manner similar to zookeeper. 

So, in particular:

LDFLAGS=/.../libleveldb.a -lstdc++

produces error messages. These errors however are about stdc++ missing (not leveldb):

Undefined symbols for architecture x86_64:
  "std::basic_string<char, std::char_traits<char>, std::allocator<char> >::data() const", referenced from:
      _leveldb_get in 000002.o
      leveldb::DBImpl::Write(leveldb::WriteOptions const&, leveldb::WriteBatch*)in 000002.o
      leveldb::DBImpl::WriteLevel0Table(leveldb::MemTable*, leveldb::VersionEdit*, leveldb::Version*)in 000002.o
      leveldb::DBImpl::DoCompactionWork(leveldb::DBImpl::CompactionState*)in 000002.o
      leveldb::DBImpl::NewDB()    in 000002.o
      leveldb::DBImpl::Recover(leveldb::VersionEdit*)in 000002.o
      leveldb::(anonymous namespace)::DBIter::value() constin 000002.o
      ...

Which is odd.

Does anyone know what is going on here? Why -lstdc++ does not link me the c++ std library?

Any high level comments on static linking with cgo these days?

Thank
P

Petar Maymounkov

unread,
Apr 3, 2013, 3:11:48 PM4/3/13
to golan...@googlegroups.com
I can say additionally that:

CGO_LDFLAGS = -L/Users/petar/aux/leveldb/lib -lleveldb -lstdc++

works on Linux, not on Darwin. 

And

CGO_LDFLAGS=/Users/petar/aux/leveldb/lib/libleveldb.a -lstdc++

does not work on either Darwin or Linux.

P

Rémy Oudompheng

unread,
Apr 3, 2013, 3:15:29 PM4/3/13
to Petar Maymounkov, golang-nuts
2013/4/3 Petar Maymounkov <pet...@gmail.com>:
>
> I haven't seen much speak about CGO static linking *.a files lately.
>
> That said, I few months ago I started being able to link libzookeeper_mt.a
> into Go programs that us gozk, statically!
>
> Simply by setting: LDFLAGS=..../libzookeeper_mt.a
>
> I would have assumed that static linking works now, but then I lately had a
> problem
> linking libleveldb.a (for levigo) in a manner similar to zookeeper.
>
> So, in particular:
>
> LDFLAGS=/.../libleveldb.a -lstdc++
>
> produces error messages. These errors however are about stdc++ missing (not
> leveldb):
>
> Undefined symbols for architecture x86_64:
> "std::basic_string<char, std::char_traits<char>, std::allocator<char>
>>::data() const", referenced from:

Please run the go tool with the -x option to show the commands
actually launched.

Rémy.

Petar Maymounkov

unread,
Apr 3, 2013, 3:22:06 PM4/3/13
to Rémy Oudompheng, golang-nuts
Sure.

go version devel +47053fd8f41e Tue Apr 02 20:58:25 2013 -0700 darwin/amd64

CGO_LDFLAGS=/Users/petar/gocircuit/misc/starter-kit-osx/zookeeper/lib/libzookeeper_mt.a
-L/Users/petar/aux/leveldb/lib -lleveldb -lstdc++
CGO_CFLAGS=-I/Users/petar/gocircuit/misc/starter-kit-osx/zookeeper/include
-I/Users/petar/aux/leveldb/include

go build -x -a <--- attached
xxx

Marcelo

unread,
Apr 3, 2013, 3:23:31 PM4/3/13
to golang-nuts
On Wed, Apr 3, 2013 at 10:29 AM, Petar Maymounkov <pet...@gmail.com> wrote:
> Undefined symbols for architecture x86_64:
> "std::basic_string<char, std::char_traits<char>, std::allocator<char>
>>::data() const", referenced from:
> _leveldb_get in 000002.o

That's a template. It must be instantiated somewhere in your code (or
leveldb's code in this case). It might have something to do with the
_order_ in which you are specifying the static libraries (or object
files in general).

Maybe this is related: are you sure you are trying to link using the
C++ compiler frontend and _not_ the C compiler one?

Marcelo

Rémy Oudompheng

unread,
Apr 3, 2013, 3:28:00 PM4/3/13
to Petar Maymounkov, golang-nuts
On 2013/4/3 Petar Maymounkov <pet...@gmail.com> wrote:
> Sure.
>
> go version devel +47053fd8f41e Tue Apr 02 20:58:25 2013 -0700 darwin/amd64
>
> CGO_LDFLAGS=/Users/petar/gocircuit/misc/starter-kit-osx/zookeeper/lib/libzookeeper_mt.a
> -L/Users/petar/aux/leveldb/lib -lleveldb -lstdc++
> CGO_CFLAGS=-I/Users/petar/gocircuit/misc/starter-kit-osx/zookeeper/include
> -I/Users/petar/aux/leveldb/include
>
> go build -x -a <--- attached

You have to use -linkmode external for static linking to work and you
are not using it. Enable it or try on linux.

Rémy.

Petar Maymounkov

unread,
Apr 3, 2013, 3:47:50 PM4/3/13
to Marcelo, golang-nuts
How can I tell which front-end I am using?
> --
> You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/yiRbLQC3mLg/unsubscribe?hl=en-US.
> To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Ian Lance Taylor

unread,
Apr 3, 2013, 4:44:54 PM4/3/13
to Marcelo, golang-nuts
On Wed, Apr 3, 2013 at 12:23 PM, Marcelo <marcelo....@gmail.com> wrote:
> On Wed, Apr 3, 2013 at 10:29 AM, Petar Maymounkov <pet...@gmail.com> wrote:
>> Undefined symbols for architecture x86_64:
>> "std::basic_string<char, std::char_traits<char>, std::allocator<char>
>>>::data() const", referenced from:
>> _leveldb_get in 000002.o
>
> That's a template. It must be instantiated somewhere in your code (or
> leveldb's code in this case). It might have something to do with the
> _order_ in which you are specifying the static libraries (or object
> files in general).

That particular template is instantiated in the libstdc++ library
itself. But, yes, ordering matters.

> Maybe this is related: are you sure you are trying to link using the
> C++ compiler frontend and _not_ the C compiler one?

I don't know if this will make a difference, but in particular it may
be worth trying
go build -ldflags='-extld g++'

Ian

Ian Lance Taylor

unread,
Apr 3, 2013, 4:45:55 PM4/3/13
to Petar Maymounkov, Marcelo, golang-nuts
On Wed, Apr 3, 2013 at 12:47 PM, Petar Maymounkov <pet...@gmail.com> wrote:
> How can I tell which front-end I am using?

It should work to use
go build -x -ldflags=-v
to see how 6l invokes the external linker.

Ian

Petar Maymounkov

unread,
Apr 3, 2013, 5:13:05 PM4/3/13
to Ian Lance Taylor, Marcelo, golang-nuts
Thanks Ian. Your last comment, i.e.

go build -ldflags='-extld g++'

worked. I wish I could understand why. Is there a short explanation?

Thank you
Petar

Ian Lance Taylor

unread,
Apr 3, 2013, 8:35:38 PM4/3/13
to Petar Maymounkov, Marcelo, golang-nuts
On Wed, Apr 3, 2013 at 2:13 PM, Petar Maymounkov <pet...@gmail.com> wrote:
> Thanks Ian. Your last comment, i.e.
>
> go build -ldflags='-extld g++'
>
> worked. I wish I could understand why. Is there a short explanation?

Hmmm. I don't have one. I didn't really expect it to work.

The way to find out would be to pass the -v option with and without
the -extld option, and closely examine the difference in the external
linker command line.

Ian

Marcelo

unread,
Apr 4, 2013, 7:53:21 AM4/4/13
to golang-nuts
My educated guess is that (because this is static linking) it's a
combination of the two things I mentioned: order matters, and using
the C++ frontend to link.

For example:

Marcelo

unread,
Apr 4, 2013, 8:07:18 AM4/4/13
to golang-nuts
I'm sorry, lately I've been managing to hit "Send" by accident all two often...
#include <string>
#include <iostream>

int main(int argc, char* argv[])
{
(void)argc;
(void)argv;
std::string s("foo");
std::cout << s << std::endl;

return 0;
}

$ c++ -c test.cc
$ c++ -o test test.o

that works.

$ cc -o test test.o

that doesn't (fails with a message similar to Petar's).

$ cc -o test test.o -lstdc++

that works (gcc 4.7; Linux)

$ cc -static -o test test.o -lstdc++

that works.

$ cc -static -o test -lstdc++ test.o

that fails.

And:

$ c++ -static -o test test.o

that works.

By using c++ as the frontend, it just happens to add -lstdc++ (among
other things) in the right location, where the linker can actually see
the needed symbols before processing the objects (or archives) that
contain the definitions. With shared objects GCC behaves differently
in terms of symbol resolution, and that's why order doesn't seem to
matter. For other compilers order still matters, even in that case.
I'm not familiar with the OS X toolchain to be able to telll you why
the case you mentioned fails there (from the few times I've dealt with
it, I remember it's not a happy place).

I hope this helps,

Marcelo

Petar Maymounkov

unread,
Apr 4, 2013, 8:33:24 AM4/4/13
to Marcelo, golang-nuts
Oh, that's very informative! Thanks.
Reply all
Reply to author
Forward
0 new messages