我几天来遇到这个奇怪的链接问题。
我有一个带有2个名称空间的C ++项目(在Ubuntu 16.04中)。每个命名空间在单独的目录中都有.h和.cpp文件,这些文件会编译为库.a文件。最后,所有内容都链接到一个可执行文件中。

该项目相当大(OpenBTS的修改),因此要使其变得更加容易,这基本上就是我要尝试的工作:

//*****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


最后,目录A中的所有文件都编译为.o文件,然后在库A.a中链接在一起,与目录B相同。main.cpp也编译为main.o

然后所有链接:
g ++ -g -O2 -Wall -pthread -rdynamic -o exename main.o ../B/.libs/B.a ../A/.libs/A.a -la53 -lzmq -pthread

这是我得到错误的地方:

未定义对“ namespace2 :: B”的引用
未定义引用'namespace2 :: B :: functionB()const'

我已经检查了是否所有虚函数都在B中被覆盖,这似乎还可以。同样,当我在namespace2中的其他代码中使用类B时,也没有问题,一切都可以编译。调用B.h中定义的函数是可行的,因此看起来链接程序无法访问B.cpp中定义的函数?

有什么建议么?

最佳答案

使用名称空间时,应将类方法的实现包装到.cpp文件中的名称空间中。您的a.cpp应该看起来像:

//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


并且您的b.cpp应该是这样的:

//file B.cpp

#include "B.h"
namespace namespace2 {

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

} // namespace2


请注意,因为构造函数是在类声明中定义的,所以实例化B类型的对象是可行的。 B::function2()的保持不变。另一方面,A::functionA()B::functionB()分别位于全局名称空间中,而不是在名称空间1和名称空间2中。

子句using namespace_name;并未在cpp文件中定义范围。它只是通知编译器调查该名称空间,以解决它将在该转换单元中找到的符号。

您尝试填充向量时遇到的错误可能是由于您的类型缺少functionB()的实现,因为它位于错误的(全局)名称空间中。因此,类型B是不完整的,不能用于实例化模板类。

编辑:
作为下面评论的后续内容,经过一番尝试和错误后,结果发现在代码方面,一切都很好,但是由于lib A和B之间的循环依赖关系,链接失败,在此虚拟示例中看不到该依赖关系,并且由于其他依赖关系需要正确的链接顺序才能正常工作。

因此,对库的链接顺序进行简单更改是不可行的。我的建议是,如果可能的话,避免循环依赖,或者使用ld特定的选项--start-group和--end-group解决此类问题。在与ld相关的gnu man pages中了解更多信息。您可以通过Internet在其用法上找到很多示例。

希望这可以帮助您解决问题。

07-24 09:46
查看更多