diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd6336386..6a95a6ee1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -243,7 +243,15 @@ jobs: run: | cd ../boost-root export ADDRMD=${{matrix.address-model}} - ./b2 -j3 libs/$LIBRARY/test libs/$LIBRARY/example toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} variant=debug,release + ./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} variant=debug,release + + - name: Run examples + run: | + cd ../boost-root + export ADDRMD=${{matrix.address-model}} + # The demos use fixed temp filenames, so run them serially (-j1) + # to avoid concurrent runs clobbering each other's archive files. + ./b2 -j1 libs/$LIBRARY/example toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} variant=debug,release windows: strategy: @@ -298,7 +306,15 @@ jobs: shell: cmd run: | cd ../boost-root - b2 -j3 libs/%LIBRARY%/test libs/%LIBRARY%/example toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker + b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker + + - name: Run examples + shell: cmd + run: | + cd ../boost-root + rem The demos use fixed temp filenames, so run them serially (-j1) + rem to avoid concurrent runs clobbering each other's archive files. + b2 -j1 libs/%LIBRARY%/example toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker posix-cmake-subdir: strategy: diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index b3c01f14c..2a5545bf9 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -11,6 +11,8 @@ project libs/serialization/example : requirements ../build//boost_serialization ; +import testing ; + import ../util/test : run-template run-invoke diff --git a/include/boost/serialization/filesystem.hpp b/include/boost/serialization/filesystem.hpp index 2aab1b10d..379d99032 100644 --- a/include/boost/serialization/filesystem.hpp +++ b/include/boost/serialization/filesystem.hpp @@ -18,8 +18,12 @@ #include +// GCC's before version 9 is the initial, incomplete +// implementation (shipped in a separate libstdc++fs and buggy at runtime), +// so the feature is disabled there. #if defined(__has_include) -# if __has_include() && (BOOST_CXX_VERSION >= 201703L) +# if __has_include() && (BOOST_CXX_VERSION >= 201703L) \ + && ! (defined(__GNUC__) && ! defined(__clang__) && __GNUC__ < 9) # define BOOST_SERIALIZATION_HAS_STD_FILESYSTEM # endif #endif diff --git a/test/test_filesystem_path.cpp b/test/test_filesystem_path.cpp index 1a14dd916..71bd0e51b 100644 --- a/test/test_filesystem_path.cpp +++ b/test/test_filesystem_path.cpp @@ -17,8 +17,11 @@ // `std::filesystem::path` is a C++17 feature; when it isn't available, this // test has nothing to exercise and simply succeeds. +// Note the guard for GCC < 9, which matches the one in +// boost/serialization/filesystem.hpp: see the comment there for the why. #if defined(__has_include) -# if __has_include() && (BOOST_CXX_VERSION >= 201703L) +# if __has_include() && (BOOST_CXX_VERSION >= 201703L) \ + && ! (defined(__GNUC__) && ! defined(__clang__) && __GNUC__ < 9) # define BOOST_SERIALIZATION_TEST_STD_FILESYSTEM # endif #endif @@ -29,6 +32,11 @@ #include #include +#include + +#ifndef BOOST_NO_STD_WSTREAMBUF +#include +#endif void check_roundtrip(const std::filesystem::path & original){ const char * testfile = boost::archive::tmpnam(NULL); @@ -57,6 +65,21 @@ std::filesystem::path from_utf8(const std::string & utf8){ #endif } +// The wide *text* archive is the one archive that cannot round-trip non-ASCII +// content: it transcodes the narrow UTF-8 std::string through the stream +// locale's codecvt (codecvt_null), which mangles bytes outside the ASCII +// range. Every other archive in the test list preserves them -- narrow text +// and XML store the bytes verbatim, binary stores them raw, and wide XML +// installs a UTF-8 codecvt. So the non-ASCII case is exercised everywhere +// except that single archive. +bool archive_round_trips_non_ascii(){ +#ifndef BOOST_NO_STD_WSTREAMBUF + return ! std::is_same::value; +#else + return true; +#endif +} + int test_main(int /* argc */, char * /* argv */ []){ check_roundtrip(std::filesystem::path()); // empty check_roundtrip("foo/bar/baz.txt"); // relative @@ -66,7 +89,8 @@ int test_main(int /* argc */, char * /* argv */ []){ // The escapes are the UTF-8 encoding of U+00E9, U+00EF and U+00FC // (e-acute, i-diaeresis, u-diaeresis); written as `\x` so the source // file stays pure ASCII and encoding-independent. - check_roundtrip(from_utf8("caf\xC3\xA9/na\xC3\xAF" "ve/\xC3\xBC.txt")); + if(archive_round_trips_non_ascii()) + check_roundtrip(from_utf8("caf\xC3\xA9/na\xC3\xAF" "ve/\xC3\xBC.txt")); return EXIT_SUCCESS; }