[Exception] Duplicate symbol error when using errinfo_api_function in static library
Dear readers, I encountered a problem in my project when using *Boost.Exception* with the predefined types errinfo_xyz in a library project. I have two classes ClassA and ClassB in my library which both throw a boost::exception with errinfo_api_function type in their implementation file (.cpp) These both classes are compiled into a static library with the C/C++-Flags -fvisibility=hidden. Then I have a main.cpp which creates an instance of ClassA and ClassB and links to the library which contains ClassA.o and ClassB.o. When I compile the main.cpp I get the linker error duplicate symbol for the errinfo_api_function object in ClassA.o and ClassB.o. If I remove the visibility=hidden flag, it links without problems. I am not an expert on the compiler flags, but I saw that many libraries use the visibility=hidden flag so I think it would be good, if my lib could also use it. For a better description I will show the sources for my project: ClassA.h ------------------------------------------------------------------------------------------------- #pragma once #include <boost/exception/all.hpp> struct my_errorA : virtual std::exception, virtual boost::exception {}; class ClassA { public: ClassA() {}; virtual ~ClassA() {}; virtual void doSomething(); }; ClassA.cpp ------------------------------------------------------------------------------------------------- #include "ClassA.h" void ClassA::doSomething() { BOOST_THROW_EXCEPTION( my_errorA() << boost::errinfo_api_function("doSomething") ); } ClassB.h ------------------------------------------------------------------------------------------------- #pragma once #include <boost/exception/all.hpp> struct my_errorB : virtual std::exception, virtual boost::exception {}; class ClassB { public: ClassB() {}; virtual ~ ClassB() {}; virtual void doSomething(); }; ClassB.cpp ------------------------------------------------------------------------------------------------- #include "ClassB.h" void ClassB::doSomething() { BOOST_THROW_EXCEPTION( my_errorB() << boost::errinfo_api_function("doSomething") ); } main.cpp ------------------------------------------------------------------------------------------------- #include "ClassA.h" #include "ClassB.h" int main(int argc, const char * argv[]) { ClassA A; ClassB B; return 0; } The Linker output: ----------------------------------------------------------------------------------------------------------------- *Ld /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/ExceptionTest normal i386 cd /Users/georg/work/ExceptionTest setenv MACOSX_DEPLOYMENT_TARGET 10.8 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -arch i386 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk -L/Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug -F/Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug -filelist /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Intermediates/ExceptionTest.build/Debug/ExceptionTest.build/Objects-normal/i386/ExceptionTest.LinkFileList -mmacosx-version-min=10.8 /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a -o /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/ExceptionTest duplicate symbol __ZTIPN5boost21errinfo_api_function_E in: /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassA.o) /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassB.o) duplicate symbol __ZTSPN5boost21errinfo_api_function_E in: /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassA.o) /Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassB.o) ld: 2 duplicate symbols for architecture i386 clang: error: linker command failed with exit code 1 (use -v to see invocation)* ----------------------------------------------------------------------------------------------------------------- I hope I described the problem well enough and I hope someone can explain what the problem is? Thank a lot and best regards Georg
On Tue, Oct 1, 2013 at 2:16 AM, Georg Leidinger < georg.leidinger@googlemail.com> wrote:
Dear readers,
I encountered a problem in my project when using *Boost.Exception* with the predefined types errinfo_xyz in a library project. I have two classes ClassA and ClassB in my library which both throw a boost::exception with errinfo_api_function type in their implementation file (.cpp) These both classes are compiled into a static library with the C/C++-Flags -fvisibility=hidden. Then I have a main.cpp which creates an instance of ClassA and ClassB and links to the library which contains ClassA.o and ClassB.o. When I compile the main.cpp I get the linker error duplicate symbol for the errinfo_api_function object in ClassA.o and ClassB.o. If I remove the visibility=hidden flag, it links without problems. I am not an expert on the compiler flags, but I saw that many libraries use the visibility=hidden flag so I think it would be good, if my lib could also use it.
Honestly I have no idea why this would happen. Anyone? -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
Hi Emil, I was able to figure out some more information about the issue and I could isolate it a little bit more. First it doesn't matter if it is a static or a shared library. Second it is not directly related to the *Boost.Exception*library but to the template class *error_info* which is used to create the predefined errinfo_xyz types. It is enough to instantiate the *errinfo_api_function* type in both doSomething() methods in the both implementation files. I am not so good in templates but I guess that the compiler creates the same symbol in both object files (ClassA.o and ClassB.o) for the type *errinfo_api_function.* I can see this via nm that I have the following line in both object files: *ClassA.o* *0000000000059860 s __ZTIN5boost21errinfo_api_function_E* * * *ClassB.o* *0000000000059870 s __ZTIN5boost21errinfo_api_function_E * * * Now, when the linker tries to link ClassA.o and ClassB.o to the main.o the both symbols clashes. But that would mean I could never use *Boost.Exception * or any other template instantiated type in a library. Best Regards Georg 2013/10/2 Emil Dotchevski <emildotchevski@gmail.com>
On Tue, Oct 1, 2013 at 2:16 AM, Georg Leidinger < georg.leidinger@googlemail.com> wrote:
Dear readers,
I encountered a problem in my project when using *Boost.Exception* with the predefined types errinfo_xyz in a library project. I have two classes ClassA and ClassB in my library which both throw a boost::exception with errinfo_api_function type in their implementation file (.cpp) These both classes are compiled into a static library with the C/C++-Flags -fvisibility=hidden. Then I have a main.cpp which creates an instance of ClassA and ClassB and links to the library which contains ClassA.o and ClassB.o. When I compile the main.cpp I get the linker error duplicate symbol for the errinfo_api_function object in ClassA.o and ClassB.o. If I remove the visibility=hidden flag, it links without problems. I am not an expert on the compiler flags, but I saw that many libraries use the visibility=hidden flag so I think it would be good, if my lib could also use it.
Honestly I have no idea why this would happen. Anyone?
-- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Wed, Oct 2, 2013 at 3:06 PM, Georg Leidinger < georg.leidinger@googlemail.com> wrote:
Hi Emil,
I was able to figure out some more information about the issue and I could isolate it a little bit more. First it doesn't matter if it is a static or a shared library. Second it is not directly related to the * Boost.Exception* library but to the template class *error_info* which is used to create the predefined errinfo_xyz types. It is enough to instantiate the *errinfo_api_function* type in both doSomething() methods in the both implementation files. I am not so good in templates but I guess that the compiler creates the same symbol in both object files (ClassA.o and ClassB.o) for the type *errinfo_api_function.* I can see this via nm that I have the following line in both object files:
*ClassA.o* *0000000000059860 s __ZTIN5boost21errinfo_api_function_E* * * *ClassB.o* *0000000000059870 s __ZTIN5boost21errinfo_api_function_E *
Instantiating a template in two compilation units should not lead to link errors. That's why I can't understand why this happens. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
It happens only if the library is build with the *LLVM 4.2* (I am using XCode so it is the Apple LLVM 4.2, I don't know if there is something different from the standard LLVM 4.2). If I choose the *LLVM GCC 4.2* no errors are reported. Is this a bug in the LLVM compiler? best Georg Leidinger 2013/10/3 Emil Dotchevski <emildotchevski@gmail.com>
On Wed, Oct 2, 2013 at 3:06 PM, Georg Leidinger < georg.leidinger@googlemail.com> wrote:
Hi Emil,
I was able to figure out some more information about the issue and I could isolate it a little bit more. First it doesn't matter if it is a static or a shared library. Second it is not directly related to the * Boost.Exception* library but to the template class *error_info* which is used to create the predefined errinfo_xyz types. It is enough to instantiate the *errinfo_api_function* type in both doSomething() methods in the both implementation files. I am not so good in templates but I guess that the compiler creates the same symbol in both object files (ClassA.o and ClassB.o) for the type *errinfo_api_function.* I can see this via nm that I have the following line in both object files:
*ClassA.o* *0000000000059860 s __ZTIN5boost21errinfo_api_function_E* * * *ClassB.o* *0000000000059870 s __ZTIN5boost21errinfo_api_function_E *
Instantiating a template in two compilation units should not lead to link errors. That's why I can't understand why this happens.
-- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
I found this *clang bug* http://llvm.org/bugs/show_bug.cgi?id=10113 which seems to be related to the problem. 2013/10/3 Georg Leidinger <georg.leidinger@googlemail.com>
It happens only if the library is build with the *LLVM 4.2* (I am using XCode so it is the Apple LLVM 4.2, I don't know if there is something different from the standard LLVM 4.2). If I choose the *LLVM GCC 4.2* no errors are reported. Is this a bug in the LLVM compiler?
best Georg Leidinger
2013/10/3 Emil Dotchevski <emildotchevski@gmail.com>
On Wed, Oct 2, 2013 at 3:06 PM, Georg Leidinger < georg.leidinger@googlemail.com> wrote:
Hi Emil,
I was able to figure out some more information about the issue and I could isolate it a little bit more. First it doesn't matter if it is a static or a shared library. Second it is not directly related to the * Boost.Exception* library but to the template class *error_info* which is used to create the predefined errinfo_xyz types. It is enough to instantiate the *errinfo_api_function* type in both doSomething() methods in the both implementation files. I am not so good in templates but I guess that the compiler creates the same symbol in both object files (ClassA.o and ClassB.o) for the type *errinfo_api_function.* I can see this via nm that I have the following line in both object files:
*ClassA.o* *0000000000059860 s __ZTIN5boost21errinfo_api_function_E* * * *ClassB.o* *0000000000059870 s __ZTIN5boost21errinfo_api_function_E *
Instantiating a template in two compilation units should not lead to link errors. That's why I can't understand why this happens.
-- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
I finally found a way to compile it with clang. I am using the pragma to make the symbols for the Boost.Exception part not hidden like this: #pragma GCC visibility push(default) #include <boost/exception/all.hpp> #pragma GCC visibility pop * * - Georg Leidinger 2013/10/3 Georg Leidinger <georg.leidinger@googlemail.com>
I found this *clang bug* http://llvm.org/bugs/show_bug.cgi?id=10113 which seems to be related to the problem.
2013/10/3 Georg Leidinger <georg.leidinger@googlemail.com>
It happens only if the library is build with the *LLVM 4.2* (I am using XCode so it is the Apple LLVM 4.2, I don't know if there is something different from the standard LLVM 4.2). If I choose the *LLVM GCC 4.2* no errors are reported. Is this a bug in the LLVM compiler?
best Georg Leidinger
2013/10/3 Emil Dotchevski <emildotchevski@gmail.com>
On Wed, Oct 2, 2013 at 3:06 PM, Georg Leidinger < georg.leidinger@googlemail.com> wrote:
Hi Emil,
I was able to figure out some more information about the issue and I could isolate it a little bit more. First it doesn't matter if it is a static or a shared library. Second it is not directly related to the * Boost.Exception* library but to the template class *error_info* which is used to create the predefined errinfo_xyz types. It is enough to instantiate the *errinfo_api_function* type in both doSomething() methods in the both implementation files. I am not so good in templates but I guess that the compiler creates the same symbol in both object files (ClassA.o and ClassB.o) for the type *errinfo_api_function.* I can see this via nm that I have the following line in both object files:
*ClassA.o* *0000000000059860 s __ZTIN5boost21errinfo_api_function_E* * * *ClassB.o* *0000000000059870 s __ZTIN5boost21errinfo_api_function_E *
Instantiating a template in two compilation units should not lead to link errors. That's why I can't understand why this happens.
-- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On 2 Oct 2013 at 17:21, Emil Dotchevski wrote:
*ClassA.o* *0000000000059860 s __ZTIN5boost21errinfo_api_function_E* * * *ClassB.o* *0000000000059870 s __ZTIN5boost21errinfo_api_function_E *
Instantiating a template in two compilation units should not lead to link errors. That's why I can't understand why this happens.
Instantiating a template in two compilation units is no different to defining a non-static function twice. Unless its symbols are marked as composable (weak on ELF, selectany on PE) the linker will error. The only portable way of marking symbols as composable in C++ is the "inline" keyword which is auto-added by a C++ compiler for functions defined inline in a class definition. Given that most modern C++ compilers don't really take much hinting from inline anymore, inline now really equals "set this symbol to weak/selectany" i.e. don't link error if I instantiate this more than once. My point is that instantiating a template in multiple compilation units needs all of its member functions to be marked inline in order to prevent link error. Or, as the OP has found, one can hack around the problem by overriding symbol visibility and forcing multiple copies in each compilation unit. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/
On 2 Oct 2013 at 14:48, Emil Dotchevski wrote:
Then I have a main.cpp which creates an instance of ClassA and ClassB and links to the library which contains ClassA.o and ClassB.o. When I compile the main.cpp I get the linker error duplicate symbol for the errinfo_api_function object in ClassA.o and ClassB.o. If I remove the visibility=hidden flag, it links without problems. I am not an expert on the compiler flags, but I saw that many libraries use the visibility=hidden flag so I think it would be good, if my lib could also use it.
Honestly I have no idea why this would happen. Anyone?
Throwable types must *always* be marked with attribute visibility default. I assume this has been done correctly, but if it hasn't that might help explain the problem. See my doc on the issue at http://gcc.gnu.org/wiki/Visibility. Note that throwable types, if with virtual function tables, may consist of more symbols than otherwise expected. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/
On Wed, Oct 2, 2013 at 4:20 PM, Niall Douglas <s_sourceforge@nedprod.com>wrote:
On 2 Oct 2013 at 14:48, Emil Dotchevski wrote:
Then I have a main.cpp which creates an instance of ClassA and ClassB and links to the library which contains ClassA.o and ClassB.o. When I compile the main.cpp I get the linker error duplicate symbol for the errinfo_api_function object in ClassA.o and ClassB.o. If I remove the visibility=hidden flag, it links without problems. I am not an expert on the compiler flags, but I saw that many libraries use the visibility=hidden flag so I think it would be good, if my lib could also use it.
Honestly I have no idea why this would happen. Anyone?
Throwable types must *always* be marked with attribute visibility default. I assume this has been done correctly, but if it hasn't that might help explain the problem. See my doc on the issue at http://gcc.gnu.org/wiki/Visibility.
These are not throwable types. For example, errinfo_api_function is not a throwable type. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
participants (3)
-
Emil Dotchevski
-
Georg Leidinger
-
Niall Douglas