0

I have a base class for all exceptions in my project. It's implemented like this:

Exception.hpp

class Exception : public std::exception
{
public:

    ELS_EXPORT_SYMBOL Exception(void) throw();
    ELS_EXPORT_SYMBOL explicit Exception(const std::string& what) throw();
    ELS_EXPORT_SYMBOL Exception(const char* format, ...) throw()
            ELS_PRINTF_FUNC(2, 3);
    ELS_EXPORT_SYMBOL Exception(const Exception& other) throw();
    ELS_EXPORT_SYMBOL Exception& operator =(const Exception& other)
            throw();
    ELS_EXPORT_SYMBOL virtual ~Exception(void) throw();

    ELS_EXPORT_SYMBOL virtual const char* what(void) const throw();

protected:

    ELS_EXPORT_SYMBOL void _M_setWhat(const char* format, ::va_list va)
        throw();

private:

    std::string _M_what;
};

#define ELS_EXC_VA_SET_WHAT(FORMAT)                                         \
    do                                                                      \
    {                                                                       \
        ::va_list va;                                                       \
        ::va_start(va, FORMAT);                                             \
        this->_M_setWhat(FORMAT, va);                                       \
        ::va_end(va);                                                       \
    }                                                                       \
    while (false)

Exception.cpp

Exception::Exception(void) throw()
    : std::exception(),
      _M_what("Exception")
{

}

Exception::Exception(const std::string& what) throw()
    : std::exception(),
      _M_what(what.empty() ? "Exception" : what)
{

}

Exception::Exception(const char* format, ...) throw()
    : std::exception(),
      _M_what()
{
    ELS_EXC_VA_SET_WHAT(format);
}

Exception::Exception(const Exception& other) throw()
    : std::exception(other),
      _M_what(other._M_what)
{

}

Exception& Exception::operator =(const Exception& other) throw()
{
    std::exception::operator =(other);
    this->_M_what = other._M_what;
    return *this;
}

Exception::~Exception(void) throw()
{

}

const char* Exception::what(void) const throw()
{
    return this->_M_what.c_str();
}

void Exception::_M_setWhat(const char* format, ::va_list va) throw()
{
    static const size_t BUFSIZE = 512;

    char buf[BUFSIZE];

    ::memset(buf, 0, BUFSIZE);
    ::vsnprintf(buf, BUFSIZE, format, va);
    this->_M_what = std::string(buf);
}

These files are a part of a shared library compiled with the following options:

-Wall -fPIC -O2 -D_GNU_SOURCE -fvisibility=hidden -rdynamic -Wl,-E

The library itself compiles without any problem, but when I try and compile a binary and link it against it I get the following error:

Main.cpp:(.text+0x297): undefined reference to `typeinfo for els::except::Exception'

I googled a bit and the common answer is to either implement all virtual methods or make them pure. I don't see this problem here. What am I doing wrong?

Zbigh1
  • 379
  • 4
  • 13
  • there is more to your code that you're not showing us? what are els and except? are those namespaces? it's possible that your definition of the functions are not in the right namespace, so the compiler thinks you're not defining the non-pure (slutty?) virtual functions. – thang Jan 31 '13 at 20:50
  • 3
    You are passing `-fvisibility=hidden` to the library. Look at [this](http://gcc.gnu.org/wiki/Visibility) wiki. There's a section titled "Problems with C++ exceptions (please read!)". You probably should read it. – n. m. could be an AI Jan 31 '13 at 21:15
  • Yep, this was the cause - fixed it. – Zbigh1 Jan 31 '13 at 21:26

3 Answers3

1

Ok, I got this - I have to make the whole class visible - class ELS_EXPORT_SYMBOL Exception.

Zbigh1
  • 379
  • 4
  • 13
  • And if you don't, you are going to have a lot of troubles, even if it links. See http://gcc.gnu.org/wiki/Visibility, read all of it, especially the part about exceptions. –  Jan 31 '13 at 23:33
0

The library itself compiles without any problem, but when I try and compile a binary and link it against it I get the following error

What's the link command line?

You're probably believe that you're passing in the library too early so the linker has already processed it before it gets around to needing that definition.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
0

There is an issue on Linux with RTTI when .so files are statically linked with C++ standard library. Classes instantiated in one .so are not available in another .so for introspection, because they have different RTTI tables (because each .so have its own copy of C++ runtime, due to static linking).

You have 2 options: 1. Use dynamic linking with C++ runtime on all program parts (I use this option) 2. Expose class explicitly like you already figured out (becomes annoying when you have a lot of classes)

strannik
  • 1,595
  • 1
  • 13
  • 22