[Serialization] Serialization of a class in a DLL
Hi everybody,
I have just tried a simple example of a class serialization in a DLL and did not
manage to make it work. I have been using Boost serialization since a while but
until now I was putting all the serialization code in the .hpp. By the way
thanks Robert (and Boost) for this great library.
I am using MSVC 8.0 and Boost 1.34.1. I have tried the same with Boost
Serialization 1.36 (head of Boost) without any success.
My test is the following. The class MyClass in declared in a DLL
boost-example.dll built from Example.cpp. A test program Example.t.cpp linked
with boost-example.dll try to serialize MyClass to an XML archive.
The files are the following:
//////// Example.hpp
#if _MSC_VER > 1000
#pragma once
#endif
// Do NOT include any headers after this point #if
(defined(__COMPILING_Example_CPP__) && defined(WIN32)) #define _LIBSPEC
__declspec(dllexport) #else #define _LIBSPEC #endif
class _LIBSPEC MyClass
{
public:
MyClass();
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive & ar, const unsigned int version);
std::string m_str;
};
//////// Example.cpp
#include <string>
#include "boost/archive/xml_oarchive.hpp"
#include "boost/archive/xml_iarchive.hpp"
#include "boost/serialization/nvp.hpp"
#include "boost/serialization/export.hpp"
#include "Example.hpp"
using namespace std;
BOOST_CLASS_EXPORT(MyClass); // should explicity instantiate template for
// xml_oarchive and xml_iarchive
MyClass::MyClass()
: m_str("MyClass") {}
template <class Archive>
void MyClass::serialize(Archive & ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(m_str);
}
//////// Example.t.cpp
#include <iostream>
#include <fstream>
#include "boost/archive/xml_oarchive.hpp"
#include "boost/serialization/nvp.hpp"
#include "Example.hpp"
using namespace std;
int main(int argc, char* argv[])
{
MyClass myClass;
// try to serialize MyClass using an XML archive
ofstream ofs("myClass.xml");
if( !ofs ) {
cout << "ERROR: Could not open myClass.xml for writing";
return EXIT_FAILURE;
}
try {
boost::archive::xml_oarchive oa(ofs);
oa << BOOST_SERIALIZATION_NVP(myClass);
} catch (const std::exception& e) {
cout << "failed to serialize MyClass with xml_oarchive: " << e.what();
ofs.setstate(ios::failbit);
}
return EXIT_SUCCESS;
}
When compiling this, I got an error at link time for Example.t:
Example.t.obj : error LNK2019: unresolved external symbol "private: void __thisc
all MyClass::serialize<class boost::archive::xml_oarchive>(class boost::archive:
:xml_oarchive &,unsigned int)" (??$serialize@Vxml_oarchive@archive@boost@@@MyCla
ss@@AAEXAAVxml_oarchive@archive@boost@@I@Z) referenced in function "public: stat
ic void __cdecl boost::serialization::access::serialize
In order for this to work, you have to explicitly instantiate the code in the library/dll. It will not be instantiated automatically as it is not called from within the library. For an example of this take a look at demo_pimple Robert Ramey Cyril Picat wrote:
Hi everybody,
I have just tried a simple example of a class serialization in a DLL and did not manage to make it work. I have been using Boost serialization since a while but until now I was putting all the serialization code in the .hpp. By the way thanks Robert (and Boost) for this great library.
I am using MSVC 8.0 and Boost 1.34.1. I have tried the same with Boost Serialization 1.36 (head of Boost) without any success.
My test is the following. The class MyClass in declared in a DLL boost-example.dll built from Example.cpp. A test program Example.t.cpp linked with boost-example.dll try to serialize MyClass to an XML archive.
The files are the following:
//////// Example.hpp #if _MSC_VER > 1000 #pragma once #endif
// Do NOT include any headers after this point #if (defined(__COMPILING_Example_CPP__) && defined(WIN32)) #define _LIBSPEC __declspec(dllexport) #else #define _LIBSPEC #endif
class _LIBSPEC MyClass { public: MyClass();
private: friend class boost::serialization::access;
template <class Archive> void serialize(Archive & ar, const unsigned int version);
std::string m_str;
};
// add the folloing here
#include
On Thu, May 29, 2008 at 10:20 AM, Robert Ramey
#include
#include
.... // instanciate the code we want to generate and add tothe library template MyClass::serializeboost::archive::xml_oarchive;
template MyClass::serializeboost::archive::xml_iarchive;
Shouldn't there also be something to register the types and archives
that are statically linked into the DLL so that serialization of
shared_ptr
Emil Dotchevski wrote:
On Thu, May 29, 2008 at 10:20 AM, Robert Ramey
wrote: #include
#include
.... // instanciate the code we want to generate and add tothe library template MyClass::serializeboost::archive::xml_oarchive;
template MyClass::serializeboost::archive::xml_iarchive;
Shouldn't there also be something to register the types and archives that are statically linked into the DLL so that serialization of shared_ptr
, etc. can find them?
This would be necessary for those types - and only those types which use BOOST_CLASS_EXPORT. In this case the BOOST_CLASS_EXPORT would go into the *.cpp module which explicitly instantiates the code for each archive.
Also, is it possible to safely unload a DLL that uses boost::serialization?
Yes - when the DLL is unloaded, the main registration table is updated accordingly. The only restriction is that you can't be unloading dlls at the same time you're serializing some type which requires code in that dll. Robert Ramey
Ok, I thought that BOOST_CLASS_EXPORT will take care of instantiating it. Actually isn't it what is explained in the doc in paragraph 'Exporting Class Serialization'? I am a bit confused and sure I should dive into the Boost.Serialization code to understand more what the macro is doing. The problem with your solution is that I don't want to include any Boost header in Example.hpp. So I have tried the solution from demo_pimpl but it still fail to link with vc 8.0 (there is a comment saying that it fails with vc 7.0)? Is it expected? So I have ended with forward declaring the archives I need in Example.hpp and it works. Though, I would rather but the explicit template instantiation in Example.cpp to keep a clean implementation agnostic header. Is there any way to make this work with VC ? So if anybody is interested, the final Example.hpp is: /////// Example.hpp #if _MSC_VER > 1000 #pragma once #endif // Do NOT include any headers after this point #if (defined(__COMPILING_Example_CPP__) && defined(WIN32)) #define _LIBSPEC __declspec(dllexport) #define _EXPORT_TEMPLATE template _LIBSPEC #else #define _LIBSPEC #define _EXPORT_TEMPLATE extern template _LIBSPEC #endif namespace boost { namespace archive { class xml_oarchive; class xml_iarchive; }; }; class _LIBSPEC MyClass { public: MyClass(); private: friend class boost::serialization::access; template <class Archive> void serialize(Archive & ar, const unsigned int version); std::string m_str; }; _EXPORT_TEMPLATE void MyClass::serializeboost::archive::xml_oarchive(boost::archive::xml_oarchive& ar, const unsigned int version); _EXPORT_TEMPLATE void MyClass::serializeboost::archive::xml_iarchive(boost::archive::xml_iarchive& ar, const unsigned int version); anyway, thanks your your help and your prompt reply. Cyril Picat -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Robert Ramey Sent: Thursday, May 29, 2008 1:20 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] [Serialization] Serialization of a class in a DLL In order for this to work, you have to explicitly instantiate the code in the library/dll. It will not be instantiated automatically as it is not called from within the library. For an example of this take a look at demo_pimple Robert Ramey Cyril Picat wrote:
Hi everybody,
I have just tried a simple example of a class serialization in a DLL and did not manage to make it work. I have been using Boost serialization since a while but until now I was putting all the serialization code in the .hpp. By the way thanks Robert (and Boost) for this great library.
I am using MSVC 8.0 and Boost 1.34.1. I have tried the same with Boost Serialization 1.36 (head of Boost) without any success.
My test is the following. The class MyClass in declared in a DLL boost-example.dll built from Example.cpp. A test program Example.t.cpp linked with boost-example.dll try to serialize MyClass to an XML archive.
The files are the following:
//////// Example.hpp #if _MSC_VER > 1000 #pragma once #endif
// Do NOT include any headers after this point #if (defined(__COMPILING_Example_CPP__) && defined(WIN32)) #define _LIBSPEC __declspec(dllexport) #else #define _LIBSPEC #endif
class _LIBSPEC MyClass { public: MyClass();
private: friend class boost::serialization::access;
template <class Archive> void serialize(Archive & ar, const unsigned int version);
std::string m_str;
};
// add the folloing here
#include
Cyril Picat wrote:
Ok, I thought that BOOST_CLASS_EXPORT will take care of instantiating it.
It is not know when the library is built for which archive classes it should be instantiated - unless you include the archive headers and use explicit instantiation. Actually isn't it what is explained in the doc in paragraph
'Exporting Class Serialization'? I am a bit confused and sure I should dive into the Boost.Serialization code to understand more what the macro is doing.
I'm not sure which version you're using. The version in the trunk has updated information on BOOST_CLASS_EXPORT which tries to be more clear about this confusing topic.
The problem with your solution is that I don't want to include any Boost header in Example.hpp.
Hmm - if you want to specify a member function serialize - Its not unreasonable to have to include the boost head which declares its arguments.
So I have tried the solution from demo_pimpl but it still fail to link with vc 8.0 (there is a comment saying that it fails with vc 7.0)? Is it expected?
I think it passes with vc 7.1 - as far as I know the example is correct. A deeper investigation of this might resolve the confusion.
So I have ended with forward declaring the archives I need in Example.hpp and it works.
Though, I would rather but the explicit template instantiation in Example.cpp to keep a clean implementation agnostic header. Is there any way to make this work with VC ?
Here's what I thnk you want to do: a) make your serialize functions - include boost serialization headers b) make a module in your library which includes the archive headers or ALL the archives you might want to use. c) explicitly instantiate all your serializaiton functions for these archives Then you main program should link with no problem. It will compile faster and include only that code actually used. The same solution works for serialization code in DLLS. Robert Ramey
participants (3)
-
Cyril Picat
-
Emil Dotchevski
-
Robert Ramey