Linker error and obfuscated name

When trying to link shared library BBB, which depends on shared library AAA, I am getting a linker error of the form:

throw_exception_ex.obj: In function `Z15throw_exceptionI16ex_xml_exceptionEvRKT_':
throw_exception_ex.cpp:2: undefined reference to `typeinfo for ex_xml_exception'

How can I determine what functionality of ex_xml_exception in AAA the throw_exception_ex code in BBB is not finding in order to link successfully ?

When trying to link shared library BBB, which depends on shared library
AAA, I am getting a linker error of the form:

throw_exception_ex.obj: In function
`Z15throw_exceptionI16ex_xml_exceptionEvRKT_':
throw_exception_ex.cpp:2: undefined reference to `typeinfo for
ex_xml_exception'

How can I determine what functionality of ex_xml_exception in AAA the
throw_exception_ex code in BBB is not finding in order to link
successfully ?

Is one of the libraries built with `-fno-rtti` and the other with `-frtti`?

No.

Here is the code and command lines:

// ex_decl.hpp

#ifndef EX_DECL_HPP
#define EX_DECL_HPP
#if defined(BLD_EX_EXAMPLE)
  #define EX_DECL __attribute__((__dllexport__))
#else
  #define EX_DECL __attribute__((__dllimport__))
#endif
#define EX_VISIBLE __attribute__((__visibility__("default")))
#endif // EX_DECL_HPP

// ex_exception.hpp

#ifndef EX_EXCEPTION_HPP
#define EX_EXCEPTION_HPP
#include <exception>
#include "ex_decl.hpp"
class EX_VISIBLE ex_exception :
     public virtual std::exception
{
private:
     char m_buffer[128];
protected:
     EX_DECL unsigned int append(unsigned int l, const char * a);
     EX_DECL ex_exception() ;
public:
     typedef enum {
       no_exception,
       other_exception
     } ex_exception_code;
     ex_exception_code code;
     EX_DECL ex_exception(ex_exception_code c,const char * e1 = 0,const char * e2 = 0) ;
     EX_DECL ex_exception(ex_exception const &) ;
     virtual EX_DECL ~ex_exception() throw() ;
     virtual EX_DECL const char * what() const throw() ;
};
#endif // EX_EXCEPTION_HPP

// ex_exception.cpp

#include <exception>
#include <cstring>
#define BLD_EX_EXAMPLE
#include "ex_exception.hpp"
EX_DECL unsigned int ex_exception::append(unsigned int l, const char * a){
     while(l < (sizeof(m_buffer) - 1)){
         char c = *a++;
         if('\0' == c)
             break;
         m_buffer[l++] = c;
     }
     m_buffer[l] = '\0';
     return l;
}
EX_DECL ex_exception::ex_exception(ex_exception_code c,const char * e1,const char * e2) : code(c)
{
     unsigned int length = 0;
     switch(code){
     case no_exception:
         length = append(length, "uninitialized exception");
         break;
     case other_exception:
         length = append(length, "unknown derived exception");
         break;
     default:
         length = append(length, "programming error");
         break;
     }
}
EX_DECL ex_exception::ex_exception(ex_exception const & oth) : std::exception(oth),code(oth.code)
{
  std::memcpy(m_buffer,oth.m_buffer,sizeof m_buffer);
}
EX_DECL ex_exception::~ex_exception() throw() {}
EX_DECL const char * ex_exception::what() const throw() { return m_buffer; }
EX_DECL ex_exception::ex_exception() : code(no_exception) {}

// Compile ex_exception.cpp

clang++.exe -c -x c++ -D__MINGW_FORCE_SYS_INTRINS -Wno-unused-local-typedef -Wno-dll-attribute-on-redeclaration -O0 -g -fno-inline -Wall -g -march=i686 -m32 -o "ex_exception.obj" "ex_exception.cpp"

// ex_xml_exception.hpp

#ifndef EX_XML_EXCEPTION_HPP
#define EX_XML_EXCEPTION_HPP
#include <exception>
#include "ex_decl.hpp"
#include "ex_exception.hpp"
class EX_VISIBLE ex_xml_exception :
     public virtual ex_exception
{
public:
     typedef enum {
         xml_archive_parsing_error,
         xml_archive_tag_mismatch,
         xml_archive_tag_name_error
     } ex_exception_code;
     EX_DECL ex_xml_exception(ex_exception_code c,const char * e1 = 0,const char * e2 = 0);
     EX_DECL ex_xml_exception(ex_xml_exception const &) ;
     virtual EX_DECL ~ex_xml_exception() throw() ;
};
#endif // EX_XML_EXCEPTION_HPP

// ex_xml_exception.cpp

#include <exception>
#define BLD_EX_EXAMPLE
#include "ex_xml_exception.hpp"
EX_DECL ex_xml_exception::ex_xml_exception(ex_exception_code c,const char * e1,const char * e2) :
         ex_exception(other_exception, e1, e2)
     {
         switch(c){
         case xml_archive_parsing_error:
             ex_exception::append(0, "unrecognized XML syntax");
             break;
         case xml_archive_tag_mismatch:
             ex_exception::append(0, "XML start/end tag mismatch");
             if(0 != e1){
                 ex_exception::append(0, " - ");
                 ex_exception::append(0, e1);
             }
             break;
         case xml_archive_tag_name_error:
             ex_exception::append(0, "Invalid XML tag name");
             break;
         default:
             ex_exception::append(0, "programming error");
             break;
         }
     }
EX_DECL ex_xml_exception::ex_xml_exception(ex_xml_exception const & oth) : std::exception(oth),ex_exception(oth){}
EX_DECL ex_xml_exception::~ex_xml_exception() throw() {}

// Compile ex_xml_exception.cpp

clang++.exe -c -x c++ -D__MINGW_FORCE_SYS_INTRINS -Wno-unused-local-typedef -Wno-dll-attribute-on-redeclaration -O0 -g -fno-inline -Wall -g -march=i686 -m32 -o "ex_xml_exception.obj" "ex_xml_exception.cpp"

// Link exmp-clang37-d-1_59.dll

clang++.exe -o "exmp-clang37-d-1_59.dll" -Wl,-soname -Wl,exmp-clang37-d-1_59.dll -shared -Wl,--start-group "ex_exception.obj" "ex_xml_exception.obj" -Wl,-Bstatic -Wl,-Bdynamic -Wl,--end-group -g -march=i686 -m32

// throw_exception_ex.cpp

#include "ex_xml_exception.hpp"
template<class E> void throw_exception(E const & e) { throw e; }
int main(int argc,char * argv)
{
  if (argc > 1)
           {
throw_exception(ex_xml_exception(ex_xml_exception::xml_archive_parsing_error));
           }
  return 0;
}

// Compile throw_exception_ex.cpp

clang++.exe -c -x c++ -D__MINGW_FORCE_SYS_INTRINS -Wno-unused-local-typedef -Wno-dll-attribute-on-redeclaration -O0 -g -fno-inline -Wall -g -march=i686 -m32 -o "throw_exception_ex.obj" "throw_exception_ex.cpp"

// Link thr_exmp-clang37-d-1_59.dll

clang++.exe -o "thr_exmp-clang37-d-1_59.dll" -Wl,-soname -Wl,thr_exmp-clang37-d-1_59.dll -shared -Wl,--start-group "throw_exception_ex.obj" "exmp-clang37-d-1_59.dll" -Wl,-Bstatic -Wl,-Bdynamic -Wl,--end-group -g -march=i686 -m32

// Error message from this link

throw_exception_ex.obj: In function `Z15throw_exceptionI16ex_xml_exceptionEvRKT_':
throw_exception_ex.cpp:2: undefined reference to `typeinfo for ex_xml_exception'
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)

Something is missing from ex_xml_exception which the link wants but I can not guess what it is.

// ex_exception.hpp

#ifndef EX_EXCEPTION_HPP
#define EX_EXCEPTION_HPP
#include <exception>
#include "ex_decl.hpp"
class EX_VISIBLE ex_exception :

I think this class should probably be dllexported. It's possible that mingw
looks at class visibility as well as dllexport attributes when deciding
whether or not to expor tthe RTTI for classes, but I'm pretty sure clang
doesn't. We could add that check for compatibility. Is there a compelling
reason to not use dllexport on the entire class here?

    // ex_exception.hpp

    #ifndef EX_EXCEPTION_HPP
    #define EX_EXCEPTION_HPP
    #include <exception>
    #include "ex_decl.hpp"
    class EX_VISIBLE ex_exception :

I think this class should probably be dllexported. It's possible that
mingw looks at class visibility as well as dllexport attributes when
deciding whether or not to expor tthe RTTI for classes, but I'm pretty
sure clang doesn't. We could add that check for compatibility. Is there
a compelling reason to not use dllexport on the entire class here?

This is a simple example of a much more complicated problem in the Boost serialization library and its source build on Windows. I had made changes to get mingw(-64)/gcc to build correctly but have run into this clang problem. In essence Boost serialization on Windows exports individual member functions rather than entire classes. I doubt I am going to get the author of the library to change this, but I will mention to him the clang limitation and maybe he can do it.

If you make the change in clang to allow individual member functions to be exported/imported for visible classes that would be much better IMO. But past versions of clang on Windows still have this limitation vis-a-vis the Boost serialization library. I do not know if other Boost libraries which are non-header only use the same technique of exporting/importing individual member functions of visible classes on Windows. If they do then clang on Windows targeting mingw(-64)/gcc will not work with them either.

On Linux clang works fine of course, as does gcc, with Boost serialization source build. On Linux the individual exporting/importing of member functions is not used ( I don't even know if it is possible on Linux ).

Clang supports importing and exporting individual members. That should
already work.

The problem is that we need a way to export the runtime type information
(RTTI). That's why the linker is talking about "typeinfo for
ex_xml_exception". Right now they only way to do that is to export the
whole class, rather than individual members.

The source you provided uses the visibility attribute, though, so I wonder
if mingw does something with that.

        On Mon, Aug 3, 2015 at 9:56 AM, Edward Diener
        <eldlistmailingz@tropicsoft.com
        <mailto:eldlistmailingz@tropicsoft.com>
        <mailto:eldlistmailingz@tropicsoft.com
        <mailto:eldlistmailingz@tropicsoft.com>>>
        wrote:

             // ex_exception.hpp

             #ifndef EX_EXCEPTION_HPP
             #define EX_EXCEPTION_HPP
             #include <exception>
             #include "ex_decl.hpp"
             class EX_VISIBLE ex_exception :

        I think this class should probably be dllexported. It's possible
        that
        mingw looks at class visibility as well as dllexport attributes when
        deciding whether or not to expor tthe RTTI for classes, but I'm
        pretty
        sure clang doesn't. We could add that check for compatibility.
        Is there
        a compelling reason to not use dllexport on the entire class here?

    This is a simple example of a much more complicated problem in the
    Boost serialization library and its source build on Windows. I had
    made changes to get mingw(-64)/gcc to build correctly but have run
    into this clang problem. In essence Boost serialization on Windows
    exports individual member functions rather than entire classes. I
    doubt I am going to get the author of the library to change this,
    but I will mention to him the clang limitation and maybe he can do it.

    If you make the change in clang to allow individual member functions
    to be exported/imported for visible classes that would be much
    better IMO. But past versions of clang on Windows still have this
    limitation vis-a-vis the Boost serialization library. I do not know
    if other Boost libraries which are non-header only use the same
    technique of exporting/importing individual member functions of
    visible classes on Windows. If they do then clang on Windows
    targeting mingw(-64)/gcc will not work with them either.

Clang supports importing and exporting individual members. That should
already work.

That's good.

The problem is that we need a way to export the runtime type information
(RTTI). That's why the linker is talking about "typeinfo for
ex_xml_exception". Right now they only way to do that is to export the
whole class, rather than individual members.

Then importing and exporting individual members works only for what ? Classes that are not importing/exporting virtual functions ? Is this where the RTTI information being exported comes in ?

The source you provided uses the visibility attribute, though, so I
wonder if mingw does something with that.

I don't know but I can tell you I had similar problems getting mingw/gcc to work. It seems that it did not work until I explicitly exported/imported all virtual functions of the classes I presented, including the virtual destructors, as well as explicitly exported/imported any compiler generated functions which were going to be used across DLL boundaries, such as the individual copy constructors. Still I am not absolutely sure exactly what the rules were for mingw/gcc since I could never get a specific answer from them on the mingw-64 mailing list regarding this, although I did get some help from them. Maybe I should have addressed these concerns on the gcc mailing list instead.