Preview of main at d0a501a, 2026-11-07

webcpp brings to C++ the libraries that other languages use for the web. Each is a header-only C++20 library, a port of a widely used original at an exact version or a library of webcpp’s own, built and tested with b2, natively and for WebAssembly, and documented on a page of its own, with its API reference. webcpp follows Boost’s guidelines and model; its source is at webcpporg/webcpp.

Libraries

Each library’s name leads to its page: the guide that teaches it, its guarantees, its API reference and how it is tested.

Library Description Ports

asio

Boost.Asio for native, browser and WASIp2/P3 targets, with explicit platform capabilities and shipped Wasm implementations.

original

beast

Beast-compatible HTTP and WebSocket interfaces for WebAssembly and native applications.

original

cobalt

Boost.Cobalt coroutine applications on native, browser and WASI targets.

original

config

webcpp’s configuration, which every webcpp library includes first: the target a program is built for, whether webcpp has exceptions, and webcpp’s version.

original

document

A JSON document for C++20 that behaves as JavaScript does, in one relocatable image.

original

idna

IDNA2008 and UTS 46 for C++20: Punycode, ToASCII and ToUnicode, and label validity, over generated Unicode 17.0 tables.

original

lexical

Validators and Boost.URL grammar rules for the string formats of JSON Schema, for C++20.

original

pratt

A generic Pratt parser engine for C++20, with a decimal calculator built on it.

original

trystero

Serverless WebRTC rooms for C++20, wire compatible with Trystero.

Trystero 0.26.0, in JavaScript (MIT)

wasi

Header-only helpers for C++ built as WebAssembly components: the HTTP handler a component exports on wasip2 and wasip3, and the macros a program writes its main between.

original

xactor

A header-only, deterministic actor system: actors that handle one message at a time, with fuel per execution, timers and a lifecycle.

original

xstate

A header-only port of XState’s state machines and actors: machines read from XState’s JSON config, stepped by XState’s pure functions or run as actors on xactor.

XState 5.33.2, in TypeScript (MIT)

Test matrix

Every library is tested on every target it declares, natively and for WebAssembly: on wasm32-wasip2 and wasm32-wasip3 with wasmtime, and with Emscripten, whose programs node runs. The test matrix shows each test and example of each library by lane, with the log of every failure.

Getting started

With Boost 1.92 or newer and b2 installed, a checkout of the superproject builds and tests every library. trystero needs three libraries that webcpp does not build yet, which its page says how to install: without them, b2 test builds and tests every other library and leaves trystero out, saying so once for each library it did not find:

git clone --recursive https://github.com/webcpporg/webcpp
cd webcpp
b2 test

A b2 project uses a library through /webcpp/<name>//<name>; CMake or a plain compiler uses the headers that b2 install --prefix=<dir> copies to <dir>/include/webcpp/. The README lists the prerequisites and how to configure them, CODING-GUIDELINES.md holds the rules for porting a library to webcpp and the decisions of its design, and AGENTS.md says how to work in the tree.

Releases

The release notes of each version of webcpp, newest first: what came into the collection, what changed in each library, and what went out.

webcpp 0.1.0

New Libraries

  • asio: Boost.Asio with browser event-loop suspension, WASIp2/P3 networking and optional source-built TLS, from R.

  • beast: HTTP messages and WebSocket applications for native, WASI and browser targets, with socket transports, browser WebSocket and fetch, WASI host HTTP and supplied byte streams, from R.

  • cobalt: Boost.Cobalt coroutine applications for native, browser and WASI targets, with explicit source distribution and optional corrected SSL integration, from R.

  • config: webcpp’s configuration, which every library includes first: the target, exceptions and the version, from R.

  • document: a header-only JSON document for C++20 that behaves as JavaScript does, exact in decimal, in one relocatable binary image, with a JavaScript module, from R.

  • idna: a header-only library of internationalized domain names for C++20: Punycode, UTS 46 and IDNA2008 validity over Unicode 17.0.0 tables, from R.

  • lexical: header-only validators of JSON Schema’s string formats for C++20, allocating nothing, each also a Boost.URL grammar rule, from R.

  • pratt: a header-only Pratt-parsing engine for C++20, with a decimal calculator built on it, from R.

  • trystero: a port of Trystero 0.26.0, serverless WebRTC rooms wire-compatible with the original, for C++20, from R.

  • wasi: a header-only HTTP handler for C++20 programs built as WebAssembly components, covering WASI 0.2 and WASI 0.3, from R.

  • xactor: a header-only, deterministic actor system for C++20, from R.

  • xstate: a header-only port of XState’s state machines and actors for C++20, from R.

Updated Libraries

None.

Removed Libraries

None.

Tools and build

  • Fixed clean CMake consumer audits rejecting system libraries and phony dependency rules.

  • Changed CI to consume verified prepared environments without rebuilding images in PR jobs.

  • Added verified archive caches and isolated container availability from unrelated CI lanes.

  • Fixed parallel builds truncating OpenSSL headers while compilers read them.

  • Fixed driven-test execution and descendant cleanup on Windows.

  • Fixed driven-test executable reuse for Windows and WASI builds.

  • Improved lint preparation by separating OpenSSL headers from archive builds and upstream tests.

  • Fixed the WASIp2 test launcher interrupting large finite workloads after 60 seconds.

  • Fixed Chrome provisioning and browser/TLS profile coverage in Asio CI lanes.

  • Added source-built OpenSSL and Cobalt SSL targets for WASIp2.

  • Added explicit browser pthread profiles with main-thread handoff tests.

  • Changed lint to verify WASIp3 ABI snapshots before excluding upstream headers.

  • Fixed embedded CA headers using an unowned namespace and include path.

  • Added source-built Boost.Context for native stackful coroutine applications.

  • Added negative link tests and explicit reference-source build discovery.

  • Added hash-verified Beast application inputs and browser CI dependencies.

  • Added isolated CA trust tests with pinned full Chrome and a Wasmtime host fixture.

  • Fixed duplicate source paths selecting conflicting targets in the lint database.

  • Updated Wasmtime to 50.0.1 for every library’s WASI targets.

  • Fixed WASIp3 network tests lacking the required runtime capabilities.

  • Fixed OpenSSL source builds with symlinked compilers and Windows checkouts.

  • Fixed serial Windows OpenSSL builds exhausting the parallel-build time budget.

  • Added native MSVC OpenSSL build recipes with B2 runtime settings.

  • Fixed Cobalt lint builds requiring pre-existing generated Boost overlays.

  • Fixed source distributions rejecting pinned site and third-party dependencies.

  • Changed release checks to accept the tested compiler subset.

  • Added agent skills with validated metadata for common contributor workflows.

  • Breaking change: changed wasip2 programs to build with exceptions, as wasip3 does; whether a program uses them is its developer’s choice.

  • Added emscripten as a tested target (Emscripten 6.0.11 under Node): tests, link-only programs and driven tests, in CI and in own lanes.

  • Added the lint rule bare-throw: a library header raises only through boost::throw_exception.

  • Added the lint rule path.exists native: a Jam file’s path.exists takes a native path, which Windows needs.

  • Added the lint rule octal escapes: no octal escape of a C++ literal runs into a digit, which MSVC refuses.

  • Changed the lint to analyse every aggregate, test and example without exceptions too, so a library keeps compiling without them.

  • Changed CI to run one own-lane job per library, lane and target, installing Node only where needed; b2 declared-lanes prints each lane’s kind.

  • Fixed an own lane that served nothing or missed a target passing silently; it now fails by name.

  • Fixed serve.py leaving wasmtime running when it is killed.

  • Changed the lint’s compilation database to include every program an own lane builds, served programs included.

  • Fixed the Node package installer leaving a stray link or a traceback when an install is killed or refused.

  • Added the names target, has, no, lib, version and test, alone or before _, to those no library may take.

  • Added the lint rule refusing an unescaped __X__ in a Doc Comment’s code span.

  • Added each version’s release notes to the index page, newest first.

  • Added the lint rule changelog: every changelog line keeps its form.

  • Added b2 check-release, b2 whats-new and b2 dist, which check, announce and package a release.

  • Added third_party/, third-party code pinned as submodules: first the JSON Schema Test Suite, which a test reads on every target through /webcpp/third_party//json-schema-test-suite.

  • Changed the lint to never read third-party code under third_party/libs/.

  • Added webcpp.generated, which checks a library’s generated files against their Python generator, and update-generated, their only writer.

  • Added --files to tools/oracle/compare.py, which compares two files byte for byte.

  • Added /webcpp//boost_url, Boost.URL built from Boost’s sources for every target, read from BOOST_SOURCE or .local/boost-source; another Boost version’s tree is refused.

  • Changed the CI’s Boost action to keep the sources of Boost’s compiled libraries; install.sh source <dir> fills a local tree.

  • Changed the lint to never analyse a source outside the tree, such as Boost’s.

  • Added /webcpp//boost_charconv, Boost.Charconv built from Boost’s sources for every target.

  • Added /webcpp//boost_locale, Boost.Locale without ICU built from Boost’s sources for every target; a program that uses it needs exceptions.

  • Added /webcpp//boost_cobalt, Boost.Cobalt built from Boost’s sources for native programs, which need exceptions.

  • Fixed a lane’s alias and a library’s generated files running the configuration check of Boost, which neither needs.

  • Added webcpp.data, which gives a test a directory of the host’s at the same path on every target, through wasmtime’s --dir on WASI.

  • Added b2 site and b2 site-serve: the whole site, every library’s page and the report under its header, into bin/site/, every link checked, then served.

  • Added the site’s tests, b2 /webcpp/site//test, and a CI lane that runs them.

  • Changed CI to publish the site, never indexed, at https://webcpporg.github.io/; the old address https://webcpporg.github.io/webcpp/ redirects there.

  • Added /webcpp//emscripten-reference, which reads a library’s reference as Emscripten’s em++ compiles it, with the emsdk of -sWEBCPP_EMSDK=<dir> or .local/emsdk.

  • Changed the lint to analyse headers and programs that build only on emscripten, with the options em++ gives them, or only against a native dependency.

  • Changed the CI’s docs and lint jobs to install emsdk only when a library declares emscripten.

  • Changed the lint’s analysis without exceptions to leave out, by name, a header whose headers-alone call declares <exception-handling>on.

  • Changed the lint’s *this rule to allow an assignment operator however its signature is split, a prefix increment or decrement, and a function marked lint-std.

  • Changed the lint’s io_context::run rule to find an io_context named through a namespace alias, and to accept a reason after lint-run:.

  • Changed the lint’s world rule to name getentropy, getrandom, arc4random, RAND_bytes and <sys/random.h>.

  • Changed the lint’s licence rule to check .js, .adoc and .html files too.

  • Added webcpp.external, which finds a library webcpp does not build through -s<VARIABLE>=<dir>, .local/ or the system, and leaves out a library that needs a missing one.

  • Added webcpp-require-external=on, which stops the build on a missing external library instead, as the CI and the lint build.

  • Changed the index to name a library a build leaves out, with the reason and no link.

  • Changed b2 install to put each library’s licence files beside its headers.

  • Added {library-root}, through which a library’s page shows a tagged region of a file its own git tracks, a test’s or an example’s as C++.

  • Added doc-check rules: a rendered page holds no em dash, no link inside inline code, and no replacement of Asciidoctor’s inside inline code.

  • Changed every library’s reference to list only a derived class’s own members (inherit-base-members: never).

  • Changed a page’s counts to read with a thousands separator, as 1,111.

  • Changed the CI’s GCC 14 and Clang 18 lanes to run in a container built from Ubuntu’s archive snapshot, with no network but the loopback.

  • Added a pinned chrome-headless-shell to the CI, for the own lanes whose driver meets a browser.

  • Added the CI actions secp256k1, libdatachannel and openssl, which build trystero’s external libraries, pinned, with each lane’s compilers.

  • Changed the Node package installer to run npm ci with DO_NOT_TRACK=1, so that no install script reports an install.

  • Changed CI to run the lint and the tests of the tools in eight shards each, at once.

  • Added --shard K/N to the tests of the tools, which runs the K-th of N slices of a suite’s cases.

  • Fixed the site refusing the report’s page of a failure: its title now fits in 70 characters, and no line of its output ends in whitespace.

  • Changed the libraries’ CI to check out the superproject’s submodules without theirs, so a pinned third-party repository’s own submodules are not fetched.

  • Added webcpp-suspend, an emscripten program’s suspension variant: jspi, the default, or asyncify, built with JavaScript-based exceptions.

  • Added /webcpp//node-test, which every test and example links, with <webcpp/test/exit_status.hpp>: under Node, a test whose main never finishes fails, and one past its bound of 120 s stops.

  • Changed webcpp::test::exit_status to end a test under Node at once, with the first status it is given.

  • Added a refusal of -sMODULARIZE and -sEXPORT_ES6 on a test or example that Node runs, which would pass having run nothing.

  • Fixed a test passing under Node when its main never ran, or when -sMODULARIZE came among other flags of one value.

  • Added webcpp.variants and webcpp.size-table: a page’s program in both suspension variants, its manifest for the page’s loader, and its sizes, kept by the CI.

  • Added the tag rule webcpp.suspend-tag, which names an emscripten program Boost’s way, with its suspension variant.

  • Changed webcpp.variants to refuse a build that asks for JavaScript exceptions, which would link the jspi variant with them.

  • Fixed the lint stopping on a program built with JavaScript-based exceptions, such as an asyncify variant’s.

  • Fixed a test ending through webcpp::test::exit_status printing Emscripten’s notice that the runtime is kept alive.

  • Changed the lint rule bare-throw to leave alone the JavaScript of an EM_JS function or an EM_ASM block.

Compilers tested

  • GCC 15

  • Emscripten 6.0.11 (node)