简体   繁体   中英

Template subclass of non-template base from shared library causing Undefined symbols typeinfo for 'class' link error

Summary

I've built a shared library containing a non-template class from which I've derived a template class within the project that is linked to the library.

When I compile/link the referencing project, I receive the following link error:

Undefined symbols for architecture x86_64:
  "typeinfo for BaseClass", referenced from:
      typeinfo for DerivedClass<int> in main.o

What does typeinfo actually refer to? I am having trouble finding information about it, in order to dig deeper.

The error almost seems to imply that BaseClass is being expected to have type information of some kind, but I don't understand what is missing.

Also, I know this error often accompanies a vtable for ... link error, usually when you forget to provide a definition for a virtual method or define it as pure virtual, but I believe I've ruled that out with #1 in Things I've Tried below, since main.cpp would not have compile if foo() 's definition was not available from the library.

Source

I've distilled the classes to the following which still reproduce the problem:

BaseClass.h (part of shared library I'm linking against)

#ifndef BASECLASS_H_
#define BASECLASS_H_

class BaseClass
{
    protected:
        int myField;

    public:
        BaseClass();
        virtual ~BaseClass() {}

        virtual void foo();
};

#endif

BaseClass.cpp (compiled into the resulting 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 (in separate project that is linked against the library)

#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 (References DerivedClass that's expressing problem)

#include "DerivedClass.h"

int main()
{

    DerivedClass<int> derived(0);
    derived.foo();

    return 0;
}

Build commands

Shared Library

Compilation:

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"

Linking:

g++ -Xlinker -install_name -Xlinker "@rpath/libmylibrary.dylib" -dynamiclib -o "libmylibrary.dylib" ./src/BaseClass.o

Referencing Project

Compilation:

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"

Linking:

g++ -L"/code/myproject/deps/mylibrary/bin" -Xlinker -rpath -Xlinker "@loader_path" -o "myproject"  ./src/InternalBaseClass.o ./src/main.o   -lmylibrary

Environment Info

  • OS: macOS 10.11.6 (El Capitan)
  • Compiler: Apple LLVM version 8.0.0 (clang-800.0.42.1) (g++ links to this)
  • Linker: ld

Things I've Tried

I've done these things to try to narrow down the cause to specifically being due to the subclass being a template, and the base class coming from a shared library.

  1. Ensuring BaseClass can be referenced on its own. Tested this by changing main.cpp to include BaseClass , and instantiating it in main() and calling foo() on it. Compiled & linked without errors.

  2. Deriving from an internal base class instead of one from a shared library. Tested this by creating a class called InternalBaseClass with exact same source, except for the __attribute__ lines in the definition file, including it in the DerivedClass header in place of including BaseClass , and specifying it as the parent in the class declaration of DerivedClass . Compiled & linked without errors.

  3. Making DerivedClass non-template. Tested this by removing template declarations in DerivedClass and replacing references to the parameterized type T with int . This compiles & links without errors.

Thanks in advance!

It looks like you are building your shared library with "-fvisibility=hidden" and mark exported function with __attribute__((visibility("default"))) however in order to export RTTI you need to mark exported class with __attribute__((visibility("default"))) . From gcc referece :

Note that the type visibility is applied to vague linkage entities associated with the class (vtable, typeinfo node, etc.). In particular, if a class is thrown as an exception in one shared object and caught in another, the class must have default visibility. Otherwise the two shared objects are unable to use the same typeinfo node and exception handling will break.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM