From e4eeff27983f534c07793ac57e989072374b3522 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 3 Dec 2017 23:32:21 +0100 Subject: [PATCH] Detect BOOST bug while configuring --- cmake/configure/TestBoostBug/CMakeLists.txt | 22 +++++ .../TestBoostBug/polymorphic_base.hpp | 38 +++++++ .../TestBoostBug/polymorphic_derived2.cpp | 47 +++++++++ .../TestBoostBug/polymorphic_derived2.hpp | 42 ++++++++ .../TestBoostBug/test_dll_exported.cpp | 98 +++++++++++++++++++ cmake/configure/TestBoostBug/text_archive.hpp | 13 +++ cmake/configure/configure_boost.cmake | 48 +++++++++ 7 files changed, 308 insertions(+) create mode 100644 cmake/configure/TestBoostBug/CMakeLists.txt create mode 100644 cmake/configure/TestBoostBug/polymorphic_base.hpp create mode 100644 cmake/configure/TestBoostBug/polymorphic_derived2.cpp create mode 100644 cmake/configure/TestBoostBug/polymorphic_derived2.hpp create mode 100644 cmake/configure/TestBoostBug/test_dll_exported.cpp create mode 100644 cmake/configure/TestBoostBug/text_archive.hpp diff --git a/cmake/configure/TestBoostBug/CMakeLists.txt b/cmake/configure/TestBoostBug/CMakeLists.txt new file mode 100644 index 0000000000..a57ad6432c --- /dev/null +++ b/cmake/configure/TestBoostBug/CMakeLists.txt @@ -0,0 +1,22 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) +PROJECT(TestBoost) + +SET(BOOST_INCLUDE_DIRS CACHE STRING "The include paths for BOOST") +SET(BOOST_LIBRARIES CACHE STRING "The BOOST libraries to use") + +# We assume the BOOST_LIBRARIES to be separated by '|' +# This matches the change in the separator we do in +# ../configure_boost.cmake +STRING(REPLACE "|" ";" BOOST_LIBRARIES_SEPARATED ${BOOST_LIBRARIES}) +INCLUDE_DIRECTORIES(${BOOST_INCLUDE_DIRS}) + +ADD_LIBRARY(derived SHARED polymorphic_derived2.cpp) +ADD_EXECUTABLE(test_boost test_dll_exported.cpp) + +TARGET_LINK_LIBRARIES(derived ${BOOST_LIBRARIES_SEPARATED}) +TARGET_LINK_LIBRARIES(test_boost derived ${BOOST_LIBRARIES_SEPARATED}) + +ADD_CUSTOM_TARGET(run + COMMAND test_boost + DEPENDS test_boost + WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}) diff --git a/cmake/configure/TestBoostBug/polymorphic_base.hpp b/cmake/configure/TestBoostBug/polymorphic_base.hpp new file mode 100644 index 0000000000..7da4d43abd --- /dev/null +++ b/cmake/configure/TestBoostBug/polymorphic_base.hpp @@ -0,0 +1,38 @@ +#ifndef POLYMORPHIC_BASE_HPP +#define POLYMORPHIC_BASE_HPP + +#include + +#include +#include +#include +#include +#include + +class BOOST_SYMBOL_VISIBLE polymorphic_base +{ + friend class boost::serialization::access; + template + void serialize( + Archive & /* ar */, + const unsigned int /* file_version */ + ){} +public: + // note that since this class uses the "no_rtti" + // extended_type_info implementation, it MUST + // implement this function + virtual const char * get_key() const = 0; + virtual ~polymorphic_base(){}; +}; + +BOOST_SERIALIZATION_ASSUME_ABSTRACT(polymorphic_base) + +// the no_rtti system requires this !!! +BOOST_CLASS_EXPORT_KEY(polymorphic_base) + +BOOST_CLASS_TYPE_INFO( + polymorphic_base, + boost::serialization::extended_type_info_no_rtti +) + +#endif // POLYMORPHIC_BASE_HPP diff --git a/cmake/configure/TestBoostBug/polymorphic_derived2.cpp b/cmake/configure/TestBoostBug/polymorphic_derived2.cpp new file mode 100644 index 0000000000..2e445d464c --- /dev/null +++ b/cmake/configure/TestBoostBug/polymorphic_derived2.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +#include "polymorphic_derived2.hpp" + +template +void polymorphic_derived2::serialize( + Archive &ar, + const unsigned int /* file_version */ +){ + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(polymorphic_base); +} + +// instantiate code for text archives +#include +#include + +template +void polymorphic_derived2::serialize( + boost::archive::text_oarchive & ar, + const unsigned int version +); +template +void polymorphic_derived2::serialize( + boost::archive::text_iarchive & ar, + const unsigned int version +); + +// instantiate code for polymorphic archives +#include +#include + +template +void polymorphic_derived2::serialize( + boost::archive::polymorphic_oarchive & ar, + const unsigned int version +); +template +/*POLYMORPHIC_DERIVED2_DLL_DECL*/ +void polymorphic_derived2::serialize( + boost::archive::polymorphic_iarchive & ar, + const unsigned int version +); + +// note: export has to be AFTER #includes for all archive classes +BOOST_CLASS_EXPORT_IMPLEMENT(polymorphic_derived2) \ No newline at end of file diff --git a/cmake/configure/TestBoostBug/polymorphic_derived2.hpp b/cmake/configure/TestBoostBug/polymorphic_derived2.hpp new file mode 100644 index 0000000000..078c4fb573 --- /dev/null +++ b/cmake/configure/TestBoostBug/polymorphic_derived2.hpp @@ -0,0 +1,42 @@ +#ifndef POLYMORPHIC_DERIVED2_HPP +#define POLYMORPHIC_DERIVED2_HPP + +#include + +#include +#include +#include +#include +#include + +#include "polymorphic_base.hpp" + +class polymorphic_derived2 : + public polymorphic_base +{ + friend class boost::serialization::access; + template + void serialize( + Archive &ar, + const unsigned int /* file_version */ + ); + virtual const char * get_key() const { + return "polymorphic_derived2"; + } +}; + +// we use this because we want to assign a key to this type +// but we don't want to explicitly instantiate code every time +// we do so!!!. If we don't do this, we end up with the same +// code in BOTH the DLL which implements polymorphic_derived2 +// as well as the main program. +BOOST_CLASS_EXPORT_KEY(polymorphic_derived2) + +// note the mixing of type_info systems is supported. +BOOST_CLASS_TYPE_INFO( + polymorphic_derived2, + boost::serialization::extended_type_info_typeid +) + +#endif // POLYMORPHIC_DERIVED2_HPP + diff --git a/cmake/configure/TestBoostBug/test_dll_exported.cpp b/cmake/configure/TestBoostBug/test_dll_exported.cpp new file mode 100644 index 0000000000..91ff59a35d --- /dev/null +++ b/cmake/configure/TestBoostBug/test_dll_exported.cpp @@ -0,0 +1,98 @@ +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 +// test_dll_exported.cpp + +// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// should pass compilation and execution + +// This is an overly complex test. The purpose of this test is to +// demostrate and test the ability to serialize a hiarchy of class +// through a base class pointer even though those class might be +// implemente in different dlls and use different extended type info +// systems. +// +// polymorphic_ base is locally declared and defined. It use the +// "no_rtti" extended type info system. + +// polymorphic_derived1 is locally declared and defined. It uses +// the default "type_id" extended type info system + +// polymorphic_derived2 is declared in polymorphic_derived.hpp +// and defined in dll_polymorphic_derived2. It uses the typeid +// system. + +#include // NULL +#include + +#include + +#include + +#include +#include + +#include +#include + +#include "polymorphic_base.hpp" + +#include "polymorphic_derived2.hpp" + +// save exported polymorphic class +void save_exported(const char *testfile) +{ + std::ofstream os(testfile); + boost::archive::text_oarchive oa(os); + + polymorphic_base *rb2 = new polymorphic_derived2; + polymorphic_derived2 *rd21 = new polymorphic_derived2; + + // export will permit correct serialization + // through a pointer to a base class + oa << BOOST_SERIALIZATION_NVP(rb2); + oa << BOOST_SERIALIZATION_NVP(rd21); + + delete rb2; + delete rd21; +} + +// save exported polymorphic class +void load_exported(const char *testfile) +{ + std::ifstream is(testfile); + boost::archive::text_iarchive ia(is); + + polymorphic_base *rb2 = NULL; + polymorphic_derived2 *rd21 = NULL; + + // export will permit correct serialization + // through a pointer to a base class + ia >> BOOST_SERIALIZATION_NVP(rb2); + assert( + boost::serialization::type_info_implementation + ::type::get_const_instance() + == + * boost::serialization::type_info_implementation + ::type::get_const_instance().get_derived_extended_type_info(*rb2)); + ia >> BOOST_SERIALIZATION_NVP(rd21); + assert( + boost::serialization::type_info_implementation + ::type::get_const_instance() + == + * boost::serialization::type_info_implementation + ::type::get_const_instance().get_derived_extended_type_info(*rd21)); + delete rb2; + delete rd21; +} + +int main( int /* argc */, char* /* argv */[] ) +{ + save_exported("testfile"); + load_exported("testfile"); + return EXIT_SUCCESS; +} + +// EOF diff --git a/cmake/configure/TestBoostBug/text_archive.hpp b/cmake/configure/TestBoostBug/text_archive.hpp new file mode 100644 index 0000000000..65425ce5a1 --- /dev/null +++ b/cmake/configure/TestBoostBug/text_archive.hpp @@ -0,0 +1,13 @@ +// (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com . +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. +// text_archive +#include +typedef boost::archive::text_oarchive test_oarchive; +typedef std::ofstream test_ostream; +#include +typedef boost::archive::text_iarchive test_iarchive; +typedef std::ifstream test_istream; diff --git a/cmake/configure/configure_boost.cmake b/cmake/configure/configure_boost.cmake index 47b18cae81..e44393031e 100644 --- a/cmake/configure/configure_boost.cmake +++ b/cmake/configure/configure_boost.cmake @@ -136,6 +136,54 @@ MACRO(FEATURE_BOOST_FIND_EXTERNAL var) RESET_CMAKE_REQUIRED() ENDIF() + IF(${var}) + # We want to pass the libraries to the CMake project that tests for the + # BOOST Serialization bug. If we don't change the separator, only the + # first one is passed. This change in the separator is reverted in + # TestBoostBug/CMakeLists.txt + STRING (REPLACE ";" "|" BOOST_LIBRARIES_SEPARATED "${BOOST_LIBRARIES}") + + FILE(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/cmake/configure/TestBoostBug) + FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake/configure/TestBoostBug) + EXECUTE_PROCESS( + COMMAND ${CMAKE_COMMAND} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DBOOST_INCLUDE_DIRS=${BOOST_INCLUDE_DIRS} + -DBOOST_LIBRARIES=${BOOST_LIBRARIES_SEPARATED} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/configure/TestBoostBug + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake/configure/TestBoostBug + RESULT_VARIABLE _boost_serialization_usuable + OUTPUT_QUIET + ERROR_QUIET + ) + IF(${_boost_serialization_usuable} EQUAL 0) + EXECUTE_PROCESS( + COMMAND ${CMAKE_COMMAND} --build . --target run + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake/configure/TestBoostBug + RESULT_VARIABLE _boost_serialization_usuable + OUTPUT_QUIET + ERROR_QUIET + ) + ENDIF() + + IF(${_boost_serialization_usuable} EQUAL 0) + MESSAGE(STATUS "Boost.Serialization is usuable.") + ELSE() + MESSAGE(STATUS + "The externally provided Boost.Serialization library " + "failed to pass a crucial test. \n" + "Therefore, the bundled boost package is used. \n" + "The configured testing project can be found at " + "${CMAKE_CURRENT_BINARY_DIR}/cmake/configure/TestBoostBug" + ) + SET(BOOST_ADDITIONAL_ERROR_STRING + "The externally provided Boost.Serialization library " + "failed to pass a crucial test." + ) + SET(${var} FALSE) + ENDIF() + ENDIF() ENDIF() ENDMACRO() -- 2.39.5