anyhttp is developed and tested in a devcontainer. The same image runs the CI jobs in :src:`.github/workflows/release.yml`, so a build that works in the container is the build CI does.
There are three image layers. Only the last one is built locally when you open the project:
| Image | Built from | Contents |
|---|---|---|
psedoc/cpp-devcontainer |
pgit/cpp-devcontainer | generic C++ toolchain and libraries |
psedoc/anyhttp |
:src:`.devcontainer/base/Dockerfile` | the HTTP/2 and HTTP/3 stack anyhttp needs |
| (local, per checkout) | :src:`.devcontainer/Dockerfile` | interactive tools, shell settings, what makes this documentation |
psedoc/anyhttp changes rarely and takes a while to build, so it is built once and pushed to Docker
Hub. Opening the project (or a codespace) then only pulls it and adds the thin top layer.
See its repository for details. In short: a Debian
trixie image with GCC, a current clang from apt.llvm.org, CMake, Ninja, gdb, and gtest-parallel.
The C++ libraries are built twice, once for each standard library, because a C++ library built against
libstdc++ cannot be linked into a libc++ program or vice versa:
| Prefix | Standard library | Libraries |
|---|---|---|
/usr/local |
libstdc++ (GCC) | Boost, GTest/GMock, fmt, spdlog |
/opt/libc++ |
libc++ (clang) | the same set |
With clang, anyhttp builds against libc++ and must pick up the libraries from /opt/libc++; with GCC
it uses libstdc++ and the ones in /usr/local. USE_LIBCXX in the top level
:src:`CMakeLists.txt` selects which (default: on for clang), and LIBCXX_ROOT (default:
/opt/libc++) where the libc++ builds are.
:src:`.devcontainer/base/Dockerfile` adds the protocol stack. All of it is C, so a single build in
/usr/local serves both standard libraries.
- AWS-LC in
/opt/boringssl, static libraries only. It is API-compatible with BoringSSL, which is what ngtcp2 calls it. It is deliberately kept out of/usr/localso it does not shadow the system OpenSSL; see "One TLS library per process" in :src:`CLAUDE.md`. - nghttp3 (lib only) in
/usr/local. - ngtcp2 in
/usr/local, with both crypto backends:ngtcp2_crypto_boringssl(what anyhttp links by default) andngtcp2_crypto_ossl(with-DTLS_LIBRARY=OpenSSL). Its OpenSSL example programs are installed asosslclientandosslserverfor interop tests. - urlparse (from ngtcp2's third-party tree).
- nghttp2 with HTTP/3 support, built against the OpenSSL variant: the library for the HTTP/2
backend, plus
nghttp,nghttpd,nghttpxandh2loadfor testing and benchmarking. libbpf is built first so thatnghttpxcan use it for QUIC connection steering. - curl from git master with nghttp2, ngtcp2 and nghttp3 over OpenSSL, so
curl --http3works. The apt package is removed so the tests cannot pick up an older curl. libev(needed by the nghttp2 and ngtcp2 tools) andgolang-cfssl(used to generate the test PKI inpki/).- The Debian
libnghttp2-dev/libnghttp3-devpackages are removed, so CMake and pkg-config cannot find a stale system copy instead of the one in/usr/local. - gdb helpers for the
vscodeuser: libc++ pretty printers and Asio's debugger extensions (backtraces acrossco_await), both registered in~/.gdbinit.
The top layer, :src:`.devcontainer/Dockerfile`, adds things for interactive use: tmux, btop,
valgrind, ping, persistent bash history (a volume mounted at /commandhistory), and the
aliases in .devcontainer/.bash_aliases. It also has Doxygen, Sphinx and Breathe, for this
documentation. :src:`.devcontainer/devcontainer.json` adds the VS Code extensions (clangd, CMake Tools,
TestMate, CodeLLDB, ...), SYS_PTRACE for debuggers and sanitizers, and bind-mounts ~/.claude
from the host.
Bump a dependency by changing its ARG ..._VERSION in the base Dockerfile, then:
cd .devcontainer/base
docker build -t psedoc/anyhttp:testing ..devcontainer/Dockerfile builds FROM that tag, so rebuilding the devcontainer ("Dev Containers:
Rebuild Container" in VS Code) picks it up. Once the tests pass in it, tag and push a numbered version
and point both .devcontainer/Dockerfile and the image: entries in
.github/workflows/release.yml at it. Keep the psedoc/anyhttp and psedoc/cpp-devcontainer
version numbers in step, so it is clear which base a given anyhttp image was built on.