Re: [Boost-users] Serialization : unregistered_cast & otherquestions
Hello Robert, Thanks for your reply. However you did not understand the problem. I read the documentation and understood the purpose of BOOST_EXPORT as explained in the documentation, and as reexplained in your last mail. The problem is at linking, but is not one of undefined reference (template not instantiated), but, on the other hand, *a multiple definition problem.* If, as suggested, you move BOOST_EXPORT to the class header, even if you move the archive headers before the serialization/export header, you will have multiple instantiations of the same template. This is because every time you include the serialization class header in your program there is some code instantiation, since the EXPORT is in that file. Since this header is included several times in the program, multiple instantiations of the same code occurs (note: apparently this happens even if there is no definition of the templated code to be instantiated (since the implementation is only in the .cc), only a declaration, because BOOST_EXPORT instantiates some kind of *helper code* that gets multiple defined). Anyway, if you can change the code in order to avoid this multiple definition problem, I'll be glad to test, but I believe it is impossible. However, putting BOOST_EXPORT in the .cc avoids the problem entirely, so this is acceptable. I am sending again code with your suggested changes, in order to show you your method does not work. If you look at the code you will see that each serialization header includes <CommonSerialize.h> which contains the archive headers. Then after <CommonSerialize.h> inclusion comes serialization/export.hpp inclusion, so the archive headers are BEFORE export.hpp. Then follows BOOST_EXPORT. At linking I get the multiple definition problem that I mentioned. If you just move BOOST_EXPORT into the .cc no problems at all. You can check for yourself if you try to compile the code. Thank you!! Jean-Noël Ps: I ran into two other problems that I'll write mail for later... OK - BOOST_EXPORT has some non-obvious behavior which I'll explain. Maybe this will help. BOOST_EXPORT has two functions: a) To associate a class with an external unique name (GUID) b) To instanticiate templated code for archives used. The second is not as obvious as it might seem. Suppose I have: class A { }; class B : public A { } A * aptr = new B; text_archive ar; ar << a; The problem is that the compiler never sees anything like ar << b so it has no way to know that the serialization code for B needs to be instantiated for the archive class text_archive. So each archive class defines a special macro. Then BOOST_EXPORT instantiates code for each combination of the class and archive class. If this were not done, one would get a link error with undefined symbol for load<text_archive, B> or something lke that. Of course the above presumes that the archive classes are included BEFORE the serialization/boost/export.hpp header. So if you make the following changes in your code I believe you will get the desired results. a) Move BOOST_EXPORT to the class header. b) In test.cc - move the headers boost/archive/... above the headers boost/serialization/.. and let me know that happens. Robert Ramey
"RIVASSEAU Jean Noel" <JN.RIVASSEAU@oberthurcs.com> wrote in message news:87F60F7FA02FF749AFB02BD9FCAA6B04DA7774@naserv31.nanterre.oberthurcs.com... Hello Robert, Thanks for your reply. However you did not understand the problem. I read the documentation and understood the purpose of BOOST_EXPORT as explained in the documentation, and as reexplained in your last mail. The problem is at linking, but is not one of undefined reference (template not instantiated), but, on the other hand, *a multiple definition problem.* If, as suggested, you move BOOST_EXPORT to the class header, even if you move the archive headers before the serialization/export header, you will have multiple instantiations of the same template. This is because every time you include the serialization class header in your program there is some code instantiation, since the EXPORT is in that file. *** Hmmm - I'll look into this. I would have expected that additional code would be generated if and only if <boost/archive/... headers are included. If these are included only once, I wouldn't expect any multiple definitions. The top of export.hpp includes the following: // if no archive headers have been included this is a no op // this is to permit BOOST_EXPORT etc to be included in a // file declaration header #if ! defined(BOOST_ARCHIVE_BASIC_ARCHIVE_HPP) #define BOOST_CLASS_EXPORT_GUID_ARCHIVE_LIST(T, K, ASEQ) which I would expect would make a BOOST_EXPORT an effective no-op if no archive files are included. **** Robert Ramey
On Feb 27, 2006, at 08:51, Robert Ramey wrote:
*** Hmmm - I'll look into this. I would have expected that additional code would be generated if and only if <boost/archive/... headers are included. If these are included only once, I wouldn't expect any multiple definitions. The top of export.hpp includes the following:
// if no archive headers have been included this is a no op // this is to permit BOOST_EXPORT etc to be included in a // file declaration header #if ! defined(BOOST_ARCHIVE_BASIC_ARCHIVE_HPP) #define BOOST_CLASS_EXPORT_GUID_ARCHIVE_LIST(T, K, ASEQ)
which I would expect would make a BOOST_EXPORT an effective no-op if no archive files are included.
I'll chime in, as I'm having exactly the same issue, but on darwin/ gcc-4 with code in multiple dynamically loaded libraries... (I have other issues too, I get to those later) The problem is that although export.hpp is only included once per generated .o file, there are multiple .o files all including the same headers - and each therefore generates the same template instantiations, thereby causing the multiple definitions during linking. Also - the same headers may be included in multiple shared libraries, exacerbating the problem with the same code instantiated into multiple libraries - a serious problem if there are singletons. I may not be understanding this correctly - here's what >I< think needs to happen - please correct me. For any derived class, there is a set of code (templates) that need to be instantiated for each archive type (specifically, the list boost::archive::detail::known_archive_types::type, for the templates guid_initializer<T> and export_instantiate<T, archive_list>) From what I see, these are NOT declarations required by the other serialization code, but singletons that, during construction, register the serializers to the derived classes with the extended_type_info class registry. Is that incorrect? If the above is correct, then the BOOST_EXPORT_CLASS should only be in exactly one implementation file (.cpp, .C, .cc, whatever). And also, THAT implementation file should ONLY be linked into one shared library.
Hugh Hoover wrote:
On Feb 27, 2006, at 08:51, Robert Ramey wrote:
*** Hmmm - I'll look into this. I would have expected that additional code would be generated if and only if <boost/archive/... headers are included. If these are included only once, I wouldn't expect any multiple definitions. The top of export.hpp includes the following:
// if no archive headers have been included this is a no op // this is to permit BOOST_EXPORT etc to be included in a // file declaration header #if ! defined(BOOST_ARCHIVE_BASIC_ARCHIVE_HPP) #define BOOST_CLASS_EXPORT_GUID_ARCHIVE_LIST(T, K, ASEQ)
which I would expect would make a BOOST_EXPORT an effective no-op if no archive files are included.
I'll chime in, as I'm having exactly the same issue, but on darwin/ gcc-4 with code in multiple dynamically loaded libraries... (I have other issues too, I get to those later)
The problem is that although export.hpp is only included once per generated .o file, there are multiple .o files all including the same headers - and each therefore generates the same template instantiations, thereby causing the multiple definitions during linking. Also - the same headers may be included in multiple shared libraries, exacerbating the problem with the same code instantiated into multiple libraries - a serious problem if there are singletons.
I may not be understanding this correctly - here's what >I< think needs to happen - please correct me.
For any derived class, there is a set of code (templates) that need to be instantiated for each archive type (specifically, the list boost::archive::detail::known_archive_types::type, for the templates guid_initializer<T> and export_instantiate<T, archive_list>) From what I see, these are NOT declarations required by the other serialization code, but singletons that, during construction, register the serializers to the derived classes with the extended_type_info class registry. Is that incorrect?
If the above is correct, then the BOOST_EXPORT_CLASS should only be in exactly one implementation file (.cpp, .C, .cc, whatever). And also, THAT implementation file should ONLY be linked into one shared library.
Not quite. There should be only one source module which includes boost/archive/... declarations. If there is more than one of these then there is a risk of multiple definitions. My practice is to: a) include all boost/serialization/.. headers in each class file. b) include NO boost/archive/... headers in any class file c) make a "template instantiation module" which instanticiates code for all archives I plan to use. This can be either in the app or in a library. d) lihk and execute without problem. Robert Ramey
On Feb 27, 2006, at 08:51, Robert Ramey wrote:
*** Hmmm - I'll look into this. I would have expected that additional code would be generated if and only if <boost/archive/... headers are included. If these are included only once, I wouldn't expect any multiple definitions. The top of export.hpp includes the following:
// if no archive headers have been included this is a no op // this is to permit BOOST_EXPORT etc to be included in a // file declaration header #if ! defined(BOOST_ARCHIVE_BASIC_ARCHIVE_HPP) #define BOOST_CLASS_EXPORT_GUID_ARCHIVE_LIST(T, K, ASEQ)
which I would expect would make a BOOST_EXPORT an effective no-op if no archive files are included.
I'll chime in, as I'm having exactly the same issue, but on darwin/ gcc-4 with code in multiple dynamically loaded libraries... (I have other issues too, I get to those later) The problem is that although export.hpp is only included once per generated .o file, there are multiple .o files all including the same headers - and each therefore generates the same template instantiations, thereby causing the multiple definitions during linking. Also - the same headers may be included in multiple shared libraries, exacerbating the problem with the same code instantiated into multiple libraries - a serious problem if there are singletons. I may not be understanding this correctly - here's what >I< think needs to happen - please correct me. For any derived class, there is a set of code (templates) that need to be instantiated for each archive type (specifically, the list boost::archive::detail::known_archive_types::type, for the templates guid_initializer<T> and export_instantiate<T, archive_list>) From what I see, these are NOT declarations required by the other serialization code, but singletons that, during construction, register the serializers to the derived classes with the extended_type_info class registry. Is that incorrect? If the above is correct, then the BOOST_EXPORT_CLASS should only be in exactly one implementation file (.cpp, .C, .cc, whatever). And also, THAT implementation file should ONLY be linked into one shared library.
participants (3)
-
Hugh Hoover
-
RIVASSEAU Jean Noel
-
Robert Ramey