cpp-splitter reads a C++ translation unit and headers through libclang and rewrites it as one piece per
function definition behind a shared preamble, so the pieces compile in parallel (locally or
on a remote build execution cluster) and are linked back ({mold,ld,lld} -r) into the single object the
build system expected. It runs transparently as a CMAKE_CXX_COMPILER_LAUNCHER in front of the real compiler; see DOCS.md and
Boost.Spirit Test Suite Benchmark for how and why.
Both hosts build through CMake RE
(cmake-re, ships ctest-re), which brings its own cmake, ninja and clang 13:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/tipi-build/cli/master/install/install_for_macos_linux.sh)"export TIPI_DISABLE_AR_RANLIB_DRIVER=ON TIPI_CACHE_CONSUME_ONLY=ON TIPI_CACHE_FORCE_ENABLE=OFFThe first configure fetches and builds Boost 1.85 through HermeticFetchContent and takes a few minutes; later ones reuse it.
macOS — host build with tipi's clang, Apple's or Homebrew's, and the Linux image through Docker
Host build with the clang 13 tipi installs at /usr/local/share/.tipi/clang/a7e6968
(x86_64; the installer sets up Rosetta on Apple silicon):
cmake-re --host -S . -B build/cmake-re-macos-clang -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=environments/macos-clang.cmake
cmake-re --build build/cmake-re-macos-clang --host -j8
ctest-re --test-dir build/cmake-re-macos-clang --output-on-failure -j8Or with the clang macOS ships, which is what CI does since the installer does not bring
tipi's clang to a GitHub runner. Apple's toolchain lacks the clang-c/ headers, so libclang
comes from Homebrew's llvm:
brew install llvm
cmake-re --host -S . -B build/cmake-re-macos-apple-clang -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=environments/macos-apple-clang.cmake
cmake-re --build build/cmake-re-macos-apple-clang --host -j8
ctest-re --test-dir build/cmake-re-macos-apple-clang --output-on-failure -j8Or entirely with Homebrew's LLVM — its clang driving the compiles and its libclang parsing.
This is the build for C++20 named modules (TODO/43): Apple's clang has no clang-scan-deps
for CMake's module scan, and -fmodules-reduced-bmi needs clang >= 20. The toolchain file
points the compiler at the macOS SDK itself, since a non-Apple clang does not find it:
brew install llvm
cmake-re --host -S . -B build/cmake-re-macos-brew-llvm -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=environments/macos-brew-llvm.cmake
cmake-re --build build/cmake-re-macos-brew-llvm --host -j8
ctest-re --test-dir build/cmake-re-macos-brew-llvm --output-on-failure -j8launcher.module_interface_split and example.cpp_20_modules run here and skip on the two
builds above. ./benchmark-cpp20-modules.sh uses this splitter by default.
The same Mac can also run the Linux build below: cmake-re starts the image through Docker
Desktop (>= 27.2.0) and mounts the tree into it.
Linux — in the tipi image, through cmake-re or plain cmake
Containerized in tipibuild/tipi-ubuntu-2404:v0.0.87, the image environments/ubuntu-clang.*
pins by digest -- the same one CI, the devcontainer and the benchmarks use. Needs docker
= 27.2.0:
cmake-re -S . -B build/cmake-re-ubuntu-clang -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=environments/ubuntu-clang.cmake
cmake-re --build build/cmake-re-ubuntu-clang -j8
cmake-re --build build/cmake-re-ubuntu-clang --run-test all --test-jobs 8The tests run inside the container through --run-test: ctest-re executes on the host,
where a Linux cpp-splitter cannot.
Already inside that image (the devcontainer, a GitHub container: job, or tipi run /bin/bash
in a container started by hand -- see CLAUDE.md), build on the host instead, which
is what CI does:
cmake-re --host -S . -B build/cmake-re-ubuntu-clang -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=environments/ubuntu-clang.cmake
cmake-re --build build/cmake-re-ubuntu-clang --host -j8
ctest-re --test-dir build/cmake-re-ubuntu-clang --output-on-failure -j8Plain cmake works there too:
cmake -GNinja -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=environments/monolithic.cmake
cmake --build build -j8
ctest --test-dir build --output-on-failure -j8--build must be the first argument to cmake-re. build/<name> is a symlink into
cmake-re's mirror of the tree. launcher.remote_split_on_rbe runs only on a Linux host with
cmake-re >= v0.0.88 and RBE_service, RBE_tls_client_auth_cert and RBE_tls_client_auth_key
set -- the variables reclient reads, the last two naming the EngFlow mTLS pair -- and skips
otherwise. CI sets them from the RBE_SERVICE, RBE_TLS_CLIENT_AUTH_CERT and
RBE_TLS_CLIENT_AUTH_KEY secrets.
Standalone, split one file, compile the pieces and link them:
./build/cmake-re-ubuntu-clang/cpp-splitter path/to/unit.cpp out/ --compile -o out/program --cxx clang++As a compiler launcher in any CMake project:
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=/abs/path/to/cpp-splitterBehind cmake-re --distributed, the split itself runs on the RBE cluster;
tools/build-spirit-cmake-re.sh show the setup. Results of the Boost measurements are in
benchmarks/.