This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: g++ isn't link an indirectly used .a library


Michael Darling wrote:

> I'm not sure if this is an issue with my KDevelop settings, or rather
> if it is a g++ problem. If it's a g++ problem, I'm wondering if

First of all, realise that g++ doesn't have any say in the matter.  g++
invokes collect2 which invokes the linker (ld), and it's the linker that
issues the error.  g++ is just a driver to invoke the linker with some
extra options, it doesn't actually do any linking.  (But you should
always link by calling the driver and not 'ld' precisely because those
extra options that the driver adds behind the scenes are vital.)

The second thing to realize is that the linker scans each object/archive
incrementally in the order specified on the command line from left to
right.  When scanning an archive (.a), if any objects in that archive
contain symbols that satisfy references that the linker has seen so far
but not yet resolved, those objects get copied from the archive into the
output.  Any remaining objects in the archive are ignored.  In other
words, when the linker examines an archive it can only use it to resolve
symbols that it knows are necessary at that point in the process.  If
some object or library later down the line refers to a symbol in one of
the objects that was not copied, it will result in an undefined
reference because the linker only examines each argument once in the
order specified.

The implication of this is that you must supply arguments in the correct
order of dependency.  Furthermore, if there is a circular dependency,
you must specify some arguments twice, e.g. if liba and libb mutally
refer to symbols in each other then you would need to specify something
like "liba.a libb.a liba.a".

The linker also has alternative ways of dealing with the problem, such
as the --start-group and --end-group options, or the --whole-archive
option.  See the ld manpage for details.  Note also that since these are
linker options, you must use -Wl when specifying them to g++ so that the
driver will pass them through to the linker rather than trying to
interpret them as compiler options, which they are not.  For example,
instead of "../../liba/liba.a ../../libb/libb.a" you might need "-Wl,-(
../../liba/liba.a ../../libb/libb.a -Wl,-)" to tell the linker that
there's a circular dependency between the two.

I should also note that as stated (app only depends on liba, and liba
only depends on libb) that your command:

> g++ -g -O2 -o app app.o -L/usr/lib/mysql ../../liba/liba.a
> ../../libb/libb.a -lmysqlclient
> ../../liba/liba.a(liba.o): In function `@@@`:
> liba.cpp:@: undefined reference to `libb::@@@`
> collect2: ld returned 1 exit status

...seems correct and should work.  But the fact that it does not
suggests that there is some additional circular dependency that exists
between liba and libb that you're not aware of, perhaps in something
unobvious like a constructor for a static object.

If you use the linker's --verbose option (i.e. g++ -Wl,--verbose) it
will show you explicitly the order in which archives and objects are
processed, and which objects get included into the final link. 
Hopefully you can compare the verbose output from the working and the
non-working case and see the nature of the liba<->libb interdependency.

> If I change app's main() from:
> libAClass goingToUseThis();
> 
> to:
> libBClass hack();
> libAClass goingToUseThis();
> 
> Then it links fine.

When you do this, ld sees a reference to libBClass at the point where it
scans app.o, which is apparently sufficiently early enough in the
process to cause it to link the necessary objects from libb.a when it is
later encountered.

> Is there a way for me to forces g++ to actually link libb.a, when app
> is only directly using liba.a? I'm suprised g++ can't figure out that
> libb.a really has to be linked since it's being told to do so through
> the arguments given.  Then again, maybe I'm missing something
> simple...

You need to have a better mental model of how linking works.  It's not a
yes/no "should I include this library or not" kind of deal (and it's not
even g++ that is at work here.)  It's more like "I will scan this
archive and from it copy any objects that satisfy undefined references
that I've encountered so far" -- the key words being "so far", as it's
impossible for the linker to know beforehand what it will need out of a
given archive unless it's already scanned every object that might
reference something in that archive.

The reason that the linker cannot simply consider everything at once in
whole is performance.  It might not matter on small projects but on
medium or large sized links it would be prohibitively slow if it worked
that way.  I suppose you could force it to operate that way by grouping
all arguments into one giant --begin-group/--end-group, but I think you
would experience a significant increase in link time for anything of
size.

> I'm using versions all included in the default RHEL5 yum repositories.
> KDevelop 3.5.1, g++ 4.1.2, automake 1.9.6, autoconf 2.59.

Note that the linker is not part of gcc.  On GNU/Linux systems the
linker is part of the binutils package.  Also note that in some
circumstances and on some platforms, the rules are different, e.g. with
shared libraries on GNU/Linux the order given on the link command
doesn't matter because the symbols are resolved at run-time anyway as
opposed to link-time.  But that shouldn't be license to ignore proper
dependency-ordering on the link command, since it does matter even for
shared libraries on other platforms, and it always matters for static
libraries (.a archives.)

Brian


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]