
Martin Ecker wrote:
Is there work under way to fix this and have working DLL builds of boost::serialization (just as there are DLL builds for, say, boost::regex)?
I have interest in addressing this. I do believe it is addressable without too much difficulty but will require some extra care. There also might be some restrictions on usage - I don't know yet.
I looked into this some more and I believe to have found somewhat of a solution (albeit a "hacky" one) for the template classes derived from extended_type_info. If you don't mind I will send you my current boost::serialization code base via private e-mail and you could maybe have a look at it. As I wrote above, I do not yet know enough about the internal structure of the library, so I can't say for sure if my changes broke anything major. In the limited tests I did with the demo samples that come with the library everything seemed to work fine though.
OK
One thing that I have not yet addressed though is the need for extended type info objects to unregister themselves from the global registry. This is important when DLLs are loaded, unloaded, and then loaded again. I believe this should be quite easy to implement. Simply make a call to some unregister function in the extended_type_info destructor, similar to the self_register call in the constructor.
I have yet to consider the issues related to dynamic loading/unloading of DLLS. The current system registers things at pre-execution time. I'm not sure what that means when the object to be registered via construction of a static object located in a DLL loaded at a subsequent time.
This actually brings me to another question: Why is the self_register call not directly in the base class constructor, i.e. in extended_type_info::extended_type_info, but rather in the deriving classes?
No particular reason as far as I can see.
My intention was the BOOST_CLASS_EXPORT be included in the header file.
I don't quite understand how this can work reliably. Say, I have two DLLs. In one DLL I have class A. A's header file also contains the BOOST_CLASS_EXPORT(A) macro. Now a second DLL also needs to use this class. Therefore it will include A's header file. This will result in a static guid_initializer instance to be created in both DLLs, which is unnecessary.
Note that a new static variable instance should created for each archive included. If no archives are included, then the header with BOOST_CLASS_EXPORT can be included anywhere any number of times. The actual restriction should be that it be included only once for a given archive class. Looking at the code now, I see that its also creating an extended_type_info instance as well and this will lead to problems with multiply defined static instances. I believe this can be enhanced to skip this step of no archives are being included. That doesn't quite do it but it points the way to improving this.
Also with the current code it will cause the class' extended type info to be registered twice, once in each DLL with a different extended type info object each time. I believe my code modifications will remedy this though, so it wouldn't matter if the registration happened multiple times, but it is still unnecessary. The only "proper" way I know of to avoid this is to always use the export macros in .cpp files.
I'm coming to this conclusion as well.
This would mean code modules would be organized similar to the demo_pimpl example where the implementation of class serialization (invocations of ar << my_class_instance) are in separate modules from the headers rather than inline functions.
I've looked at that sample, but since we are trying to integrate boost::serialization into an existing project, reorganizing all of our code is pretty much out of the question. We tend to have the serialization code inlined in the header files of the class it belongs to. This has so far proven to be good for maintenance of the code as well (e.g. when a new member variable is added to a class it is harder to forget to also change the serialization code, if necessary).
I think it's a mistake to dismiss this idea. I appreciate the ease of maintenance but in the type of project your working with I think it would be best to: a) refrain from defining serialize inline in the header file. b) implement serialize() in the my_class.cpp file for each class. c) include BOOST_CLASS_EXPORT in each my_class.cpp file d) instanciate the templates in the class *.cpp file for archive classes you expect to support. Only the my_class.cpp will included archive class headers. I believe it is common practice is to have an *.hpp file and a *.cpp file for each non-trivial class. So I would be surprised to find that much code reorganization would be required to implement this. I also believe that to reliably support libraries and DLLs of exported classes, such an organization will be required. It will also result in much smaller code with almost no loss of speed. If the code is compiled to a static library, the executable won't contain any "dead" code. If compiled to a DLL, the code won't have to be loaded unless it is actually used. Note that this organization will be required only for those class types which are serialized through pointers to derived classes. So it may not be as much as a burden as it might seem. Robert Ramey