0

I'm having this strange linking problem for a few days now. I have a C++ project (in Ubuntu 16.04) with 2 namespaces. Each namespace has .h and .cpp files in a separate directory compiling into a library .a file. At the end everything is linked into a single executable.

The project is quite large (modification of OpenBTS) so to make it more easy this is basically what I'm trying to do:

//*****directory A:

//file: A.h

namespace1 {

     class A {

         public:
         void functionA();
     };
}

//file: A.cpp

#include <B.h>
#include <vector.h>

using namespace1;
using namespace2;

void A::functionA (){
      B testB1;
      B testB2;
      testB2 = testB1; //works 
      testB1.functionB2(); //defined in B.h, works
      testB1.functionB(); //undefined reference to 'namespace2::B::functionB() const'
      std::vector<B> testvector;
      testvector.push_back(testB1); //undefined reference to 'namespace2::B'
}

//

//******directory B:

//file: B.h

#include "C.h"
//class C was part of the project before I started editing it and should not be the problem because other classes derived from it compile without problem.
namespace 2{
    class B: public C{
         int varB;
         public:
         B(){};
        ~B(){};

        void functionB() const; //overrides virtual functionB in class C
        int functionB2() { return varB;}
        void functionB2() //overrides pure virtual functionB2 in class C
    };
}

//file B.cpp

#include "B.h"
using namespace2

void B::functionB(){
  //code...
}

//main.cpp
//this creates an instance of A

At the end all files in directory A are compiled in .o files and then linked together in libary A.a, the same for directory B. Also main.cpp is compiled main.o

Then all is linked: g++ -g -O2 -Wall -pthread -rdynamic -o exename main.o ../B/.libs/B.a ../A/.libs/A.a -la53 -lzmq -pthread

This is where I get the errors:

undefined reference to 'namespace2::B' undefined reference to 'namespace2::B::functionB() const'

I've already checked if all virtual functions are overridden in B and this seems OK. Also when I use class B within other code in the namespace2 there is no problem and everything compiles fine. Calling a function defined in B.h is working so it rather seems like the linker cannot access functions defined in B.cpp?

Any suggestions?

2 Answers 2

2

When using namespaces, you should wrap the implementation of the methods of your classes into the namespace as well inside your .cpp file. Your a.cpp should look something like:

//file: A.cpp

#include <B.h>
#include <vector.h>

namespace namespace1 {

using namespace2; // means 'look in namespace2' to the compiler

void A::functionA (){
      B testB1;
      B testB2;
      testB2 = testB1; 
      testB1.functionB2(); 
      testB1.functionB(); 
      std::vector<B> testvector;
      testvector.push_back(testB1); 
}

} // namespace1

and your b.cpp should be like this:

//file B.cpp

#include "B.h"
namespace namespace2 {

void B::functionB() const{
  //code...
}

} // namespace2

Note that the instantiation of objects of type B works because the constructor is defined inside the class declaration. The same hold for B::function2(). On the other hand, A::functionA() and B::functionB() are in the global namespace, not in namespace1 and namespace2, as they should.

The clause using namespace_name; does not define the scope inside your cpp files. It just informs the compiler to look into that namespace to resolve the symbols that it will find in that translation unit.

The error you get while you try to populate the vector is probably due to the fact that your type is missing the implementation of functionB(), because it is in the wrong (global) namespace. Therefore type B is incomplete and cannot be used to instantiate a template class.

EDIT: As a follow up to the comments below, after some trial and error, it turned out that on the code side everything is fine, but the linking fails because of circular dependencies between lib A and B, that are not clearly visible in this dummy example, and because of other dependencies that need a proper linking order to work.

Therefore, a simple change in the linkin order of the libraries is not viable. My advice is to avoid circular dependencies if possible, or to use the ld specific options --start-group and --end-group to resolve this kind of issues. Learn more at the gnu man pages related to ld. You will find a lot of examples through the internet on their usage.

Hope this can help in fixing your problem.

Sign up to request clarification or add additional context in comments.

6 Comments

Originally the code in the .cpp was wrapped in the namespace but it didn't work so I tried something different. Now I've changed it once more like you suggested but still the same error.
I noticed that functionB() is const qualified. Please add const also in the method definition in the cpp file. This is another possible cause of the issue. Also there is a typo in the namespace wrapping class B. But I'm assuming it was just in the question...
Pardon, typos also in class A declaration. To use a namespace you must use the keyword namespace followed by the name of the namespace. Exactly like in my version o the cpp files.
I forgot the const in the example, it's there in the real code. So it's not the missing const causing the problem :(
Ok, I think it may be just a linking problem then. I've no time to derive a minimal code to test, so i'm asking to you to do a simple test: please swap B.a and A.a position in the compile command (A.a should come first). If it works I will elaborate more on this.
|
0

I think it has something to do with this function called text(std::ostream&)

In B.h there is:

class B {
    ...
    void text(std::ostream&) const;
}

In B.cpp there is (wrapped in namespace2):

void B::text(std::ostream& os) const {
    os << "some text";
}

If I delete the definition in B.cpp and declare and define in B.h:

class B {
    ...
    void text(std::ostream&) const {}; //no link problems!
}

Definition directly in the .h and it will compile successfully.

Note that text() overrides the virtual function from class C, declared in C.h as:

virtual void text(std::ostream& os) const
    { os << "(no text())"; }

I've also tried to add virtual before the function in B.h but that doesn't solve the problem.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.