Search code examples
c++boostboost-serializationheader-only

Is it possible to use Boost serialization as a header only library?


Below is a minimal example to use the great Boost.Serialization library.

To compile the library I need to link with the boost_serialization precompiled library.

$ c++ -std=c++11 example.cpp -o example.x -lboost_serialization
                                          ^^^^^^^^^^^^^^^^^^^^^

The library is heavily templated an although complicated internally the actual code (function body) is quite simple. There are only a few references that need the linking, namely:

boost::archive::text_oarchive_impl<boost::archive::text_oarchive>::text_oarchive_impl(std::ostream&, unsigned int)
boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::text_iarchive_impl(std::istream&, unsigned int)
boost::archive::text_iarchive_impl<boost::archive::text_oarchive>::~text_oarchive_impl()
boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::~text_iarchive_impl()
...
boost::archive::archive_exception::~archive_exception()'

Is there a chance that the library can be used without linking as a header-only library?

For example some undocumented trick or hack?

That would make it more simple to use in some supercomputer clusters and environments where it is not that simply to compile Boost.

#include<sstream>
#include<numeric>
#include<boost/archive/text_oarchive.hpp> // needs linking 
#include<boost/archive/text_iarchive.hpp>
#include<boost/serialization/vector.hpp>

int main(){

    std::vector<double> v(10); std::iota(v.begin(), v.end(), 0);
    std::stringstream ss;
    {
        boost::archive::text_oarchive toa(ss);
        toa << v;
    }
    std::vector<double> v2;
    boost::archive::text_iarchive tia(ss);
    tia >> v2;
    assert(v == v2);
}

EDIT: I would be very cool if the library gave the option to be header only, like Boost.Asio does (https://stackoverflow.com/a/40729439/225186.)


EDIT2: The author and maintainer of Boost.Serialization rejected the idea of making it header only. https://github.com/boostorg/serialization/issues/71


Solution

  • I ended up including the cpp sources from a certain version of Boost Serialization. I chose the cpp files by trial and error.

    https://gitlab.com/correaa/boost-mpi3/-/tree/master/include/mpi3/serialization_hack

    serialiation_hack

    Basically, I include these cpp files from the same place I would include the Serialization hpp files.

    #include <boost/archive/detail/common_iarchive.hpp>
    #include <boost/archive/detail/common_oarchive.hpp>
    
    #include <boost/archive/archive_exception.hpp>
    #include <boost/archive/basic_streambuf_locale_saver.hpp>
    #include <boost/archive/detail/auto_link_archive.hpp>
    //#include <boost/archive/detail/abi_prefix.hpp> // must be the last header
    
    #include <boost/serialization/array.hpp>
    #include <boost/serialization/is_bitwise_serializable.hpp>
    #include <boost/serialization/item_version_type.hpp>
    #include <boost/serialization/string.hpp>
    
    #include <boost/mpl/placeholders.hpp>
    
    #include <any>
    #include <optional>
    
    // use this to avoid need for linking -lserialization
    #ifdef _MAKE_BOOST_SERIALIZATION_HEADER_ONLY
    //#include <boost/archive/detail/decl.hpp>
    #if BOOST_VERSION > 106000 && BOOST_VERSION < 106600
    #include "../mpi3/serialization_hack/singleton.cpp"
    #endif
    #if BOOST_VERSION < 105900
    #define BOOST_ARCHIVE_DECL
    #define BOOST_SERIALIZATION_DECL
    #endif
    // NOLINTBEGIN(hicpp-use-auto,modernize-use-auto)  external code
    #include "../mpi3/serialization_hack/archive_exception.cpp"  // NOLINT(bugprone-suspicious-include) hack
    #include "../mpi3/serialization_hack/basic_archive.cpp"  // NOLINT(bugprone-suspicious-include) hack
    #include "../mpi3/serialization_hack/basic_iarchive.cpp"  // NOLINT(bugprone-suspicious-include) hack
    #include "../mpi3/serialization_hack/basic_iserializer.cpp"  // NOLINT(bugprone-suspicious-include) hack
    #include "../mpi3/serialization_hack/basic_oarchive.cpp"  // NOLINT(bugprone-suspicious-include) hack
    #include "../mpi3/serialization_hack/basic_oserializer.cpp"  // NOLINT(bugprone-suspicious-include) hack
    #include "../mpi3/serialization_hack/extended_type_info.cpp"  // NOLINT(bugprone-suspicious-include) hack
    #include "../mpi3/serialization_hack/extended_type_info_typeid.cpp"  // NOLINT(bugprone-suspicious-include) hack
    // NOLINTEND(hicpp-use-auto,modernize-use-auto)
    
    

    A problem with this approach is that I had to modify the sources to accommodate different versions of Boost.Serialization and also had to do some modification to appease compiler warnings and static analyzers.