[cfe-dev] Linker error and obfuscated name: Part II
Edward Diener
eldlistmailingz at tropicsoft.com
Thu Aug 6 13:21:52 PDT 2015
On 8/6/2015 12:44 PM, Reid Kleckner wrote:
> Hm, GCC never tries to import RTTI, so maybe it makes sense that we
> never export it. Anyway, there's a bug here. Maybe David knows what's up.
I tried this simple example:
// ex_aclass.hpp
#ifndef EX_ACLASS_HPP
#define EX_ACLASS_HPP
#if defined(BLD_EX_EXAMPLE)
#define EX_DECL __attribute__((__dllexport__))
#else
#define EX_DECL __attribute__((__dllimport__))
#endif
class EX_DECL ex_aclass
{
public:
int a_function(long);
};
#endif // EX_ACLASS_HPP
// ex_aclass.cpp
#define BLD_EX_EXAMPLE
#include "ex_aclass.hpp"
int ex_aclass::a_function(long amt)
{
return(amt > 1000000 ? 10 : 20);
}
// Compile ex_aclass
clang++.exe -c -x c++ -D__MINGW_FORCE_SYS_INTRINS -O0 -g -fno-inline
-Wall -g -march=i686 -m32 -o "ex_aclass.obj" "ex_aclass.cpp"
// Link to ex_ac dll
clang++.exe -o "ex_ac.dll" -Wl,-soname -Wl,ex_ac.dll -shared
-Wl,--start-group "ex_aclass.obj" -Wl,-Bstatic -Wl,-Bdynamic
-Wl,--end-group -g -march=i686 -m32
// ex_use_aclass.cpp
#include "ex_aclass.hpp"
int main(int argc,char * argv[])
{
ex_aclass aclass;
int ret(aclass.a_function(10000));
return ret;
}
// Compile ex_use_aclass
clang++.exe -c -x c++ -D__MINGW_FORCE_SYS_INTRINS -O0 -g -fno-inline
-Wall -g -march=i686 -m32 -o "ex_use_aclass.obj" "ex_use_aclass.cpp"
// Link ex_use_ac executable
clang++.exe -Wl,-R -Wl,"." -Wl,-rpath-link -Wl,"." -o "ex_use_ac.exe"
-Wl,--start-group "ex_use_aclass.obj" "ex_ac.dll" -Wl,-Bstatic
-Wl,-Bdynamic -Wl,--end-group -g -march=i686 -m32
All of this worked with no problems.
So the basic ability to access functionality in a class in a DLL from
outside that DLL works fine using clang on Windows. It is something
specific in my original example below that is causing linking problems,
whether I export entire classes or whether I export individual member
functions. Just thought I would let you know. Needless to say I need to
solve my original problem because that code mimics the design of a very
small portion of the Boost serialization library and is the cause why
the Boost serialization library will not build with clang on Windows
targeting gcc.
>
> On Thu, Aug 6, 2015 at 9:36 AM, Reid Kleckner
> <rnk-hpIqsD4AKlfQT0dZR+AlfA at public.gmane.org
> <mailto:rnk-hpIqsD4AKlfQT0dZR+AlfA at public.gmane.org>> wrote:
>
> I reproduced your example, and it looks like we are forgetting to
> export RTTI with dllexport in Itanium. We only export the vtable.
> This is what each compiler exports for ex_xml_exception.obj:
>
> $ dumpbin -directives ex_xml_exception.clang.obj | grep -export:_ZT
> | c++filt --no-strip-underscore
> -export:virtual thunk to ex_xml_exception::~ex_xml_exception()
> -export:virtual thunk to ex_xml_exception::~ex_xml_exception()
> -export:vtable for ex_xml_exception,data
>
> $ dumpbin -directives ex_xml_exception.gcc.obj | grep -export:_ZT |
> c++filt --no-strip-underscore
> -export:typeinfo for ex_exception,data
> -export:typeinfo for ex_xml_exception,data
> -export:construction vtable for
> ex_exception-in-ex_xml_exception,data
> -export:VTT for ex_xml_exception,data
> -export:vtable for ex_xml_exception,data
> -export:virtual thunk to ex_xml_exception::~ex_xml_exception()
> -export:virtual thunk to ex_xml_exception::~ex_xml_exception()
>
> In your previous example where the whole class wasn't exported, I
> think we might be doing the wrong thing when the key function is
> dllimport / dllexport. We think that it will provide exported
> symbols for vtables and RTTI but it doesn't. This is something we
> didn't run into because the MSVC ABI doesn't have key functions.
>
> On Thu, Aug 6, 2015 at 6:16 AM, Edward Diener
> <eldlistmailingz at tropicsoft.com
> <mailto:eldlistmailingz-5p0dqD/c5LGWd6l5hS35sQ at public.gmane.org>> wrote:
>
> Using clang on Windows targeting mingw(-64)/gcc since it does
> not appear possible to export individual member functions of a
> class, as well as export the RTTI of the class, without
> exporting the entire class, I have changed my example in my post
> "Linker error and obfuscated name" to export the entire class
> itself. But I am still seeing a linker error, Here is the
> changed 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
> #endif // EX_DECL_HPP
>
> // ex_exception.hpp
>
> #ifndef EX_EXCEPTION_HPP
> #define EX_EXCEPTION_HPP
> #include <exception>
> #include "ex_decl.hpp"
> class EX_DECL ex_exception :
> public virtual std::exception
> {
> private:
> char m_buffer[128];
> protected:
> unsigned int append(unsigned int l, const char * a);
> ex_exception() ;
> public:
> typedef enum {
> no_exception,
> other_exception
> } ex_exception_code;
> ex_exception_code code;
> ex_exception(ex_exception_code c,const char * e1 = 0,const
> char * e2 = 0) ;
> ex_exception(ex_exception const &) ;
> virtual ~ex_exception() throw() ;
> virtual const char * what() const throw() ;
> };
> #endif // EX_EXCEPTION_HPP
>
> // ex_exception.cpp
>
> #include <exception>
> #include <cstring>
> #define BLD_EX_EXAMPLE
> #include "ex_exception.hpp"
> 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_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_exception::ex_exception(ex_exception const & oth) :
> std::exception(oth),code(oth.code)
> {
> std::memcpy(m_buffer,oth.m_buffer,sizeof m_buffer);
> }
> ex_exception::~ex_exception() throw() {}
> const char * ex_exception::what() const throw() { return
> m_buffer; }
> 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_DECL 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_xml_exception(ex_exception_code c,const char * e1 =
> 0,const char * e2 = 0);
> ex_xml_exception(ex_xml_exception const &) ;
> virtual ~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_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_xml_exception::ex_xml_exception(ex_xml_exception const & oth)
> : std::exception(oth),ex_exception(oth){}
> 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.exe
>
> clang++.exe -Wl,-R -Wl,"." -Wl,-rpath-link -Wl,"." -o
> "thr_exmp.exe" -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
> `_imp___ZTI16ex_xml_exception'
> clang++.exe: error: linker command failed with exit code 1 (use
> -v to see invocation)
>
> So even when I export/import the entire class rather than
> individual member functions, I can not link my final module
> successfully as it is still looking for something in the shared
> library that it says is not there.
>
> This same code succeeds without problem with mingw(-64)/gcc on
> Windows.
More information about the cfe-dev
mailing list