[serialization] polymorphic archives + boost_class_export generates linker errors

Hi, I've posted this with no luck to the boost-users mailing list: the attached example [1] generates a couple of linker [2] errors on msvc 9.0 / boost 1.40.0 all related to missing archive_serializer_map symbols. when switching from polymorphic archives to corresponding non-polymorphic archives the attached example runs fine. It seems that the usage of BOOST_CLASS_EXPORT in conjunction with polymorphic archives triggers the linker error. I tried to add explicit template instantiations, such as [3], for the missing types to boost archive, recompiled boost and was able to get rid of the linker error. The problem then, however, is that the example fails at runtime with an assertion that a type-lookup did not succeed. So I guess adding the explicit template instantiations was not the correct approach. Is this a bug? Can anyone confirm this issue? Best regards, Christoph

Have your tried runnig the tests/demos included with the package that use polymorphic archives? Do they build and run? Robert Ramey Christoph Heindl wrote:
Hi,
I've posted this with no luck to the boost-users mailing list:
the attached example [1] generates a couple of linker [2] errors on msvc 9.0 / boost 1.40.0 all related to missing archive_serializer_map symbols.
when switching from polymorphic archives to corresponding non-polymorphic archives the attached example runs fine.
It seems that the usage of BOOST_CLASS_EXPORT in conjunction with polymorphic archives triggers the linker error.
I tried to add explicit template instantiations, such as [3], for the missing types to boost archive, recompiled boost and was able to get rid of the linker error. The problem then, however, is that the example fails at runtime with an assertion that a type-lookup did not succeed. So I guess adding the explicit template instantiations was not the correct approach.
Is this a bug? Can anyone confirm this issue?
Best regards, Christoph
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Robert, I haven't yet. Instead, I've downloaded the binaries from boost-pro and checked with them and got the same linker error. Can you provide me with information on how to build/run just the tests for serialization with bjam? Best regards, Christoph

Christoph Heindl wrote:
Robert,
I haven't yet. Instead, I've downloaded the binaries from boost-pro and checked with them and got the same linker error.
Can you provide me with information on how to build/run just the tests for serialization with bjam?
1. Get source 2. In source tree root: .\bootstrap.bat 3. In source tree root . .\bjam libs/serialization/test HTH, Volodya

Volodya, thanks a lot! I'll give it a try. On Thu, Nov 26, 2009 at 9:27 AM, Vladimir Prus <vladimir@codesourcery.com> wrote:
Christoph Heindl wrote:
Robert,
I haven't yet. Instead, I've downloaded the binaries from boost-pro and checked with them and got the same linker error.
Can you provide me with information on how to build/run just the tests for serialization with bjam?
1. Get source 2. In source tree root:
.\bootstrap.bat
3. In source tree root .
.\bjam libs/serialization/test
HTH, Volodya
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Christoph Heindl wrote:
Volodya,
thanks a lot! I'll give it a try.
On Thu, Nov 26, 2009 at 9:27 AM, Vladimir Prus <vladimir@codesourcery.com> wrote:
Christoph Heindl wrote:
Robert,
I haven't yet. Instead, I've downloaded the binaries from boost-pro and checked with them and got the same linker error.
Can you provide me with information on how to build/run just the tests for serialization with bjam?
1. Get source 2. In source tree root:
.\bootstrap.bat
3. In source tree root .
.\bjam libs/serialization/test
Note that Robert suggested to build demo, so you might actually want to do: .\bjam libs/serialization/examples//demo_polymorphic (The double slash is not a typo, it separates project/directory name from target name). - Volodya

I've been able to successfully compile/link/run the demo_polymorphic. demo_polymorphic, however, uses no boost_class_export. So I've added it along with a virtual destructor and was still able to run the demo. But once I've added #include <boost/archive/xml_iarchive.hpp> to demo_polymorphic_A.cpp so top of the file becomes #include <boost/archive/xml_iarchive.hpp> #include <boost/archive/polymorphic_iarchive.hpp> #include <boost/archive/polymorphic_oarchive.hpp> #include <boost/serialization/export.hpp> #include "demo_polymorphic_A.hpp" BOOST_CLASS_EXPORT(A); the compiler breaks with "cannot convert parameter 1 from 'boost::archive::xml_iarchive' to 'boost::archive::polymorphic_iarchive &" in 'boost/serialization/access.hpp' Not the linker error I noticed but probably related to the source of the problem. That raises a couple of questions: - in my example i use polymorphic archives but still implement the templated version of serialize. Is that allowed? The reason for doing so is that I do not have knowledge about the concrete archive type the user supplies. - can a class be exported for polymorphic and non-polymorphic archives at the same time? Best regards, Christoph

Christoph Heindl wrote:
#include <boost/archive/xml_iarchive.hpp> #include <boost/archive/polymorphic_iarchive.hpp> #include <boost/archive/polymorphic_oarchive.hpp> #include <boost/serialization/export.hpp> #include "demo_polymorphic_A.hpp" BOOST_CLASS_EXPORT(A);
the compiler breaks with "cannot convert parameter 1 from 'boost::archive::xml_iarchive' to 'boost::archive::polymorphic_iarchive &" in 'boost/serialization/access.hpp'
I took this example and indeed it failed to compile. It took me quite a while to discover the cause. demo_polymorphic_A.hpp includes class A { ... void serialization(boost::archive::polymorphic_iarchive &ar, const unsigned version); ... }; When BOOST_CLASS_EXPORT(A) is encountered, it attempts to "register" All the archives included. This means xml_iarchive with the type A. But class A includes declaration only for polymorphic_iarchive. So during the "register" process, it tries to convert a reference to xml_iarchive to a reference to polymorphic_iarchive - which fails with a compile time error. So the appropriate fix is not to include xml_iarchive - (maybe to enforce the usage of polymorphic archives all the time- or whatever reason) or use replace the serialize above with: ttemplate<class Archive> void serialize(Archive & ar, const unsigned int version); This WILL compile without problem. However it will fail to link as the serialization function will not have been instantiated with xml_iarchive. This can be addressed by altering demo_polymorphic_A.cpp to look like the following: #include <boost/archive/polymorphic_iarchive.hpp> #include <boost/archive/polymorphic_oarchive.hpp> #include "demo_polymorphic_A.hpp" // explicitly instantiate templates for polymorphic archives // used by this demo. template void A::serialize<boost::archive::polymorphic_iarchive>( boost::archive::polymorphic_iarchive &, const unsigned int ); template void A::serialize<boost::archive::polymorphic_oarchive>( boost::archive::polymorphic_oarchive &, const unsigned int ); This will compiler and link as expected. Perhaps this explanation will help with your own application. At the bottom of its is the EXPORT(A) requires that templates or declarations exist which match all archive classes included. Robert Ramey

Robert,
This will compiler and link as expected. Perhaps this explanation will help with your own application. At the bottom of its is the EXPORT(A) requires that templates or declarations exist which match all archive classes included.
Thanks a lot for the explanation. This actually helped me quite a lot in getting my example to compile. Thanks for that! One more question, Robert: Did you have a chance to look up the subsequent issue I posted this thread? Here's the gmane link http://article.gmane.org/gmane.comp.lib.boost.devel/197061 I really feel inconvenient to bother you with this. What's the policy for such potential issues anyway? Post them on the mailing list or file them as bug? Best regards, Christoph

Hi all, boost:1.4.0 compiler: vs 2005 code: #define Data_Io_Load_Save(class_name, members) \ friend class boost::serialization::access; \ template<class Archive> \ void serialize(Archive & ar, const unsigned int version) \ { ar members; } #define Data_Io_Load_Save_Base(base_class) BOOST_SERIALIZATION_BASE_OBJECT_NVP(base_class) #define Auto_Value_Decl(type) BOOST_SERIALIZATION_NVP(type) struct TestStruct { int type; int ina[10]; std::map<std::string, std::string> mapstr; Data_Io_Load_Save(TestStruct, &Auto_Value_Decl(type) &Auto_Value_Decl(ina) &Auto_Value_Decl(mapstr) ); }; void TestSerial() { TestStruct ts, its; ts.type = 2222; ts. mapstr ["str1"] = "str1"; ts. mapstr ["str2"] = "str2"; ts. mapstr ["str3"] = "str3"; ts. mapstr ["str4"] = "str4"; // save std::ofstream ofs("proto.txt"); boost::archive::xml_oarchive oa(ofs); oa << Auto_Value_Decl(ts. mapstr); // oa << Auto_Value_Decl(ts); // ofs.close(); //load std::ifstream ifs("proto.txt"); boost::archive::xml_iarchive ia(ifs); ts.mapint.clear(); ia & Auto_Value_Decl(ts. mapstr); // error ia & Auto_Value_Decl(its); // error ifs.close(); } because loading " std::map<std::string, std::string> mapstr;", the compiler stop at stack_constructor.hpp:64, the line is " this->address()->~T(); " so, I changed "stack_constructor.hpp" template<typename T > struct stack_allocate { T * address() { return static_cast<T*>(&storage_/*.address()*/); } T & reference() { return * address(); } private: //typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage< // sizeof(T), // #if BOOST_WORKAROUND(__BORLANDC__,BOOST_TESTED_AT(0x560)) // 8 // #else // boost::alignment_of<T>::value // #endif //> type; T storage_; }; // construct element on the stack template<class Archive, class T> struct stack_construct : public stack_allocate<T> { stack_construct(Archive & ar, const unsigned int version){ //// note borland emits a no-op without the explicit namespace //boost::serialization::load_construct_data_adl( // ar, // this->address(), // version //); } ~stack_construct(){ //this->address()->~T(); // undo load_construct_data above } }; then, all be ok. Regards. Simon Cheung.

Robert,
Have your tried runnig the tests/demos included with the package that use polymorphic archives? Do they build and run?
I've run all tests and polymorphic examples successfully. This however does not solve my problem: My initial linker error was due to the included headers in my previous example: including <boost/archive/polymorphic_xml_archive.hpp> or any other concrete polymorphic archive before a call to BOOST_CLASS_EXPORT fails with the named linker error. I was not aware of the the fact that including <boost/polymorphic_iarchive.hpp> and <boost/polymorphic_oarchive.hpp> suffices to enable export for all polymorphic archives. Maybe this should go into documentation? Based on demo_polymorphic.cpp I've re-created minimal test example, which I think is correct, that fails with the runtime assertion it != m_map.end(), file libs\serialization\src\basic_serializer_map.cpp, line 72 on load. The demo consists of 5 files that create the following scenario: class B inherits from polymorphic base class A. An object of B is allocated on the heap and serialized through a base pointer A using a polymorphic xml archive. Saving runs without problems. Next, B is loaded from the stream through a base pointer to A. This fails with the mentioned assertion. What makes me wonder is that changing the from polymorphic_xml_iarchive to xml_iarchive and from polymorphic_xml_oarchive to xml_oarchive will not produce the named assertion. As mentioned in my previous post, I tested this with boost 1.40.0 and msvc 9.0. I would be really, really, grateful if you could give the demo a try. I've prepared everything so that it is just a matter of copying the files to libs/serialization/example and adding [ demo_bsl_run demo_polymorphic_cheind : cheind_a cheind_b ] to the jamfile. I hope it is ok to attach the files directly to this message. With best regards, Christoph
participants (4)
-
Christoph Heindl
-
Robert Ramey
-
Simon Cheung
-
Vladimir Prus