[serialization] Multiply defined symbol: guid_initializer
Hi,
I'm currently trying to polymorphically serialize a class without using
RTTI. I'm doing this currently in a file called StaticText.hpp:
#ifndef RS_GUI_WIDGETS_STATICTEXT_HPP
#define RS_GUI_WIDGETS_STATICTEXT_HPP
#include
Look at the pimple demo in the examples or test directory. Basically you're getting some things defined twiice.
Move the implementation of template< class Archive >
void serialize( Archive& archive, unsigned int version ) to the *.cpp
and move
BOOST_CLASS_EXPORT( rs::StaticText )
to the *.cpp file as well. compile that/those *.cpp files and include in the library. This is touched upon in the manual in the part describing EXPORT.
Robert Ramey
"Robert Dailey"
But I've already tried that, as I said. It fails at runtime with an
exception saying "unregistered void cast". I'll test it once more, but I
don't expect different results.
On Thu, Apr 2, 2009 at 10:07 PM, Robert Ramey
Look at the pimple demo in the examples or test directory. Basically you're getting some things defined twiice.
Move the implementation of template< class Archive > void serialize( Archive& archive, unsigned int version ) to the *.cpp and move BOOST_CLASS_EXPORT( rs::StaticText )
to the *.cpp file as well. compile that/those *.cpp files and include in the library. This is touched upon in the manual in the part describing EXPORT.
Robert Ramey
"Robert Dailey"
wrote in message news:496954360904021720o79c9c17cs18b1cf3f53da08c@mail.gmail.com... Hi, I'm currently trying to polymorphically serialize a class without using RTTI. I'm doing this currently in a file called StaticText.hpp: #ifndef RS_GUI_WIDGETS_STATICTEXT_HPP #define RS_GUI_WIDGETS_STATICTEXT_HPP
#include
#include #include #include #include #include #include
#include namespace rs { class StaticText : public Widget { public: StaticText( std::string const& text );
void Update(); void Render( RenderSystem& renderer, Camera& camera ); char const* get_key() const;
private: StaticText() {}
template< class Archive > void serialize( Archive& archive, unsigned int version ) { archive & boost::serialization::base_object<Widget>( *this );
std::string text; archive & text; m_text.reset( new Text( text ) ); }
boost::scoped_ptr<Text> m_text;
friend class boost::serialization::access; }; }
BOOST_CLASS_TYPE_INFO( rs::StaticText, extended_type_info_no_rttirs::StaticText )
BOOST_CLASS_EXPORT( rs::StaticText )
#endif // RS_GUI_WIDGETS_STATICTEXT_HPP
When I compile this into a LIB first, and then link the lib into an EXE, the linker says this (Visual Studio 2008): *gui.lib(StaticText.obj) : error LNK2005: "public: static struct boost::archive::detail::guid_initializer<class rs::StaticText> const & const boost::archive::detail::init_guid<class rs::StaticText>::guid_initializer" (?guid_initializer@?$init_guid@VStaticText@rs@@@detail@archive@boost@ @2ABU?$guid_initializer@VStaticText@rs@@@234@B) already defined in main.obj* * * If I move the 2 macro calls into the StaticText.cpp file, everything compiles/links just fine but I end up getting an exception thrown at runtime that says "unregistered void cast".
------------------------------
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Hello,
I had a similar problem, you must call a function in the compilation
unit if you put only the macros in the .cpp if will not work.
BOOST_CLASS_EXPORT(Curve2);
BOOST_CLASS_EXPORT(Line2);
BOOST_CLASS_EXPORT(Circle2);
/**
* DO NOT REMOVE THIS FUNCTION
* The C++ standard guarantees that all global objects contained
* in a compilation unit (a CPP file) are initialized by the time
* execution enters a function from that compilation unit. So, if
* execution never enters a function from that compilation unit,
* the compiler is allowed to deadstrip it.
*
* BOOST_CLASS_EXPORT is based upon global objects.
*/
void force_serialize_export();
________________________________
De : boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] De la part de Robert Dailey
Envoyé : vendredi 3 avril 2009 16:56
À : boost-users@lists.boost.org
Objet : Re: [Boost-users] [serialization] Multiply defined symbol:guid_initializer
But I've already tried that, as I said. It fails at runtime with an exception saying "unregistered void cast". I'll test it once more, but I don't expect different results.
On Thu, Apr 2, 2009 at 10:07 PM, Robert Ramey
What?? I see you have a force_serialize_export() function, but how can you
guys expect me to mangle my interfaces to get boost::serialization to do its
job? So I have to now call arbitrary global functions all over the place?
This is unreasonable and unacceptable. There has to be a better way!
On Fri, Apr 3, 2009 at 11:05 AM, Renaud Lepere
Hello,
I had a similar problem, you must call a function in the compilation unit if you put only the macros in the .cpp if will not work.
BOOST_CLASS_EXPORT(Curve2); BOOST_CLASS_EXPORT(Line2); BOOST_CLASS_EXPORT(Circle2);
/** * DO NOT REMOVE THIS FUNCTION * The C++ standard guarantees that all global objects contained * in a compilation unit (a CPP file) are initialized by the time * execution enters a function from that compilation unit. So, if * execution never enters a function from that compilation unit, * the compiler is allowed to deadstrip it. * * BOOST_CLASS_EXPORT is based upon global objects. */ void force_serialize_export();
________________________________
De : boost-users-bounces@lists.boost.org [mailto: boost-users-bounces@lists.boost.org] De la part de Robert Dailey Envoyé : vendredi 3 avril 2009 16:56 À : boost-users@lists.boost.org Objet : Re: [Boost-users] [serialization] Multiply defined symbol:guid_initializer
But I've already tried that, as I said. It fails at runtime with an exception saying "unregistered void cast". I'll test it once more, but I don't expect different results.
On Thu, Apr 2, 2009 at 10:07 PM, Robert Ramey
wrote: Look at the pimple demo in the examples or test directory. Basically you're getting some things defined twiice.
Move the implementation of template< class Archive > void serialize( Archive& archive, unsigned int version ) to the *.cpp and move BOOST_CLASS_EXPORT( rs::StaticText )
to the *.cpp file as well. compile that/those *.cpp files and include in the library. This is touched upon in the manual in the part describing EXPORT.
Robert Ramey
"Robert Dailey"
wrote in message news:496954360904021720o79c9c17cs18b1cf3f53da08c@mail.gmail.com... Hi, I'm currently trying to polymorphically serialize a class without using RTTI. I'm doing this currently in a file called StaticText.hpp:
#ifndef RS_GUI_WIDGETS_STATICTEXT_HPP #define RS_GUI_WIDGETS_STATICTEXT_HPP
#include
#include #include #include #include #include #include
#include namespace rs { class StaticText : public Widget { public: StaticText( std::string const& text );
void Update(); void Render( RenderSystem& renderer, Camera& camera ); char const* get_key() const;
private: StaticText() {}
template< class Archive > void serialize( Archive& archive, unsigned int version ) { archive & boost::serialization::base_object<Widget>( *this );
std::string text; archive & text; m_text.reset( new Text( text ) ); }
boost::scoped_ptr<Text> m_text;
friend class boost::serialization::access; }; }
BOOST_CLASS_TYPE_INFO( rs::StaticText, extended_type_info_no_rttirs::StaticText )
BOOST_CLASS_EXPORT( rs::StaticText )
#endif // RS_GUI_WIDGETS_STATICTEXT_HPP
When I compile this into a LIB first, and then link the lib into an EXE, the linker says this (Visual Studio 2008): gui.lib(StaticText.obj) : error LNK2005: "public: static struct boost::archive::detail::guid_initializer<class rs::StaticText> const & const boost::archive::detail::init_guid<class rs::StaticText>::guid_initializer" (?guid_initializer@ ?$init_guid@VStaticText@rs@@@detail@archive@boost@ @2ABU?$guid_initializer@VStaticText@rs@@@234@B) already defined in main.obj
If I move the 2 macro calls into the StaticText.cpp file, everything compiles/links just fine but I end up getting an exception thrown at runtime that says "unregistered void cast".
________________________________
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Besides, it doesn't make sense to have the global function in the first
place. I'm already creating instances of the very class I'm exporting via
the macro. That alone should be enough to keep the compiler from stripping
out the class specializations created by the boost class macros, right? This
whole thing is just so confusing... why can't it just work like it is
supposed to? I am doing things exactly as they are being done in the
test_no_rtti unit test...
On Fri, Apr 3, 2009 at 11:26 AM, Robert Dailey
What?? I see you have a force_serialize_export() function, but how can you guys expect me to mangle my interfaces to get boost::serialization to do its job? So I have to now call arbitrary global functions all over the place? This is unreasonable and unacceptable. There has to be a better way!
On Fri, Apr 3, 2009 at 11:05 AM, Renaud Lepere
wrote: Hello,
I had a similar problem, you must call a function in the compilation unit if you put only the macros in the .cpp if will not work.
BOOST_CLASS_EXPORT(Curve2); BOOST_CLASS_EXPORT(Line2); BOOST_CLASS_EXPORT(Circle2);
/** * DO NOT REMOVE THIS FUNCTION * The C++ standard guarantees that all global objects contained * in a compilation unit (a CPP file) are initialized by the time * execution enters a function from that compilation unit. So, if * execution never enters a function from that compilation unit, * the compiler is allowed to deadstrip it. * * BOOST_CLASS_EXPORT is based upon global objects. */ void force_serialize_export();
________________________________
De : boost-users-bounces@lists.boost.org [mailto: boost-users-bounces@lists.boost.org] De la part de Robert Dailey Envoyé : vendredi 3 avril 2009 16:56 À : boost-users@lists.boost.org Objet : Re: [Boost-users] [serialization] Multiply defined symbol:guid_initializer
But I've already tried that, as I said. It fails at runtime with an exception saying "unregistered void cast". I'll test it once more, but I don't expect different results.
On Thu, Apr 2, 2009 at 10:07 PM, Robert Ramey
wrote: Look at the pimple demo in the examples or test directory. Basically you're getting some things defined twiice.
Move the implementation of template< class Archive > void serialize( Archive& archive, unsigned int version ) to the *.cpp and move BOOST_CLASS_EXPORT( rs::StaticText )
to the *.cpp file as well. compile that/those *.cpp files and include in the library. This is touched upon in the manual in the part describing EXPORT.
Robert Ramey
"Robert Dailey"
wrote in message news:496954360904021720o79c9c17cs18b1cf3f53da08c@mail.gmail.com. .. Hi, I'm currently trying to polymorphically serialize a class without using RTTI. I'm doing this currently in a file called StaticText.hpp:
#ifndef RS_GUI_WIDGETS_STATICTEXT_HPP #define RS_GUI_WIDGETS_STATICTEXT_HPP
#include
#include #include #include #include #include #include
#include namespace rs { class StaticText : public Widget { public: StaticText( std::string const& text );
void Update(); void Render( RenderSystem& renderer, Camera& camera ); char const* get_key() const;
private: StaticText() {}
template< class Archive > void serialize( Archive& archive, unsigned int version ) { archive & boost::serialization::base_object<Widget>( *this );
std::string text; archive & text; m_text.reset( new Text( text ) ); }
boost::scoped_ptr<Text> m_text;
friend class boost::serialization::access; }; }
BOOST_CLASS_TYPE_INFO( rs::StaticText, extended_type_info_no_rttirs::StaticText )
BOOST_CLASS_EXPORT( rs::StaticText )
#endif // RS_GUI_WIDGETS_STATICTEXT_HPP
When I compile this into a LIB first, and then link the lib into an EXE, the linker says this (Visual Studio 2008): gui.lib(StaticText.obj) : error LNK2005: "public: static struct boost::archive::detail::guid_initializer<class rs::StaticText> const & const boost::archive::detail::init_guid<class rs::StaticText>::guid_initializer" (?guid_initializer@ ?$init_guid@VStaticText@rs@@@detail@archive@boost@ @2ABU?$guid_initializer@VStaticText@rs@@@234@B) already defined in main.obj
If I move the 2 macro calls into the StaticText.cpp file, everything compiles/links just fine but I end up getting an exception thrown at runtime that says "unregistered void cast".
________________________________
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Two things are getting mixed up here.
a) The first is not using RTTI. You've used the test as an example and this seems fine to me.
b) You want to serialize a polymorphic derived class through a pointer to it's base class. This
is OK too, but requires special care. The problem is that C++ compile/link will generally not
include code which is not specifically referred to. This occurs when compiling (optimizing out
dead code) and linking - skipping modules not referred to.
To deal with the second, you have "trick" the compiler/linker to not discard your code. There
are a couple of ways to do this.
a) Somewhere in the main module, refer to the derived type in the library. An easy way to
do this is to just create one more function in your code which refers to the code in the library.
Well, its not that easy because the C++ optimiser will usually throw away the whole call
if the result isn't used. You can use the "force_include.hpp" to keep this from happening.
b) You can re-package your library as a DLL. DLLS are different in that the whole DLL
is imported when the application starts up - not just the functions actually referred to.
The "registers" all the "EXPORT"ed functions and things would as advertised.
Sorry it has to be this way. The whole idea of using a library is to automatically
include only that code which the linker detects is actually called. Loading through
a base class pointer explicitly hides this fact so one has to make special effort
of some sort. The only other alternative would be to have the linker import ALL the
code in the library which would defeat the reason for having a library in the first place.
Robert Ramey
"Robert Dailey"
On Fri, Apr 3, 2009 at 1:37 PM, Robert Ramey
Two things are getting mixed up here.
a) The first is not using RTTI. You've used the test as an example and this seems fine to me.
This is the exact behavior I'm looking for. The platform in question does not support RTTI and thus I cannot use it.
b) You want to serialize a polymorphic derived class through a pointer to it's base class. This is OK too, but requires special care. The problem is that C++ compile/link will generally not include code which is not specifically referred to. This occurs when compiling (optimizing out dead code) and linking - skipping modules not referred to.
To deal with the second, you have "trick" the compiler/linker to not discard your code. There are a couple of ways to do this.
a) Somewhere in the main module, refer to the derived type in the library. An easy way to do this is to just create one more function in your code which refers to the code in the library. Well, its not that easy because the C++ optimiser will usually throw away the whole call if the result isn't used. You can use the "force_include.hpp" to keep this from happening.
Could you give me a code example for this? I'm not sure what the code for this is. Do I just define a global function in force_include.hpp and implement that function in each base class's CPP file? What would the definition of such a global function have? I obviously have to call this global function somewhere, where would I call it? b) You can re-package your library as a DLL. DLLS are different in that the
whole DLL is imported when the application starts up - not just the functions actually referred to. The "registers" all the "EXPORT"ed functions and things would as advertised.
Sorry it has to be this way. The whole idea of using a library is to automatically include only that code which the linker detects is actually called. Loading through a base class pointer explicitly hides this fact so one has to make special effort of some sort. The only other alternative would be to have the linker import ALL the code in the library which would defeat the reason for having a library in the first place.
Could you explain to me why having all of the code in the LIB file defeats the purpose for having a library in the first place? Of the two solutions you listed above (DLL vs global function), which would you suggest? Using a DLL seems like the most transparent solution and I might go for that. Thanks for your help, I really appreciate it.
Also, I'm a bit confused about something else Robert.
All along we've been saying that if the code in the translation unit is not
used, it may be stripped by the linker. What code exactly is being stripped?
I mean, I create my classes before I serialize them and I'm calling member
functions on these instances. So for sure the translation unit is being
"entered" before serialization even begins. Does this not meet the
requirements?
Is the problem that the code generated by BOOST_CLASS_EXPORT() and
BOOST_CLASS_TYPE_INFO() is not being used, and thus stripped?
On Fri, Apr 3, 2009 at 12:48 PM, Robert Dailey
On Fri, Apr 3, 2009 at 1:37 PM, Robert Ramey
wrote: Two things are getting mixed up here.
a) The first is not using RTTI. You've used the test as an example and this seems fine to me.
This is the exact behavior I'm looking for. The platform in question does not support RTTI and thus I cannot use it.
b) You want to serialize a polymorphic derived class through a pointer to it's base class. This is OK too, but requires special care. The problem is that C++ compile/link will generally not include code which is not specifically referred to. This occurs when compiling (optimizing out dead code) and linking - skipping modules not referred to.
To deal with the second, you have "trick" the compiler/linker to not discard your code. There are a couple of ways to do this.
a) Somewhere in the main module, refer to the derived type in the library. An easy way to do this is to just create one more function in your code which refers to the code in the library. Well, its not that easy because the C++ optimiser will usually throw away the whole call if the result isn't used. You can use the "force_include.hpp" to keep this from happening.
Could you give me a code example for this? I'm not sure what the code for this is. Do I just define a global function in force_include.hpp and implement that function in each base class's CPP file? What would the definition of such a global function have? I obviously have to call this global function somewhere, where would I call it?
b) You can re-package your library as a DLL. DLLS are different in that
the whole DLL is imported when the application starts up - not just the functions actually referred to. The "registers" all the "EXPORT"ed functions and things would as advertised.
Sorry it has to be this way. The whole idea of using a library is to automatically include only that code which the linker detects is actually called. Loading through a base class pointer explicitly hides this fact so one has to make special effort of some sort. The only other alternative would be to have the linker import ALL the code in the library which would defeat the reason for having a library in the first place.
Could you explain to me why having all of the code in the LIB file defeats the purpose for having a library in the first place?
Of the two solutions you listed above (DLL vs global function), which would you suggest? Using a DLL seems like the most transparent solution and I might go for that.
Thanks for your help, I really appreciate it.
"Robert Dailey"
"Robert Dailey"
wrote in message news:496954360904031054x3cb9f3cfldf1985695a096614@mail.gmail.com... Also, I'm a bit confused about something else Robert. All along we've been saying that if the code in the translation unit is not used, it may be stripped by the linker. What code exactly is being stripped? I mean, I create my classes before I serialize them and I'm calling member functions on these instances. So for sure the translation unit is being "entered" before serialization even begins. Does this not meet the requirements?
I've been presuming your doing something like:
base * b = new derived; ar << b;
.... base * new_b;
ar >> new_b; the linker look for the code to load derived.
Robert Ramey
What exactly are you trying to say here? Are you saying that only when I stream in does the translation unit for "derived" get visited? Could you
On Fri, Apr 3, 2009 at 3:02 PM, Robert Ramey
"Robert Dailey"
On Fri, Apr 3, 2009 at 4:07 PM, Robert Ramey
**** at this point, the serialization library doesn't necessary doesn't know anything about derived. (I'm assuming derived is polymorphic.) Depending on what is compiled into the library and waht is inline, there may or may not be a problem at link time
Sorry I feel like we're going in circles about this. Let me explain in detail how I see what is happening. Because I'm calling functions off of "base" polymophically from my executable using the LIB in question, it *cannot* ignore the two classes "base" and "derived", because I'm actually using the code. The polymorphic behavior of the function call "base->DoStuff()" touches the implementations of that function in "base::DoStuff()" and "derived::DoStuff()". So it isn't the classes themselves being ignored, it has to be something else. When I call "BOOST_CLASS_EXPORT( derived )", it creates a specialization of the class "init_guid<>". Right below that, the static variable inside the "init_guid" struct is statically initialized with some value from a singleton. This class *cannot* be going away, because the act of calling a member function off of "derived" (e.g. derived::DoStuff() ) causes that translation unit to be visited, thus causing that static member to be initialized. So it seems that given the circumstances, nothing in this translation unit is going away. Because I am calling a member function off of my "derived" instance before I serialize it out, the translation unit is being "visited" and that alone is all that the "derived" class needs. However, the "base" class has no implementation for "DoStuff", it is pure virtual. This means the "base" translation unit is not being visited. Is this the problem? This might be the reason for the "unregistered void cast" error. Am I on the right track about all of this? You mentioned a "force_export" header of some sort, but I'm not sure where you are going with this. As far as I know, this is undocumented behavior in Boost.Serialization. If someone wouldn't mind providing me a detailed and functional example of how to use this "force_export" concept, I would appreciate it. I also do not wish to use archive.register_type<>, because this requires doing this for every archive I am using. If I add a new derived type, I'll have to go back and change this. This violates the open/close principle. This whole thing is pretty confusing, so I hope you'll bear with me while I try to understand this.
On Fri, Apr 3, 2009 at 3:30 PM, Robert Dailey
On Fri, Apr 3, 2009 at 4:07 PM, Robert Ramey
wrote: **** at this point, the serialization library doesn't necessary doesn't know anything about derived. (I'm assuming derived is polymorphic.) Depending on what is compiled into the library and waht is inline, there may or may not be a problem at link time
Sorry I feel like we're going in circles about this. Let me explain in detail how I see what is happening.
Because I'm calling functions off of "base" polymophically from my executable using the LIB in question, it *cannot* ignore the two classes "base" and "derived", because I'm actually using the code. The polymorphic behavior of the function call "base->DoStuff()" touches the implementations of that function in "base::DoStuff()" and "derived::DoStuff()".
So it isn't the classes themselves being ignored, it has to be something else. When I call "BOOST_CLASS_EXPORT( derived )", it creates a specialization of the class "init_guid<>". Right below that, the static variable inside the "init_guid" struct is statically initialized with some value from a singleton. This class *cannot* be going away, because the act of calling a member function off of "derived" (e.g. derived::DoStuff() ) causes that translation unit to be visited, thus causing that static member to be initialized.
So it seems that given the circumstances, nothing in this translation unit is going away. Because I am calling a member function off of my "derived" instance before I serialize it out, the translation unit is being "visited" and that alone is all that the "derived" class needs.
However, the "base" class has no implementation for "DoStuff", it is pure virtual. This means the "base" translation unit is not being visited. Is this the problem? This might be the reason for the "unregistered void cast" error. Am I on the right track about all of this?
You mentioned a "force_export" header of some sort, but I'm not sure where you are going with this. As far as I know, this is undocumented behavior in Boost.Serialization. If someone wouldn't mind providing me a detailed and functional example of how to use this "force_export" concept, I would appreciate it. I also do not wish to use archive.register_type<>, because this requires doing this for every archive I am using. If I add a new derived type, I'll have to go back and change this. This violates the open/close principle.
This whole thing is pretty confusing, so I hope you'll bear with me while I try to understand this.
In our current example we've been using 2 classes: "base" and "derived". These are not accurate examples, however. In reality the "base" class is actually "Widget", and "derived" is "StaticText". Widget has: Widget::SetPosition() This function is implemented in Widget.cpp. Widget.cpp also has the BOOST_CLASS_EXPORT( Widget ) call. StaticText has a constructor that takes a string, which is also implemented in StaticText.cpp. This file also has BOOST_CLASS_EXPORT( StaticText ) So when I have code in my executable that does this: StaticText* text = new rs::StaticText( "Hello World" ); text->SetPosition( 20, 20 ); The first line of code results in the constructor for staticText to be called, which means StaticText.cpp gets "touched". The second line calls the non-virtual SetPosition() call in base class Widget, which results in Widget.cpp getting touched. So both translation units are getting touched, which means both macros are being executed. This should work just fine, right? Later on I do this: Widget* widget = text; archive << widget;
"Robert Dailey"
On Fri, Apr 3, 2009 at 2:59 PM, Robert Ramey
One fool proof method is to use the funcion archive.register_type to for the derived type to indicate to the archive that code for this type MUST be included.
Could you provide a code example for archive.register_type or link me to
documentation on this? I really am not sure what you mean. I'm still confused because I'm currently doing things to my derived and base types that should result in the translation units for both being visited.
"Robert Dailey"
participants (3)
-
Renaud Lepere
-
Robert Dailey
-
Robert Ramey