摘要
我构建了一个包含非模板类的共享库,从中派生了一个链接到该库的项目内的模板类。
当我编译/链接引用项目时,我收到以下链接错误:
Undefined symbols for architecture x86_64:
"typeinfo for BaseClass", referenced from:
typeinfo for DerivedClass<int> in main.o
typeinfo
实际上指的是什么? 为了深入挖掘,我很难找到有关它的信息。
该错误似乎暗示BaseClass应该具有某种类型信息,但我不明白缺少什么。
另外,我知道此错误通常伴随着vtable for ...
链接错误,通常是当您忘记为虚拟方法提供定义或将其定义为纯虚拟时,但我相信我已经在下面的我尝试过的事情中用 #1 排除了这一点,因为如果库中没有foo()
的定义,main.cpp
就不会编译。
源
我已经将类提炼为以下内容,这些类仍然重现了该问题:
BaseClass.h(我链接的共享库的一部分)
#ifndef BASECLASS_H_
#define BASECLASS_H_
class BaseClass
{
protected:
int myField;
public:
BaseClass();
virtual ~BaseClass() {}
virtual void foo();
};
#endif
BaseClass.cpp(编译成生成的dylib)
#include <iostream>
#include "BaseClass.h"
__attribute__((visibility("default")))
BaseClass::BaseClass()
: myField(0)
{
}
__attribute__((visibility("default")))
void BaseClass::foo()
{
std::cout<<myField<<std::endl;
}
DerivedClass.h(在与库链接的单独项目中)
#ifndef DERIVEDCLASS_H_
#define DERIVEDCLASS_H_
#include <BaseClass.h>
template <typename T>
class DerivedClass : public BaseClass
{
protected:
T data;
public:
DerivedClass(T data) : data(data) {}
virtual ~DerivedClass() {}
};
#endif
main.cpp(引用派生类表示问题)
#include "DerivedClass.h"
int main()
{
DerivedClass<int> derived(0);
derived.foo();
return 0;
}
生成命令
共享库
汇编:
g++ -O3 -Wall -c -fmessage-length=0 -fvisibility=hidden -MMD -MP -MF"src/BaseClass.d" -MT"src/BaseClass.o" -o "src/BaseClass.o" "../src/BaseClass.cpp"
连接:
g++ -Xlinker -install_name -Xlinker "@rpath/libmylibrary.dylib" -dynamiclib -o "libmylibrary.dylib" ./src/BaseClass.o
参考项目
汇编:
g++ -I"/code/myproject/deps/mylibrary/include" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/main.d" -MT"src/main.o" -o "src/main.o" "../src/main.cpp"
连接:
g++ -L"/code/myproject/deps/mylibrary/bin" -Xlinker -rpath -Xlinker "@loader_path" -o "myproject" ./src/InternalBaseClass.o ./src/main.o -lmylibrary
环境信息
- 操作系统:macOS 10.11.6 (El Capitan)
- 编译器:Apple LLVM 版本 8.0.0 (clang-800.0.42.1) (g++ 链接到此)
- 链接器:ld
我尝试过的事情
我做了这些事情,试图将原因缩小到特别是由于子类是模板,而基类来自共享库。
确保基类可以单独引用。通过更改
main.cpp
以包含BaseClass
,并在main()
中实例化它并在其上调用foo()
来对此进行测试。 编译和链接没有错误。
派生自内部基类,而不是从共享库派生基类。通过创建一个名为
InternalBaseClass
的类来测试这一点,该类具有完全相同的源,除了定义文件中的__attribute__
行,将其包含在DerivedClass
标头中以代替包含BaseClass
,并将其指定为DerivedClass
类声明中的父级。编译和链接没有错误。使
DerivedClass
非模板。通过删除DerivedClass
中的模板声明并将对参数化类型T
的引用替换为int
来对此进行测试。 这编译和链接没有错误。
提前感谢!
看起来您正在使用"-fvisibility=hidden"构建共享库并使用__attribute__((visibility("default")))
标记导出的功能,但是为了导出RTTI,您需要使用__attribute__((visibility("default")))
标记导出的类。来自 gcc 裁判:
请注意,类型可见性应用于与类关联的模糊链接实体(vtable、typeinfo 节点等)。特别是,如果一个类在一个共享对象中作为异常引发并在另一个共享对象中捕获,则该类必须具有默认可见性。否则,两个共享对象将无法使用相同的 typeinfo 节点,异常处理将中断。