Skip to content

Build streams.h without std::char_traits<uint8_t> - #27

Merged
garethsb merged 3 commits into
nmos-cppfrom
bugfix/libcxx-char-traits
Nov 4, 2026
Merged

garethsb merged 3 commits into
nmos-cppfrom
bugfix/libcxx-char-traits

Conversation

@garethsb

@garethsb garethsb commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

The standard only defines std::char_traits for the character types. libc++ 19 removed the generic std::char_traits template, so std::basic_string<uint8_t> no longer compiles. cpprest/streams.h used it in Value2StringFormatter<uint8_t>. As a result, every file that includes that header failed to compile with libc++ 19 or later. That includes the default Xcode on macOS since Xcode 16.3, and Clang with -stdlib=libc++ elsewhere.

This change avoids std::basic_string<uint8_t> rather than defining character traits for uint8_t:

  • Value2StringFormatter<uint8_t> returns the formatted bytes as a std::string, and basic_ostream writes any formatted string through a private helper.
  • The basic_ostream::print overload for strings is now a template on the traits and allocator. Calling print on a basic_ostream<uint8_t> therefore no longer instantiates std::basic_string<uint8_t> during overload resolution. For char and wchar_t streams, partial ordering still selects this overload for strings, as before.
  • Printing to a basic_ostream<uint8_t> no longer stops at an embedded NUL byte, because the bytes are no longer copied through c_str().
  • In the stream buffer tests, std::vector replaces std::basic_string for the data to write. One test used rawptr_buffer<std::string> where it meant rawptr_buffer<char>.

The second commit adds macOS jobs to CI, on the macos-15 (Xcode 16.4) and macos-26 (Xcode 26.6) runners, with Homebrew's Boost and OpenSSL. They exclude websockets, because Homebrew's websocketpp is 0.8.2, which does not build with Boost 1.87 or later.

Tested locally:

  • Ubuntu 26.04, Clang 21 with libc++ 21: before the change, 94 files fail to compile. After it, the whole tree builds. The tests cannot run in that container, because Ubuntu's Boost is built against libstdc++ and the test runner uses boost::filesystem to find the test libraries. The macOS jobs run the tests.
  • Ubuntu 24.04, GCC 13 with AddressSanitizer: all 237 streams tests pass, as do the json, utils, uri, pplx and listener tests.
  • Windows, MSVC 14.50, Debug: all 270 streams tests pass.

Fixes #11.

The same problem is reported upstream in microsoft#1812. microsoft#1829 fixes it with a separate traits class for uint8_t, and Homebrew and FreeBSD apply that change as patches. This change is smaller and does not need a traits class.

Co-authored-by: Gareth's 🤖 buddy

The standard only defines std::char_traits for the character types.
libc++ 19 removed the generic std::char_traits template, so
std::basic_string<uint8_t> no longer compiles. streams.h used it in
Value2StringFormatter<uint8_t>, which made every file that includes
cpprest/streams.h fail to compile with libc++ 19 or later, including
with Xcode 16.3 or later on macOS.

Make Value2StringFormatter<uint8_t> return the formatted bytes as a
std::string, and have basic_ostream write any formatted string through
a private helper. Make the basic_ostream::print overload for strings a
template on the traits and allocator, so that calling print on a
basic_ostream<uint8_t> does not instantiate std::basic_string<uint8_t>.
Printing to a basic_ostream<uint8_t> also no longer stops at an
embedded NUL byte.

In the stream buffer tests, use std::vector instead of
std::basic_string for the data to write, and use rawptr_buffer<char>
where a test used rawptr_buffer<std::string>.

Fixes #11.

Signed-off-by: Gareth Sylvester-Bradley <garethsb@nvidia.com>
Build with the default Xcode on the macos-15 and macos-26 runners,
whose libc++ does not define std::char_traits for types other than the
character types. Use Homebrew's Boost and OpenSSL, and exclude
websockets, because Homebrew's websocketpp is 0.8.2, which does not
build with Boost 1.87 or later.

Signed-off-by: Gareth Sylvester-Bradley <garethsb@nvidia.com>
@garethsb
garethsb force-pushed the bugfix/libcxx-char-traits branch from 2918fcc to 2f3c33d Compare November 4, 2026 16:34
GitHub warns that "Due to capacity constraints, jobs targeting macOS
arm64 runners may experience longer queue times", and cancelled every
macOS job in one run because no runner picked it up. Build Release on
macos-15 and Debug on macos-26, rather than both build types on both
runners, so that each change waits for fewer macOS runners.

Signed-off-by: Gareth Sylvester-Bradley <garethsb@nvidia.com>
@garethsb
garethsb merged commit d8e0505 into nmos-cpp Nov 4, 2026
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build fails with libc++ 19 and later: std::basic_string<uint8_t> in streams.h

1 participant