flight-cpp is the incubating C++20 runtime for TypeScript compiled by Flight Compiler. It was incubated inside the compiler repository while the generated-code boundary settled and now stands on its own, carrying that history with it. The runtime builds with CMake or Bazel and needs no Node.js.
This is a working foundation, not yet a production-support claim. Version 0.1.0 provides tested representations for shared arrays, insertion-ordered maps and sets, typed-array views, explicit undefined/null presence, SameValueZero equality, UTF-16 strings, source-style errors and number formatting, UTC date instants, shared coroutine tasks, and closed multi-member unions with distinct C++ alternatives. Tasks use an explicit non-reentrant executor and implement first-settlement-wins construction, exact rejection values, queued continuation, recovery, cleanup, assimilation, and ordered aggregation. Full Unicode case conversion is supplied through a host service. Compiler-generated conformance exercises collections, strings, classes, typed arrays, optional access, coroutines, and checker-proven union narrowing; cancellation, time zones, captured mutation, duplicate union representations, and optional variants remain open.
The core runtime and its tests have no third-party dependencies. The presets require CMake 3.20 or newer, a C++20 compiler, and Ninja:
cmake --preset development
cmake --build --preset development
ctest --preset developmentThe presets use Ninja and leave compiler selection to CMake. Pass -DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain.cmake at configure time for a cross or pinned toolchain; CMakeUserPresets.json is ignored for machine-local settings.
The independent Bazel 9 module builds and runs the same public runtime, C ABI, generated-source, header, and consumer surfaces. Bazelisk selects the checked-in version:
bazel test --config=local-posix //:testsUse --config=local-msvc for the default Visual C++ toolchain, or select an arbitrary registered platform and C++ toolchain without changing the Flight graph. The Bazel build contract covers local, cross, remote-execution, and reproducibility policy.
GCC and Clang development builds can add -DFLIGHT_CPP_ENABLE_SANITIZERS=ON to run the same runtime and generated-program tests under AddressSanitizer and UndefinedBehaviorSanitizer.
The handwritten SDL 3 host is an optional CMake package. Enabling it builds SDL lifecycle/window support plus
separate GL, Vulkan, and WebGPU surface targets without adding dependencies to Flight::Cpp:
cmake --preset development -DFLIGHT_CPP_BUILD_HOST_SDL=ON
cmake --build --preset development
ctest --preset developmentSee the SDL host package guide for dependencies, exported targets, ownership, and the generated SDK wiring lane.
Release builds can add -DFLIGHT_CPP_BUILD_BENCHMARKS=ON. The resulting flight_cpp.performance CTest emits JSON-lines measurements and applies deliberately broad throughput floors for collection, ordered-map, and settled-task regressions. These are smoke gates, not cross-machine comparisons; release-candidate history should tighten them only after a stable runner baseline exists.
The development and release presets build the native examples. Run the compiler-generated tween example after a development build:
./out/cmake/development/examples/flight_cpp_tween_exampleThe example preserves the fifteen easing tracks from Flight's TypeScript tween example and renders one deterministic frame in a terminal. Its portable calculation is TypeScript transpiled by the pinned flight-compiler; a small handwritten C++ host owns terminal output. See examples/README.md for the source, generated output, regeneration command, and the current boundary around browser-backed examples.
The same generated curves also have an interactive SDL/OpenGL ES host. Enable the optional SDL package and disable the unused Vulkan adapter, then run the native window:
cmake --preset development \
-DFLIGHT_CPP_BUILD_HOST_SDL=ON \
-DFLIGHT_CPP_BUILD_HOST_SDL_VULKAN=OFF
cmake --build --preset development
./out/cmake/development/examples/flight_cpp_tween_sdl_gl_exampleConsumers can build it in-tree with add_subdirectory, or install it and use:
find_package(FlightCpp 0.1 CONFIG REQUIRED)
target_link_libraries(my_program PRIVATE Flight::Cpp)Foreign-language consumers can link Flight::C and include <flight/c/runtime.h>. The initial ABI exposes version negotiation and reference-counted UTF-8 string handles without leaking C++ layout or exceptions. It is intentionally smaller than the C++ surface; bindings add functions only after their ownership, error, and threading rules are fixed. The C ABI contract defines those rules, and the ABI v1 contract snapshot makes function-signature and status-value drift explicit in repository checks.
The C++ semantic runtime remains header-only during incubation; Flight::C is its separately linked ABI adapter. Include the complete C++ compatibility surface with:
#include <flight/runtime.hpp>The umbrella header provides FlightTask<T> and FlightDate compatibility names. The compiler's flight-cpp runtime profile emits the namespaced semantic APIs directly.
Native hosts configure executor and Unicode policy together with flight::HostScope. Services are thread-scoped and nest safely, which gives an embedder an explicit boundary instead of process-global callbacks.
The installed flight/ headers and Flight::Cpp target are the extraction boundary. Nothing in this directory imports the compiler, assumes its repository layout, participates in the npm workspace, or relies on generated source checked in elsewhere.
The compiler emits semantic runtime types such as flight::Array<T> and flight::Map<K, V> when runtimeProfile: "flight-cpp" is elected. The separate standard-library profile preserves generic provisional output without claiming TypeScript-equivalent collection behavior. See compiler integration and runtime semantics.
The first full-SDK inventory is committed under generated/. It contains every header the
pinned compiler can currently emit from the package closure declared by @flighthq/sdk, plus a complete refusal
ledger. It is intentionally visible before it forms a compilable library. The SDL host bring-up
defines the handwritten native lane that will inject GL or WGPU handles without duplicating upstream renderers.
The supported input boundary is versioned as flight-portable-typescript/1. known-exceptions.json owns every checked-in C++ refusal. The compiler repository verifies it against its own fixture corpus, because a refusal changes when the compiler changes; this repository owns the file, and that gate reads it from a pinned checkout of this repository.
The runtime and the compiler are separate repositories that must keep agreeing, so each pins the other rather than sharing a tree. dependencies.lock.json names the exact commit of flight and flight-compiler this checkout is verified against:
npm run rehydrate # materialize the pinned checkouts under .dependencies/
npm run rehydrate:check # fail if a checkout is missing or off its pin
npm run rehydrate:update # re-pin each dependency to its tracking branch headThe checkouts are gitignored, disposable build inputs. Nothing in .dependencies/ is committed, and the lock is the only thing that decides which revision a gate reads.
The native build is the runtime's own gate and is run directly with CMake or Bazel. npm run check covers what building cannot show:
| Gate | Question |
|---|---|
npm run abi:check |
Do the C header, its implementation, and the committed ABI snapshot name the same symbols? |
npm run build:check |
Do the CMake and Bazel graphs describe the same headers, sources, tests, and benchmarks? |
npm run examples:check |
Does the pinned compiler reproduce the checked-in native example output? |
npm run sdk:check |
Does the pinned compiler reproduce the committed SDK headers and refusal inventory? |
npm run release:check |
Do the version, ABI, C++ standard, and conformance profile agree across every file that states them? |
npm run compile:check |
Does the pinned compiler's emitted C++ still compile against this runtime? |
compile:check reports and skips when the checkout is absent or no C++ compiler is installed, so a fresh clone stays runnable. The compiler repository asks the same question from its side against the runtime revision it pins; both are wanted, because each side owns the pin it can move and a failure names which one changed.
MIT. See LICENSE.md.