help-gplusplus
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Cannot link against my own library due to undefined symbols???


From: Larry Smith
Subject: Re: Cannot link against my own library due to undefined symbols???
Date: Tue, 05 Feb 2008 19:59:46 GMT
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.11) Gecko/20070803 SUSE/1.1.7-0.1 SeaMonkey/1.1.7

Pep wrote:
> Using g++ 3.3.6 on various linux distro's.
> 
> I have a namespace spread over 4 source files called file1.h file1.cc
> file2.h file2.cc, which are built in to a static library. My problem
> is that I cannot link against the library I create. The symbols from
> the library used in the main routine are rejected as undefined. I have
> checked the mangled names in both the main routine and the library and
> they match.
> 
> g++ -I. -L. -ltest -o test-main main.cc
> /tmp/ccuB5As0.o: In function `main':
> main.cc:(.text+0x19): undefined reference to
> `ns1::derived_class::derived_class()'
> main.cc:(.text+0x29): undefined reference to
> `ns1::derived_class::~derived_class()'
> collect2: ld returned 1 exit status
> 
> Yet if I compile and link the objects in one unit, everything is fine,
> as shown by the following
> 
> g++ -I. -o test-main main.cc file1.cc file2.cc
> 
> ./test-main
> ns1::base_class::base_class()
> ns1::derived_class::derived_class()
> ns1::derived_class::~derived_class()
> ns1::base_class::~base_class()
> 
> Here's the working source files that demonstrate the problem, with the
> output of the build steps at the end
> 
> // file1.h
> #ifndef X__FILE1_H__X
> #define X__FILE1_H__X
> 
> namespace ns1
> {
>         class base_class
>         {
>                 public:
>                         base_class();
>                         ~base_class();
>         };
> }
> #endif // X__FILE1_H__X
> 
> // file 1.cc
> #include <file1.h>
> 
> #include <iostream>
> 
> ns1::base_class::base_class()
> {
>         std::cout << "ns1::base_class::base_class()" << std::endl;
> }
> 
> ns1::base_class::~base_class()
> {
>         std::cout << "ns1::base_class::~base_class()" << std::endl;
> }
> 
> // file2.h
> #ifndef X__FILE2_H__X
> #define X__FILE2_H__X
> 
> #include <file1.h>
> 
> namespace ns1
> {
>         class derived_class
>                 : public base_class
>         {
>                 public:
>                         derived_class();
>                         ~derived_class();
>         };
> }
> #endif // X__FILE2_H_X
> 
> // file2.cc
> #include <file2.h>
> 
> #include <iostream>
> 
> ns1::derived_class::derived_class()
> {
>         std::cout << "ns1::derived_class::derived_class()" <<
> std::endl;
> }
> 
> ns1::derived_class::~derived_class()
> {
>         std::cout << "ns1::derived_class::~derived_class()" <<
> std::endl;
> }
> 
> // file main.cc
> #include <file2.h>
> 
> int main(int argc, char** argv)
> {
>         ns1::derived_class object;
> 
>         return(1);
> }
> 
> file1 contains a base class called base_class which is derived in to a
> class called derived_class in file2.
> 
> main.cc contains a simple test for the problem that only instantiates
> an object of derived_class.
> 
> Here's the output of the library build step with output from nm
> 
> g++ -c -I./ file1.cc file2.cc && ar cqsv libtest.a *.o && nm --print-
> armap libtest.a
> a - file1.o
> a - file2.o
> 
> Archive index:
> _ZN3ns110base_classD1Ev in file1.o
> _ZN3ns110base_classD2Ev in file1.o
> _ZN3ns110base_classC1Ev in file1.o
> _ZN3ns110base_classC2Ev in file1.o
> _ZN3ns113derived_classD1Ev in file2.o
> _ZN3ns113derived_classD2Ev in file2.o
> _ZN3ns113derived_classC1Ev in file2.o
> _ZN3ns113derived_classC2Ev in file2.o
> 
> file1.o:
> 00000046 t _GLOBAL__I__ZN3ns110base_classC2Ev
> 00000000 t _Z41__static_initialization_and_destruction_0ii
> 000000ca T _ZN3ns110base_classC1Ev
> 000000f6 T _ZN3ns110base_classC2Ev
> 00000072 T _ZN3ns110base_classD1Ev
> 0000009e T _ZN3ns110base_classD2Ev
>          U _ZNSolsEPFRSoS_E
>          U _ZNSt8ios_base4InitC1Ev
>          U _ZNSt8ios_base4InitD1Ev
>          U _ZSt4cout
>          U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
> 00000000 b _ZSt8__ioinit
>          U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
>          U __cxa_atexit
>          U __dso_handle
>          U __gxx_personality_v0
> 0000005e t __tcf_0
> 
> file2.o:
> 00000046 t _GLOBAL__I__ZN3ns113derived_classC2Ev
>          U _Unwind_Resume
> 00000000 t _Z41__static_initialization_and_destruction_0ii
>          U _ZN3ns110base_classC2Ev
>          U _ZN3ns110base_classD2Ev
> 00000146 T _ZN3ns113derived_classC1Ev
> 000001a4 T _ZN3ns113derived_classC2Ev
> 00000072 T _ZN3ns113derived_classD1Ev
> 000000dc T _ZN3ns113derived_classD2Ev
>          U _ZNSolsEPFRSoS_E
>          U _ZNSt8ios_base4InitC1Ev
>          U _ZNSt8ios_base4InitD1Ev
>          U _ZSt4cout
>          U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
> 00000000 b _ZSt8__ioinit
>          U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
>          U __cxa_atexit
>          U __dso_handle
>          U __gxx_personality_v0
> 0000005e t __tcf_0
> 
> Here's the output of the main.cc build step with output from nm
> 
> g++ -c -I. -o main.o main.cc && nm --print-armap main.o
>          U _ZN3ns113derived_classC1Ev
>          U _ZN3ns113derived_classD1Ev
>          U __gxx_personality_v0
> 00000000 T main
> 
> I've been looking at this for some time now and am frankly stumped by
> what I know must be a simple case of me not doing something I should
> have but I don't know what. I blame all these RAD tools and things
> like autoconf, etc because I've been so embedded in them for years
> that I can't do a simple thing on the comand line, lol.
> 
> TIA,
> Pep.

Here is the "makefile" I used to build your example:

----------

# GNU Make makefile

# how to make a '.o' from a '.cc'.
# make will use this rule to build main.o, file1.o, and file2.o
%.o: %.cc
        g++ -c -o $@ -I. $<

# how to make 'test-main'
# the pre-reqs libtest.a and main.o will be built first
test-main : libtest.a main.o
        g++ -o $@ main.o -L. -ltest

# how to make libtest.a
# the pre-reqs file1.o and file2.o will be built first
libtest.a : file1.o file2.o
        ar -rvs $@ $^

# clean up the files created by 'make'
clean :
        -rm main.o file1.o file2.o libtest.a test-main

------------

Here is the output from the command "make":

~/x/pep> make
g++ -c -o file1.o -I. file1.cc
g++ -c -o file2.o -I. file2.cc
ar -rvs libtest.a file1.o file2.o
ar: creating libtest.a
a - file1.o
a - file2.o
g++ -c -o main.o -I. main.cc
g++ -o test-main main.o -L. -ltest


Here is the output from executing "test-main":

~/x/pep> ./test-main
ns1::base_class::base_class()
ns1::derived_class::derived_class()
ns1::derived_class::~derived_class()
ns1::base_class::~base_class()

So, it works for me (openSUSE 10.3, g++ v4.2.1)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]