C++ (g++) linker error linking dependent static libraries to createexecutable

  • Thread starter sriram.sundararajan
  • Start date
S

sriram.sundararajan

I'm battling a linker issue. Here is the scenario. I have two static
libraries libA.a and libB.b and am trying to create an executable
hello.exe from hello.cpp, libA.a and libB.a.

blah/
/libA
libA.h libA.cpp -----> libA.a <= A::printA(string arga)
/libB
libB.h libB.cpp ------> libB.a <= B::printB(string argb)
{ A().(argb) }
/src
hello.cpp

LibA contains class A, with method A::printA(string arga).
LibB contains class B with method B::printB(string argb) which calls
A().printA(argb).
hello.cpp invokes B().printB("Hello, World"). When I compiled libB, I
did not link with libA.a as I wanted to keep the libraries separate.
My "real world" libraries are way way larger.

So I created static libraries libA.a and libB.a. When I tried to
create hello.exe using,

g++ -W -Wall -pipe -g -o main.exe main.o -Lblah/src -Lblah/lib1 -
Lblah/lib2 blah/lib1/libA.a blah/lib2/libB.a

I got this....

blah/lib2/libB.a(libB.o): In function `ZN1B1aESs':
blah/lib2/libB.cpp:9: undefined reference to `A::printB(std::string)'
blah/lib2/libB.a(libB.o): In function `ZN1B1bEi':
blah/lib2/libB.cpp:15: undefined reference to `A::printA(int)'
collect2: ld returned 1 exit status
make: *** [debug/main.exe] Error

I am sure
1. I used my -L and -l options right
2. I used nm to verify the symbols are actually in both the libraries.
(A in libA and B in libB. There are 'U'ndefined references to A in
libB though).
3. The methods are public
4. I tried ordering the libraries differently in the -l option. Here
there are only 2 possibilities I guess.

I am using MinGW. Any suggestions? Why does this occur? My google-fu
has failed me the past couple of days. I would like to keep the
libraries separate. combining libs A and B does work. I'm puzzled as
to why this approach does not work. The symbol definitions are
definitely present in both the libraries.

I am guessing that since hello calls B::b, libB gets linked first and
the process of linking, the linker(?) tries to lookup all symbols in
B, including A. Since A has not been linked in, we are getting this
error. I tried defining A first in hello.cpp and invoked A().printA
before invoking B. This actually took care of the linker errors. I
Can't do that in real life! I would also prefer to keep the libraries
static.

Thanks
Sriram
 
V

Victor Bazarov

I'm battling a linker issue. Here is the scenario. I have two static
libraries libA.a and libB.b and am trying to create an executable
hello.exe from hello.cpp, libA.a and libB.a.

blah/
/libA
libA.h libA.cpp -----> libA.a <= A::printA(string arga)
/libB
libB.h libB.cpp ------> libB.a <= B::printB(string argb)
{ A().(argb) }
/src
hello.cpp

LibA contains [..]

Your issue has nothing to do with the language. Please post your
g++ question to the g++ newsgroup: gnu.g++.help.

V
 
J

James Kanze

I'm battling a linker issue. Here is the scenario. I have two static
libraries libA.a and libB.b and am trying to create an executable
hello.exe from hello.cpp, libA.a and libB.a.
blah/
/libA
libA.h libA.cpp -----> libA.a <= A::printA(string arga)
/libB
libB.h libB.cpp ------> libB.a <= B::printB(string argb)
{ A().(argb) }
/src
hello.cpp
LibA contains class A, with method A::printA(string arga).
LibB contains class B with method B::printB(string argb) which calls
A().printA(argb).
hello.cpp invokes B().printB("Hello, World"). When I compiled libB, I
did not link with libA.a as I wanted to keep the libraries separate.
My "real world" libraries are way way larger.
So I created static libraries libA.a and libB.a. When I tried to
create hello.exe using,
g++ -W -Wall -pipe -g -o main.exe main.o -Lblah/src -Lblah/lib1 -
Lblah/lib2 blah/lib1/libA.a blah/lib2/libB.a

Why not?

g++ -W -Wall -pipe -g -o main.exe main.o \
-Lblah/src -Lblah/lib1 - Lblah/lib2 -lA -lB

The purpose of the -L option is to allow the shorthand use of
-l.

Of course, you'll still have the problem, since A::printA isn't
an unresolved extern when you link in libA.a.
I got this....
blah/lib2/libB.a(libB.o): In function `ZN1B1aESs':
blah/lib2/libB.cpp:9: undefined reference to `A::printB(std::string)'
blah/lib2/libB.a(libB.o): In function `ZN1B1bEi':
blah/lib2/libB.cpp:15: undefined reference to `A::printA(int)'
collect2: ld returned 1 exit status
make: *** [debug/main.exe] Error
I am sure
1. I used my -L and -l options right

You didn't in the example.
2. I used nm to verify the symbols are actually in both the
libraries. (A in libA and B in libB. There are 'U'ndefined
references to A in libB though).

Then B must be linked in first.

The rest is really very gcc specific, but in general, linkers
work in one of two ways: most (including gcc and all Unix based
compilers I'm familiar with) process the files in the order they
are given; a few (VC++, for example), collect the libraries, and
process them as if they were a single library, after having
processed all of the object files. Generally, the first gives
you considerably more control, but requires exposing your
dependencies to the user. (FWIW, I once used a linker which not
only processed the libraries in order, but processed each
library sequentially. Even within a library, you had to do a
topological sort on the dependencies to ensure the order.)
3. The methods are public
4. I tried ordering the libraries differently in the -l option. Here
there are only 2 possibilities I guess.

No you didn't. Or you have other dependencies, which create a
cycle.
I am using MinGW. Any suggestions? Why does this occur? My
google-fu has failed me the past couple of days. I would like
to keep the libraries separate. combining libs A and B does
work. I'm puzzled as to why this approach does not work. The
symbol definitions are definitely present in both the
libraries.
I am guessing that since hello calls B::b, libB gets linked
first and the process of linking, the linker(?) tries to
lookup all symbols in B, including A.

These are libraries, not object files. The compiler processes
them in the order they occur, incorporating modules which
resolve unresolved external symbols, and only those modules.
Since when the compiler processes your libA.a, there is no
unresolved symbol A::printA, so the module which contains it is
not incorporated into the program. When the compiler later
processes libB.a, it finds an unresolved external for A::printA,
but there is nothing left to resolve it.
 
S

sriram.sundararajan

g++ -W -Wall -pipe -g -o main.exe main.o -Lblah/src -Lblah/lib1 -
Why not?

g++ -W -Wall -pipe -g -o main.exe main.o \
-Lblah/src -Lblah/lib1 - Lblah/lib2 -lA -lB

The purpose of the -L option is to allow the shorthand use of
-l.
Yes you could do that. I tried it, but what I posted was the command
generated by libtool in my Makefile. Sorry for the confusion.
Of course, you'll still have the problem, since A::printA isn't
an unresolved extern when you link in libA.a.
Right.
I got this....
blah/lib2/libB.a(libB.o): In function `ZN1B1aESs':
blah/lib2/libB.cpp:9: undefined reference to `A::printB(std::string)'
blah/lib2/libB.a(libB.o): In function `ZN1B1bEi':
blah/lib2/libB.cpp:15: undefined reference to `A::printA(int)'
collect2: ld returned 1 exit status
make: *** [debug/main.exe] Error
I am sure
1. I used my -L and -l options right

You didn't in the example.

You mean I should've used -lA and -lB instead of specifying the paths
to libA.a and libB.b? I think they are equivalent. Admittedly what I
posted was a longer form, but that output was expanded to blah/lib1/
libA.a from the -lA option I specified in the Makefile by libtool.
Either way, they are one and the same or at least that is my
understanding.
Then B must be linked in first.
Yup. Tried it and it worked! Thanks. I kept thinking that A must be
linked in first. Your explanation in the last paragraph explained why
linking in A first didn't work :).
The rest is really very gcc specific, but in general, linkers
work in one of two ways: most (including gcc and all Unix based
compilers I'm familiar with) process the files in the order they
are given; a few (VC++, for example), collect the libraries, and
process them as if they were a single library, after having
processed all of the object files.
Thanks, I did not know that about VC++! But it does make sense!

(FWIW, I once used a linker which not
only processed the libraries in order, but processed each
library sequentially. Even within a library, you had to do a
topological sort on the dependencies to ensure the order.)
Your pain was far greater than mine :)!
No you didn't.
Ofcourse I didn't! I tried so many things, I thought I obviously did
something as simple as reversing the order or libraries linked!

These are libraries, not object files. The compiler processes
them in the order they occur, incorporating modules
which resolve unresolved external symbols, and only those modules.
Since when the compiler processes your libA.a, there is no
unresolved symbol A::printA, so the module which contains it is
not incorporated into the program.
Nice! Makes perfect sense now.

When the compiler later
processes libB.a, it finds an unresolved external for A::printA,
but there is nothing left to resolve it.

Thanks
Sriram
 
J

James Kanze

I got this....
blah/lib2/libB.a(libB.o): In function `ZN1B1aESs':
blah/lib2/libB.cpp:9: undefined reference to `A::printB(std::string)'
blah/lib2/libB.a(libB.o): In function `ZN1B1bEi':
blah/lib2/libB.cpp:15: undefined reference to `A::printA(int)'
collect2: ld returned 1 exit status
make: *** [debug/main.exe] Error
I am sure
1. I used my -L and -l options right
You didn't in the example.
You mean I should've used -lA and -lB instead of specifying the paths
to libA.a and libB.b?

No, I mean you should have specified libB before libA.
I think they are equivalent.

They are IF the -L flags are set correctly, and IF the libraries
are names correctly. Almost, anyway: if you specify -lA, and
there is both a libA.a and a libA.so in the same directory,
which one you'll get will depend on various compiler options
(but by default is the .so). If you specify <path>/libA.a, then
you'll get the statically linked one.

In fact, I almost always use the pathname (as you did in your
example) for my own libraries, leaving -l for libraries which
the compiler should search in "standard places".

[...]
(FWIW, I once used a linker which not> only processed the
libraries in order, but processed each
Your pain was far greater than mine :)!

It did encourage one to avoid cyclic dependencies, which isn't
bad:). And there was a tool to order the libraries. But yes, it
was a bit drastic.
 
K

Krishanu Debnath

James Kanze wrote:
[snip]
It did encourage one to avoid cyclic dependencies, which isn't
bad:). And there was a tool to order the libraries. But yes, it
was a bit drastic.

May I know the name of the tool? Thank you.

Krishanu
 
J

James Kanze

James Kanze wrote:
[snip]
It did encourage one to avoid cyclic dependencies, which isn't
bad:). And there was a tool to order the libraries. But yes, it
was a bit drastic.
May I know the name of the tool? Thank you.

Sure: the system linker for OS-16 and OS-32 on the Interdata
systems.

I doubt you'll run into it:). (Although IIRC, the Interdata
8/32 was the second architecture to get a C compiler, after the
PDP-11.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,701
Latest member
XavierQ83

Latest Threads

Top