Development container ===================== 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: .. list-table:: :header-rows: 1 * - 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. What cpp-devcontainer provides ------------------------------ 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: .. list-table:: :header-rows: 1 * - 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. What anyhttp adds ----------------- :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/local`` so 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) and ``ngtcp2_crypto_ossl`` (with ``-DTLS_LIBRARY=OpenSSL``). Its OpenSSL example programs are installed as ``osslclient`` and ``osslserver`` for 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``, ``nghttpx`` and ``h2load`` for testing and benchmarking. **libbpf** is built first so that ``nghttpx`` can use it for QUIC connection steering. * **curl** from git master with nghttp2, ngtcp2 and nghttp3 over OpenSSL, so ``curl --http3`` works. The apt package is removed so the tests cannot pick up an older curl. * ``libev`` (needed by the nghttp2 and ngtcp2 tools) and ``golang-cfssl`` (used to generate the test PKI in ``pki/``). * The Debian ``libnghttp2-dev`` / ``libnghttp3-dev`` packages are removed, so CMake and pkg-config cannot find a stale system copy instead of the one in ``/usr/local``. * gdb helpers for the ``vscode`` user: libc++ pretty printers and Asio's debugger extensions (backtraces across ``co_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. Updating the images ------------------- Bump a dependency by changing its ``ARG ..._VERSION`` in the base Dockerfile, then: .. code-block:: sh 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.