From c6b24e6e45ca00197f881e50da475f54dff47ccf Mon Sep 17 00:00:00 2001 From: Alan George Date: Mon, 19 Oct 2026 11:43:57 -0700 Subject: [PATCH 01/10] Initial linux compiler fix --- AGENTS.md | 9 ++- build.sh | 169 +++++++++++++++++++++++++++++++++++++++++++++++ docs/building.md | 48 +++++++++++--- docs/tools.md | 25 ++++++- 4 files changed, 238 insertions(+), 13 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index cc4ce419..ef20635c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -145,7 +145,14 @@ the source tree. Track capture Rust sources and shaders in build dependencies. The build scripts pass an explicit job count to `cmake --build --parallel`. Set `CMAKE_BUILD_PARALLEL_LEVEL` to override the default detected logical CPU count. -**Requirements:** CMake 3.20+, C++17, Rust toolchain (cargo), protoc. On macOS: `brew install cmake ninja protobuf abseil`. On Linux: see the CI workflow for apt packages. spdlog is vendored automatically via FetchContent (or vcpkg on Windows) to avoid system conflicts. +**Requirements:** CMake 3.20+, C++17, Rust toolchain (cargo), protoc. Linux +source builds require clang/clang++ 21+ and a matching libclang runtime; +`build.sh` discovers versioned installations, validates the toolchain, and +rejects stale build directories configured with another compiler. macOS builds +use Xcode Apple Clang selected through `xcrun`. On macOS: +`brew install cmake ninja protobuf abseil`. On Linux: see `docs/building.md` +and the CI workflow for apt packages. spdlog is vendored automatically via +FetchContent (or vcpkg on Windows) to avoid system conflicts. ### SDK Packaging diff --git a/build.sh b/build.sh index 4a4aec6f..f67e8b08 100755 --- a/build.sh +++ b/build.sh @@ -27,6 +27,146 @@ detect_os() { OS_TYPE="$(detect_os)" +compiler_clang_major() { + local compiler="$1" + "${compiler}" -dM -E -x c /dev/null 2>/dev/null \ + | awk '$2 == "__clang_major__" { print $3; exit }' +} + +resolve_compiler() { + local compiler="$1" + if [[ "${compiler}" == */* ]]; then + [[ -x "${compiler}" ]] || return 1 + printf '%s\n' "${compiler}" + else + command -v "${compiler}" 2>/dev/null + fi +} + +find_libclang_dir() { + local llvm_root="$1" + local clang_major="$2" + local -a search_dirs=( + "${llvm_root}/lib" + "${llvm_root}/lib64" + "/usr/lib/llvm-${clang_major}/lib" + ) + local directory candidate + + for directory in "${search_dirs[@]}"; do + [[ -d "${directory}" ]] || continue + for candidate in \ + "${directory}/libclang.so" \ + "${directory}"/libclang.so.* \ + "${directory}"/libclang-*.so \ + "${directory}"/libclang-*.so.*; do + [[ -f "${candidate}" ]] || continue + [[ "$(basename "${candidate}")" == *-cpp.* ]] && continue + printf '%s\n' "${directory}" + return 0 + done + done + + return 1 +} + +select_linux_clang_pair() { + local candidate_cc="$1" + local candidate_cxx="$2" + local resolved_cc resolved_cxx cc_major cxx_major llvm_root libclang_dir + + resolved_cc="$(resolve_compiler "${candidate_cc}")" || return 1 + resolved_cxx="$(resolve_compiler "${candidate_cxx}")" || return 1 + cc_major="$(compiler_clang_major "${resolved_cc}")" + cxx_major="$(compiler_clang_major "${resolved_cxx}")" + + [[ -n "${cc_major}" && "${cc_major}" == "${cxx_major}" ]] || return 1 + ((cc_major >= 21)) || return 1 + + llvm_root="$(cd "$(dirname "${resolved_cxx}")/.." && pwd -P)" + libclang_dir="$(find_libclang_dir "${llvm_root}" "${cxx_major}")" || return 1 + + CC="${resolved_cc}" + CXX="${resolved_cxx}" + LIBCLANG_PATH="${libclang_dir}" + export CC CXX LIBCLANG_PATH + return 0 +} + +configure_linux_toolchain() { + local -a llvm_roots=() + local root version + + if [[ -n "${LLVM_ROOT:-}" ]]; then + if ! select_linux_clang_pair "${LLVM_ROOT}/bin/clang" "${LLVM_ROOT}/bin/clang++"; then + echo "ERROR: LLVM_ROOT=${LLVM_ROOT} does not contain clang/clang++ 21+ and libclang." >&2 + exit 1 + fi + elif [[ -n "${CC:-}" || -n "${CXX:-}" ]]; then + if [[ -z "${CC:-}" || -z "${CXX:-}" ]]; then + echo "ERROR: CC and CXX must both be set when selecting a compiler explicitly." >&2 + exit 1 + fi + if ! select_linux_clang_pair "${CC}" "${CXX}"; then + echo "ERROR: CC=${CC} and CXX=${CXX} must select matching clang 21+ compilers with libclang." >&2 + exit 1 + fi + else + shopt -s nullglob + llvm_roots=(/opt/llvm-*) + shopt -u nullglob + if ((${#llvm_roots[@]})); then + while IFS= read -r root; do + if select_linux_clang_pair "${root}/bin/clang" "${root}/bin/clang++"; then + break + fi + done < <(printf '%s\n' "${llvm_roots[@]}" | sort -Vr) + fi + + if [[ -z "${CC:-}" ]]; then + for ((version = 40; version >= 21; --version)); do + if select_linux_clang_pair "clang-${version}" "clang++-${version}"; then + break + fi + done + fi + + if [[ -z "${CC:-}" ]] && ! select_linux_clang_pair "clang" "clang++"; then + echo "ERROR: Linux builds require clang/clang++ 21+ and libclang." >&2 + echo "Ubuntu 22.04 and 24.04 distro clang versions are too old." >&2 + echo "Install clang-21 from apt.llvm.org or set LLVM_ROOT to a compatible LLVM installation." >&2 + exit 1 + fi + fi + + echo "==> Linux compiler: $("${CXX}" --version | awk 'NR == 1 { print; exit }')" + echo "==> CC=${CC}" + echo "==> CXX=${CXX}" + echo "==> LIBCLANG_PATH=${LIBCLANG_PATH}" +} + +configure_macos_toolchain() { + if ! command -v xcrun >/dev/null 2>&1; then + echo "ERROR: xcrun is unavailable. Install Xcode Command Line Tools." >&2 + exit 1 + fi + + CC="$(xcrun --find clang)" + CXX="$(xcrun --find clang++)" + export CC CXX + + echo "==> macOS compiler: $("${CXX}" --version | awk 'NR == 1 { print; exit }')" + echo "==> CC=${CC}" + echo "==> CXX=${CXX}" +} + +configure_build_toolchain() { + case "${OS_TYPE}" in + linux) configure_linux_toolchain ;; + macos) configure_macos_toolchain ;; + esac +} + usage() { cat <&2 + echo " cached CC=${cached_cc}" >&2 + echo " cached CXX=${cached_cxx}" >&2 + echo " selected CC=${CC}" >&2 + echo " selected CXX=${CXX}" >&2 + echo "Run './build.sh clean' and retry." >&2 + exit 1 + fi + fi + echo "==> Configuring CMake (${BUILD_TYPE}) using preset ${PRESET}..." local -a extra_args=("-DLIVEKIT_CAPTURE=${CAPTURE_OVERRIDE}") if [[ -n "${LIVEKIT_VERSION}" ]]; then @@ -351,6 +511,8 @@ clean() { else echo " (skipping) Unknown build system or not configured" fi + rm -f "${debug_dir}/CMakeCache.txt" + rm -rf "${debug_dir}/CMakeFiles" else echo " (skipping) build-debug does not exist." fi @@ -365,6 +527,8 @@ clean() { else echo " (skipping) Unknown build system or not configured" fi + rm -f "${release_dir}/CMakeCache.txt" + rm -rf "${release_dir}/CMakeFiles" else echo " (skipping) build-release does not exist." fi @@ -400,6 +564,11 @@ fi cmd="$1" parse_opts "$@" +case "${cmd}" in + debug|debug-examples|debug-tests|debug-all|release|release-examples|release-tests|release-all|build-all) + configure_build_toolchain + ;; +esac case "${cmd}" in debug) BUILD_TYPE="Debug" diff --git a/docs/building.md b/docs/building.md index f1494135..f2726b5a 100644 --- a/docs/building.md +++ b/docs/building.md @@ -20,8 +20,8 @@ CMake/vcpkg flows. | Platform | Compiler | Package manager | |----------|----------|-----------------| | Windows | Visual Studio 2019+ (MSBuild or Ninja) | vcpkg (see below) | -| Linux | GCC 9+ or Clang 10+ | `apt` / `dnf` (or vcpkg) | -| macOS | Xcode 12+ (macOS 12.3+ for ScreenCaptureKit) | Homebrew (or vcpkg) | +| Linux | Clang 21+ with libclang | `apt` (or vcpkg) | +| macOS | Xcode 12+ Apple Clang (macOS 12.3+ for ScreenCaptureKit) | Homebrew (or vcpkg) | @@ -104,14 +104,32 @@ brew install cmake ninja protobuf abseil rust ```bash sudo apt update && sudo apt install -y \ build-essential cmake ninja-build pkg-config \ - llvm-dev libclang-dev clang \ libprotobuf-dev protobuf-compiler libabsl-dev \ - libssl-dev + libssl-dev wget ca-certificates gnupg lsb-release + +# Ubuntu 22.04 ships clang 14 and Ubuntu 24.04 ships clang 18. The Rust +# WebRTC bridge requires clang 21 or later, so install the minimal versioned +# compiler package from apt.llvm.org. +sudo install -m 0755 -d /etc/apt/keyrings +wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ + | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null +sudo chmod a+r /etc/apt/keyrings/llvm.asc +codename=$(lsb_release -cs) +echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-21 main" \ + | sudo tee /etc/apt/sources.list.d/llvm-21.list >/dev/null +sudo apt update +sudo apt install -y clang-21 # Install Rust if you don't already have it curl https://sh.rustup.rs -sSf | sh ``` +`clang-21` pulls in the matching libclang runtime without installing the full +LLVM tool suite. `build.sh` discovers versioned compiler installations and +exports `CC`, `CXX`, and `LIBCLANG_PATH` for CMake and Cargo. To use a custom +LLVM installation instead, set `LLVM_ROOT` to its prefix (for example, +`/opt/llvm-21.1.8`). + If you plan to build the [example collection](https://github.com/livekit-examples/cpp-example-collection) (SDL-based renderer + camera/mic capture), also install: @@ -226,6 +244,14 @@ cmake -B build -S . ` cmake --build build --config Release ``` +**Linux (compiler environment):** +```bash +# Direct CMake use bypasses build.sh's compiler validation. +export CC=clang-21 +export CXX=clang++-21 +export LIBCLANG_PATH=/usr/lib/llvm-21/lib +``` + **Linux/macOS:** ```bash cmake -B build -S . \ @@ -348,9 +374,8 @@ git submodule update --init --recursive ### Deprecated-declaration errors on Linux -Newer GCC versions (12+) are stricter with the WebRTC legacy code in the -Rust submodule. If `./build.sh release` errors with `-Werror=deprecated-declarations`, -relax it for the build: +Some WebRTC sources use deprecated declarations. If `./build.sh release` +errors with `-Werror=deprecated-declarations`, relax it for the build: ```bash export CXXFLAGS="-Wno-deprecated-declarations" @@ -359,10 +384,11 @@ export CFLAGS="-Wno-deprecated-declarations" ### Rust bindgen fails with "unable to find libclang" -Install `libclang-dev` (Ubuntu) or `llvm` (macOS Homebrew). bindgen normally -discovers libclang from the system paths once `libclang-dev` is installed; if -not, point `LIBCLANG_PATH` at your LLVM's `lib` directory (e.g. -`/usr/lib/llvm-18/lib` on Ubuntu 24.04). +On Linux, install `clang-21` as shown above. `build.sh` accepts both versioned +libraries such as `libclang-21.so.1` and an unversioned `libclang.so`. For a +custom installation, set `LLVM_ROOT` or point `LIBCLANG_PATH` at its library +directory. On macOS, install the Xcode Command Line Tools; `build.sh` selects +Xcode Apple Clang with `xcrun`. ### Rust code recompiles after C++ edits diff --git a/docs/tools.md b/docs/tools.md index 1961742a..362c6c25 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -8,6 +8,15 @@ are also enforced in CI on PRs. The shared configuration and tooling scripts come from the [`livekit/cpp-tools`](https://github.com/livekit/cpp-tools) submodule. +These developer tools are versioned independently from the compiler used to +build the SDK: + +- Linux SDK builds require clang 21 or later. +- Formatting CI uses clang-format 22. +- Static-analysis CI uses clang-tidy 19 (the configuration requires at least + version 19). +- macOS SDK builds use Xcode Apple Clang, not Homebrew LLVM. + - **`clang-tidy`** — static analysis. See [cpp-tools/.clang-tidy](https://github.com/livekit/cpp-tools/blob/main/.clang-tidy) for the enabled checks. Enforced in CI on PR. @@ -32,10 +41,24 @@ This installs `clang-format`, `clang-tidy`, and `run-clang-tidy`. Homebrew may ask you to add `/opt/homebrew/opt/llvm/bin` (Apple Silicon) or `/usr/local/opt/llvm/bin` (Intel) to your `PATH`. +CI remains the reference for exact formatter and analyzer versions when the +current Homebrew LLVM release differs. + **Linux (Ubuntu/Debian):** ```bash -sudo apt-get install clang-format clang-tidy clang-tools +# Configure the apt.llvm.org signing key as described in building.md, then add +# the two developer-tool repositories: +codename=$(lsb_release -cs) +for version in 19 22; do + echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${version} main" \ + | sudo tee "/etc/apt/sources.list.d/llvm-${version}.list" >/dev/null +done +sudo apt-get update +sudo apt-get install clang-format-22 clang-tidy-19 clang-tools-19 +sudo ln -sf /usr/bin/clang-format-22 /usr/local/bin/clang-format +sudo ln -sf /usr/bin/clang-tidy-19 /usr/local/bin/clang-tidy +sudo ln -sf /usr/bin/run-clang-tidy-19 /usr/local/bin/run-clang-tidy ``` Install the shared configuration symlinks from the repository root: From 078ed9c43ec7dbf925b80949eaa534da7b152dd6 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 28 Oct 2026 12:56:36 -0700 Subject: [PATCH 02/10] Additional script cleanup and documentation updates Co-authored-by: Cursor --- .github/actions/setup-sdk-deps/action.yml | 32 +++-- AGENTS.md | 8 +- build.sh | 120 +--------------- docs/building.md | 165 ++++++++++++---------- scripts/setup-linux-toolchain.sh | 157 ++++++++++++++++++++ 5 files changed, 278 insertions(+), 204 deletions(-) create mode 100755 scripts/setup-linux-toolchain.sh diff --git a/.github/actions/setup-sdk-deps/action.yml b/.github/actions/setup-sdk-deps/action.yml index bc343f10..7c9b2bec 100644 --- a/.github/actions/setup-sdk-deps/action.yml +++ b/.github/actions/setup-sdk-deps/action.yml @@ -43,25 +43,37 @@ runs: fi sudo apt-get update sudo apt-get install -y \ - build-essential cmake ninja-build pkg-config \ - llvm-dev libclang-dev clang \ + build-essential cmake ninja-build pkg-config git git-lfs curl \ libva-dev libdrm-dev libgbm-dev libx11-dev libgl1-mesa-dev \ libxext-dev libxcomposite-dev libxdamage-dev libxfixes-dev \ libxrandr-dev libxi-dev libxkbcommon-dev \ libasound2-dev libpulse-dev \ - libssl-dev \ - libprotobuf-dev protobuf-compiler \ - libabsl-dev \ - libcurl4-openssl-dev \ + libglib2.0-dev libssl-dev libcurl4-openssl-dev \ libwayland-dev libdecor-0-dev \ + wget ca-certificates gnupg lsb-release \ "${extra_packages[@]}" - # libwebrtc ships hermetic libc++ headers that require a newer clang than - # Ubuntu provides. The submodule script exports CC/CXX for later steps. - - name: Install clang for libwebrtc + - name: Install Clang 21 if: runner.os == 'Linux' shell: bash - run: client-sdk-rust/.github/scripts/install-clang.sh + run: | + set -eux + sudo install -m 0755 -d /etc/apt/keyrings + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ + | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null + sudo chmod a+r /etc/apt/keyrings/llvm.asc + codename=$(lsb_release -cs) + echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-21 main" \ + | sudo tee /etc/apt/sources.list.d/llvm-21.list >/dev/null + sudo apt-get update + sudo apt-get install -y clang-21 + + source scripts/setup-linux-toolchain.sh + { + echo "CC=$CC" + echo "CXX=$CXX" + echo "LIBCLANG_PATH=$LIBCLANG_PATH" + } >> "$GITHUB_ENV" - name: Install base deps (macOS) if: runner.os == 'macOS' diff --git a/AGENTS.md b/AGENTS.md index ef20635c..ed098da8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -147,9 +147,11 @@ The build scripts pass an explicit job count to `cmake --build --parallel`. Set **Requirements:** CMake 3.20+, C++17, Rust toolchain (cargo), protoc. Linux source builds require clang/clang++ 21+ and a matching libclang runtime; -`build.sh` discovers versioned installations, validates the toolchain, and -rejects stale build directories configured with another compiler. macOS builds -use Xcode Apple Clang selected through `xcrun`. On macOS: +`build.sh` sources `scripts/setup-linux-toolchain.sh` to discover versioned +installations and validate the toolchain. Source that script before direct +Linux CMake usage. The build script rejects stale build directories configured +with another compiler. macOS builds use Xcode Apple Clang selected through +`xcrun`. On macOS: `brew install cmake ninja protobuf abseil`. On Linux: see `docs/building.md` and the CI workflow for apt packages. spdlog is vendored automatically via FetchContent (or vcpkg on Windows) to avoid system conflicts. diff --git a/build.sh b/build.sh index f67e8b08..ba87de2c 100755 --- a/build.sh +++ b/build.sh @@ -27,124 +27,6 @@ detect_os() { OS_TYPE="$(detect_os)" -compiler_clang_major() { - local compiler="$1" - "${compiler}" -dM -E -x c /dev/null 2>/dev/null \ - | awk '$2 == "__clang_major__" { print $3; exit }' -} - -resolve_compiler() { - local compiler="$1" - if [[ "${compiler}" == */* ]]; then - [[ -x "${compiler}" ]] || return 1 - printf '%s\n' "${compiler}" - else - command -v "${compiler}" 2>/dev/null - fi -} - -find_libclang_dir() { - local llvm_root="$1" - local clang_major="$2" - local -a search_dirs=( - "${llvm_root}/lib" - "${llvm_root}/lib64" - "/usr/lib/llvm-${clang_major}/lib" - ) - local directory candidate - - for directory in "${search_dirs[@]}"; do - [[ -d "${directory}" ]] || continue - for candidate in \ - "${directory}/libclang.so" \ - "${directory}"/libclang.so.* \ - "${directory}"/libclang-*.so \ - "${directory}"/libclang-*.so.*; do - [[ -f "${candidate}" ]] || continue - [[ "$(basename "${candidate}")" == *-cpp.* ]] && continue - printf '%s\n' "${directory}" - return 0 - done - done - - return 1 -} - -select_linux_clang_pair() { - local candidate_cc="$1" - local candidate_cxx="$2" - local resolved_cc resolved_cxx cc_major cxx_major llvm_root libclang_dir - - resolved_cc="$(resolve_compiler "${candidate_cc}")" || return 1 - resolved_cxx="$(resolve_compiler "${candidate_cxx}")" || return 1 - cc_major="$(compiler_clang_major "${resolved_cc}")" - cxx_major="$(compiler_clang_major "${resolved_cxx}")" - - [[ -n "${cc_major}" && "${cc_major}" == "${cxx_major}" ]] || return 1 - ((cc_major >= 21)) || return 1 - - llvm_root="$(cd "$(dirname "${resolved_cxx}")/.." && pwd -P)" - libclang_dir="$(find_libclang_dir "${llvm_root}" "${cxx_major}")" || return 1 - - CC="${resolved_cc}" - CXX="${resolved_cxx}" - LIBCLANG_PATH="${libclang_dir}" - export CC CXX LIBCLANG_PATH - return 0 -} - -configure_linux_toolchain() { - local -a llvm_roots=() - local root version - - if [[ -n "${LLVM_ROOT:-}" ]]; then - if ! select_linux_clang_pair "${LLVM_ROOT}/bin/clang" "${LLVM_ROOT}/bin/clang++"; then - echo "ERROR: LLVM_ROOT=${LLVM_ROOT} does not contain clang/clang++ 21+ and libclang." >&2 - exit 1 - fi - elif [[ -n "${CC:-}" || -n "${CXX:-}" ]]; then - if [[ -z "${CC:-}" || -z "${CXX:-}" ]]; then - echo "ERROR: CC and CXX must both be set when selecting a compiler explicitly." >&2 - exit 1 - fi - if ! select_linux_clang_pair "${CC}" "${CXX}"; then - echo "ERROR: CC=${CC} and CXX=${CXX} must select matching clang 21+ compilers with libclang." >&2 - exit 1 - fi - else - shopt -s nullglob - llvm_roots=(/opt/llvm-*) - shopt -u nullglob - if ((${#llvm_roots[@]})); then - while IFS= read -r root; do - if select_linux_clang_pair "${root}/bin/clang" "${root}/bin/clang++"; then - break - fi - done < <(printf '%s\n' "${llvm_roots[@]}" | sort -Vr) - fi - - if [[ -z "${CC:-}" ]]; then - for ((version = 40; version >= 21; --version)); do - if select_linux_clang_pair "clang-${version}" "clang++-${version}"; then - break - fi - done - fi - - if [[ -z "${CC:-}" ]] && ! select_linux_clang_pair "clang" "clang++"; then - echo "ERROR: Linux builds require clang/clang++ 21+ and libclang." >&2 - echo "Ubuntu 22.04 and 24.04 distro clang versions are too old." >&2 - echo "Install clang-21 from apt.llvm.org or set LLVM_ROOT to a compatible LLVM installation." >&2 - exit 1 - fi - fi - - echo "==> Linux compiler: $("${CXX}" --version | awk 'NR == 1 { print; exit }')" - echo "==> CC=${CC}" - echo "==> CXX=${CXX}" - echo "==> LIBCLANG_PATH=${LIBCLANG_PATH}" -} - configure_macos_toolchain() { if ! command -v xcrun >/dev/null 2>&1; then echo "ERROR: xcrun is unavailable. Install Xcode Command Line Tools." >&2 @@ -162,7 +44,7 @@ configure_macos_toolchain() { configure_build_toolchain() { case "${OS_TYPE}" in - linux) configure_linux_toolchain ;; + linux) source "${PROJECT_ROOT}/scripts/setup-linux-toolchain.sh" ;; macos) configure_macos_toolchain ;; esac } diff --git a/docs/building.md b/docs/building.md index f2726b5a..635a05f6 100644 --- a/docs/building.md +++ b/docs/building.md @@ -11,17 +11,15 @@ CMake/vcpkg flows. - **CMake** ≥ 3.20 - **Rust / Cargo** — latest stable toolchain (for building the Rust FFI layer). Install via [rustup](https://rustup.rs/). -- **Git LFS** — required for examples that pull test media assets. -- **Protobuf** ≥ 5.29 -- **Abseil** — always required (used by Protobuf 5.x+) +- **Git/Submodules/LFS** — required to clone submodules and to pull test assets. ### Platform-specific toolchains | Platform | Compiler | Package manager | |----------|----------|-----------------| +| Linux | Clang 21+ with libclang (See [here](#clang-compiler-usage-on-linux) for rationale) | `apt` | +| macOS | Xcode 12+ Apple Clang (macOS 12.3+ for ScreenCaptureKit) | Homebrew | | Windows | Visual Studio 2019+ (MSBuild or Ninja) | vcpkg (see below) | -| Linux | Clang 21+ with libclang | `apt` (or vcpkg) | -| macOS | Xcode 12+ Apple Clang (macOS 12.3+ for ScreenCaptureKit) | Homebrew (or vcpkg) | @@ -73,8 +71,8 @@ pkg-config --modversion gstreamer-1.0 gstreamer-app-1.0 ## Clone the repository -The SDK depends on the [`client-sdk-rust`](https://github.com/livekit/rust-sdks) -submodule (recursive), so always clone with submodules: +The SDK uses recursive submodules for the [`Rust core`](https://github.com/livekit/rust-sdks), shared [C++ tooling](https://github.com/livekit/cpp-tools), and +the [C++ example collection](https://github.com/livekit-examples/cpp-example-collection). ```bash # Option 1: clone with submodules in one step @@ -85,13 +83,14 @@ git clone https://github.com/livekit/client-sdk-cpp.git cd client-sdk-cpp git submodule update --init --recursive -# Pull Git LFS assets if you want to run the integration tests: +# Pull the media asset required by the test suite: git lfs pull ``` ## Recommended setup -These are the exact packages our CI uses. They will also work for examples. +This section outlines the recommended dependency/environmental setup for +each supported platform. ### macOS @@ -99,17 +98,16 @@ These are the exact packages our CI uses. They will also work for examples. brew install cmake ninja protobuf abseil rust ``` -### Ubuntu / Debian +### Linux ```bash sudo apt update && sudo apt install -y \ - build-essential cmake ninja-build pkg-config \ - libprotobuf-dev protobuf-compiler libabsl-dev \ - libssl-dev wget ca-certificates gnupg lsb-release + build-essential cmake ninja-build pkg-config git git-lfs curl \ + libglib2.0-dev libssl-dev libcurl4-openssl-dev \ + wget ca-certificates gnupg lsb-release -# Ubuntu 22.04 ships clang 14 and Ubuntu 24.04 ships clang 18. The Rust -# WebRTC bridge requires clang 21 or later, so install the minimal versioned -# compiler package from apt.llvm.org. +# Ubuntu 22.04 ships clang 14 and Ubuntu 24.04 ships clang 18. Install +# clang 21 and libclang from apt.llvm.org. sudo install -m 0755 -d /etc/apt/keyrings wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null @@ -122,13 +120,10 @@ sudo apt install -y clang-21 # Install Rust if you don't already have it curl https://sh.rustup.rs -sSf | sh -``` -`clang-21` pulls in the matching libclang runtime without installing the full -LLVM tool suite. `build.sh` discovers versioned compiler installations and -exports `CC`, `CXX`, and `LIBCLANG_PATH` for CMake and Cargo. To use a custom -LLVM installation instead, set `LLVM_ROOT` to its prefix (for example, -`/opt/llvm-21.1.8`). +# After cargo installs, run this (or open a new terminal) +. "$HOME/.cargo/env" +``` If you plan to build the [example collection](https://github.com/livekit-examples/cpp-example-collection) (SDL-based renderer + camera/mic capture), also install: @@ -169,8 +164,9 @@ wrap the right CMake preset for your platform and pick sensible defaults. ./build.sh debug-tests # Debug + tests ./build.sh release-all # Release + tests + examples ./build.sh debug-all # Debug + tests + examples +./build.sh build-all # All Debug and Release variants above ./build.sh clean # Clean CMake build artifacts + local-install -./build.sh clean-all # Deep clean (C++ + Rust + local-install + generated files) +./build.sh clean-all # Remove build dirs, local-install, and Rust target ``` **Windows:** @@ -186,7 +182,7 @@ wrap the right CMake preset for your platform and pick sensible defaults. To create an installable SDK bundle with public headers, runtime libraries, and CMake package files, add `--bundle --prefix ` to a build command: -**Linux/Mac:** +**Linux/macOS:** ```bash ./build.sh release --bundle --prefix sdk-out/livekit-sdk @@ -200,6 +196,8 @@ CMake package files, add `--bundle --prefix ` to a build command: The build scripts pass an explicit job count to `cmake --build --parallel`. Set `CMAKE_BUILD_PARALLEL_LEVEL` to override the auto-detected logical CPU count. +Run `./build.sh help` for additional packaging and configuration options, +including `--archive`, `--archive-name`, `--version`, and `-G`. ## Advanced: CMake presets @@ -208,6 +206,7 @@ For more control, drive CMake directly via the presets in ```bash # Linux +source scripts/setup-linux-toolchain.sh cmake --preset linux-release cmake --build --preset linux-release @@ -226,13 +225,13 @@ Windows requires `VCPKG_ROOT` to be set: $env:VCPKG_ROOT = "C:\path\to\vcpkg" ``` -## Advanced: vcpkg manifest mode +## Advanced: Windows vcpkg manifest mode vcpkg will automatically install all dependencies listed in [vcpkg.json](https://github.com/livekit/client-sdk-cpp/blob/main/vcpkg.json) the first time you configure with its toolchain -file. +file. This dependency path is supported only on Windows. Linux and macOS use +the vendored dependency paths described above. -**Windows:** ```powershell cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake cmake --build build --config Release @@ -244,37 +243,15 @@ cmake -B build -S . ` cmake --build build --config Release ``` -**Linux (compiler environment):** -```bash -# Direct CMake use bypasses build.sh's compiler validation. -export CC=clang-21 -export CXX=clang++-21 -export LIBCLANG_PATH=/usr/lib/llvm-21/lib -``` - -**Linux/macOS:** -```bash -cmake -B build -S . \ - -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake \ - -DCMAKE_BUILD_TYPE=Release -cmake --build build - -# With examples: -cmake -B build -S . \ - -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DLIVEKIT_BUILD_EXAMPLES=ON -cmake --build build -``` - ## CMake options | Option | Default | Description | |--------|---------|-------------| | `LIVEKIT_BUILD_EXAMPLES` | OFF | Build example applications | -| `LIVEKIT_USE_SYSTEM_PROTOBUF` | OFF | Use system Protobuf instead of vcpkg's | +| `LIVEKIT_BUILD_TESTS` | OFF | Build test executables | +| `LIVEKIT_USE_SYSTEM_PROTOBUF` | OFF on Linux/macOS; ON on Windows | Select the platform dependency path; CMake forces the value | | `LIVEKIT_LOG_LEVEL` | `TRACE` | Compile-time log threshold (see [logging.md](logging.md)) | -| `LIVEKIT_VERSION` | repo-derived | SDK version string baked into the binary | +| `LIVEKIT_VERSION` | `0.0.0` | SDK version string baked into the binary; set with `--version` or CMake | | `LIVEKIT_CAPTURE` | empty (`none`) | Capture sources for the Rust FFI (`all`, `none`, or a comma-separated list; see [Capture sources](#capture-sources)) | ## Build output @@ -289,12 +266,15 @@ build-release/ │ └── livekit{,_ffi}.lib # Import libraries (Windows) ├── include/ # Public headers (auto-synced) │ └── livekit/ -└── bin/ - └── livekit{,_ffi}.dll # SDK DLLs (Windows) +├── generated/ # Generated protobuf and FFI sources +├── compile_commands.json # Compilation database +└── bin/ # Tests/examples when enabled; DLLs on Windows ``` Release archives use the same layout: `include/`, `lib/`, and (on Windows) -`bin/`. The exact build-tree layout can vary with the CMake generator. +`bin/`. The repository root also receives a `compile_commands.json` symlink. +Example builds use `local-install/` while configuring the example collection. +The exact build-tree layout can vary with the CMake generator. ## Integrating into your project @@ -384,11 +364,13 @@ export CFLAGS="-Wno-deprecated-declarations" ### Rust bindgen fails with "unable to find libclang" -On Linux, install `clang-21` as shown above. `build.sh` accepts both versioned -libraries such as `libclang-21.so.1` and an unversioned `libclang.so`. For a -custom installation, set `LLVM_ROOT` or point `LIBCLANG_PATH` at its library -directory. On macOS, install the Xcode Command Line Tools; `build.sh` selects -Xcode Apple Clang with `xcrun`. +On Linux, install `clang-21` as shown above. Rust bindgen uses libclang to +generate the libyuv bindings; this is separate from the Clang 21 compiler +requirement imposed by libwebrtc's hermetic libc++. `build.sh` accepts both +versioned libraries such as `libclang-21.so.1` and an unversioned +`libclang.so`. For a custom installation, set `LLVM_ROOT` or point +`LIBCLANG_PATH` at its library directory. On macOS, install the Xcode Command +Line Tools; `build.sh` selects Xcode Apple Clang with `xcrun`. ### Rust code recompiles after C++ edits @@ -397,31 +379,33 @@ change or the Rust library is missing. ### Cannot find Protobuf or other dependencies -Make sure you're passing the vcpkg toolchain file: +On Linux and macOS, Protobuf, Abseil, spdlog, and nlohmann/json are fetched +while CMake configures the project. Check network access and verify that all +recursive submodules are initialized: + ```bash --DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake +git submodule update --init --recursive ``` +On Windows, make sure `VCPKG_ROOT` is set and pass the vcpkg toolchain file as +shown above. + ### `clang-tidy` on Windows Not currently supported via our scripts — the Visual Studio (MSBuild) CMake generator doesn't produce `compile_commands.json`. The Ninja generator does; see [tools.md](tools.md). -### How do I deep-clean? +Or clean one configured build tree with its CMake targets: ```bash -./build.sh clean-all # C++ + Rust + local-install + generated files +cmake --build build-release --target clean # CMake artifacts +cmake --build build-release --target cargo_clean # Rust artifacts +cmake --build build-release --target clean_generated # Generated protobuf files +cmake --build build-release --target clean_all # Full clean; removes build-release ``` -Or via CMake targets: - -```bash -cmake --build build --target clean # CMake artifacts -cmake --build build --target cargo_clean # Rust artifacts -cmake --build build --target clean_generated # Generated protobuf headers -cmake --build build --target clean_all # Full clean -``` +Replace `build-release` with `build-debug` for a Debug configuration. ## Cargo output paths on Windows @@ -495,3 +479,40 @@ See [Capture sources](capture-sources.md) for dependencies and usage. - GitHub Issues: - LiveKit Docs: + +## Appendix + +### Clang compiler usage on Linux + +The SDK compiler requirement moved from GCC to Clang 21 when the core Rust SDK +[upgraded to WebRTC M150](https://github.com/livekit/rust-sdks/commit/415f05512b3b5cb417d21630e485c032c21d71b8). +LiveKit's M150 artifact is built with Chromium's hermetic libc++ and ships +those same headers for the Rust `webrtc-sys` C++ bridge. Chromium built that +artifact with Clang 23, while the shipped libc++ headers declare Clang 21 as +their minimum supported compiler. Older Clang versions fail on newer builtins +used by those headers. GCC is also unsuitable for this artifact because it +does not preserve the required libc++ `trivial_abi` calling conventions. + +The SDK also heavily used Clang tooling for formatting and tidy code quality +checks before this WebRTC update, so a Clang dependency was not avoided before +the migration off GCC. + +#### Avoiding Mixing Clang Versions + +Stable Linux distributions generally freeze a compiler major version for the +life of a release. For example, Ubuntu 22.04 provides Clang 14, Ubuntu 24.04 +provides Clang 18, Debian 12 provides Clang 14, and Debian 13 provides Clang +19. Those versions remain useful and supported by their distributions, but +they predate the LLVM toolchain used to produce the current libwebrtc +artifact. The apt.llvm.org repository above supplies a newer, versioned +toolchain without replacing the distribution compiler. + +`build.sh` sources `scripts/setup-linux-toolchain.sh`, which locates the right +Clang environment paths and exports `CC`, `CXX`, and `LIBCLANG_PATH` for CMake +and Cargo. Within `build.sh`, those settings apply only to the build and its +child processes. Direct CMake users can source the same setup script and those +environment settings remain in the current shell. Neither usage modifies the +system-wide compiler configuration. + +To use a custom LLVM installation instead, set +`LLVM_ROOT` to its prefix (for example, `/opt/llvm-21.1.8`). \ No newline at end of file diff --git a/scripts/setup-linux-toolchain.sh b/scripts/setup-linux-toolchain.sh new file mode 100755 index 00000000..c4372576 --- /dev/null +++ b/scripts/setup-linux-toolchain.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash + +# Copyright 2026 LiveKit, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + echo "ERROR: This script must be sourced so it can export the compiler environment:" >&2 + echo " source scripts/setup-linux-toolchain.sh" >&2 + exit 1 +fi + +livekit_compiler_clang_major() { + local compiler="$1" + "${compiler}" -dM -E -x c /dev/null 2>/dev/null \ + | awk '$2 == "__clang_major__" { print $3; exit }' +} + +livekit_resolve_compiler() { + local compiler="$1" + if [[ "${compiler}" == */* ]]; then + [[ -x "${compiler}" ]] || return 1 + printf '%s\n' "${compiler}" + else + command -v "${compiler}" 2>/dev/null + fi +} + +livekit_find_libclang_dir() { + local llvm_root="$1" + local clang_major="$2" + local -a search_dirs=( + "${llvm_root}/lib" + "${llvm_root}/lib64" + "/usr/lib/llvm-${clang_major}/lib" + ) + local directory candidate + + for directory in "${search_dirs[@]}"; do + [[ -d "${directory}" ]] || continue + for candidate in \ + "${directory}/libclang.so" \ + "${directory}"/libclang.so.* \ + "${directory}"/libclang-*.so \ + "${directory}"/libclang-*.so.*; do + [[ -f "${candidate}" ]] || continue + [[ "$(basename "${candidate}")" == *-cpp.* ]] && continue + printf '%s\n' "${directory}" + return 0 + done + done + + return 1 +} + +livekit_select_linux_clang_pair() { + local candidate_cc="$1" + local candidate_cxx="$2" + local resolved_cc resolved_cxx cc_major cxx_major llvm_root libclang_dir + + resolved_cc="$(livekit_resolve_compiler "${candidate_cc}")" || return 1 + resolved_cxx="$(livekit_resolve_compiler "${candidate_cxx}")" || return 1 + cc_major="$(livekit_compiler_clang_major "${resolved_cc}")" + cxx_major="$(livekit_compiler_clang_major "${resolved_cxx}")" + + [[ -n "${cc_major}" && "${cc_major}" == "${cxx_major}" ]] || return 1 + ((cc_major >= 21)) || return 1 + + llvm_root="$(cd "$(dirname "${resolved_cxx}")/.." && pwd -P)" + libclang_dir="$(livekit_find_libclang_dir "${llvm_root}" "${cxx_major}")" || return 1 + + CC="${resolved_cc}" + CXX="${resolved_cxx}" + LIBCLANG_PATH="${libclang_dir}" + export CC CXX LIBCLANG_PATH + return 0 +} + +livekit_configure_linux_toolchain() { + local -a llvm_roots=() + local root version + + if [[ -n "${LLVM_ROOT:-}" ]]; then + if ! livekit_select_linux_clang_pair "${LLVM_ROOT}/bin/clang" "${LLVM_ROOT}/bin/clang++"; then + echo "ERROR: LLVM_ROOT=${LLVM_ROOT} does not contain clang/clang++ 21+ and libclang." >&2 + return 1 + fi + elif [[ -n "${CC:-}" || -n "${CXX:-}" ]]; then + if [[ -z "${CC:-}" || -z "${CXX:-}" ]]; then + echo "ERROR: CC and CXX must both be set when selecting a compiler explicitly." >&2 + return 1 + fi + if ! livekit_select_linux_clang_pair "${CC}" "${CXX}"; then + echo "ERROR: CC=${CC} and CXX=${CXX} must select matching clang 21+ compilers with libclang." >&2 + return 1 + fi + else + shopt -s nullglob + llvm_roots=(/opt/llvm-*) + shopt -u nullglob + if ((${#llvm_roots[@]})); then + while IFS= read -r root; do + if livekit_select_linux_clang_pair "${root}/bin/clang" "${root}/bin/clang++"; then + break + fi + done < <(printf '%s\n' "${llvm_roots[@]}" | sort -Vr) + fi + + if [[ -z "${CC:-}" ]]; then + for ((version = 40; version >= 21; --version)); do + if livekit_select_linux_clang_pair "clang-${version}" "clang++-${version}"; then + break + fi + done + fi + + if [[ -z "${CC:-}" ]] && ! livekit_select_linux_clang_pair "clang" "clang++"; then + echo "ERROR: Linux builds require clang/clang++ 21+ and libclang." >&2 + echo "Ubuntu 22.04 and 24.04 distro clang versions are too old." >&2 + echo "Install clang-21 from apt.llvm.org or set LLVM_ROOT to a compatible LLVM installation." >&2 + return 1 + fi + fi + + echo "==> Linux compiler: $("${CXX}" --version | awk 'NR == 1 { print; exit }')" + echo "==> CC=${CC}" + echo "==> CXX=${CXX}" + echo "==> LIBCLANG_PATH=${LIBCLANG_PATH}" +} + +if livekit_configure_linux_toolchain; then + livekit_setup_status=0 +else + livekit_setup_status=$? +fi + +unset -f livekit_compiler_clang_major +unset -f livekit_resolve_compiler +unset -f livekit_find_libclang_dir +unset -f livekit_select_linux_clang_pair +unset -f livekit_configure_linux_toolchain + +if ((livekit_setup_status != 0)); then + unset livekit_setup_status + return 1 +fi +unset livekit_setup_status From 9f41d974da826b15cb6490de4fedfcd4548571c7 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 28 Oct 2026 13:11:52 -0700 Subject: [PATCH 03/10] Fix Linux CI libclang path handling Co-authored-by: Cursor --- .github/workflows/builds.yml | 3 --- .github/workflows/make-release.yml | 3 --- .github/workflows/tests.yml | 9 ++------- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index a743c725..1ce0230e 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -157,9 +157,6 @@ jobs: run: | echo "CXXFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" echo "CFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" - LLVM_ROOT="$(dirname "${CXX}")/.." - test -f "${LLVM_ROOT}/lib/libclang.so" - echo "LIBCLANG_PATH=${LLVM_ROOT}/lib" >> "$GITHUB_ENV" # ---------- Build ---------- - name: Build standard SDK diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index bb901991..7b274637 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -165,9 +165,6 @@ jobs: run: | echo "CXXFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" echo "CFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" - LLVM_ROOT="$(dirname "${CXX}")/.." - test -f "${LLVM_ROOT}/lib/libclang.so" - echo "LIBCLANG_PATH=${LLVM_ROOT}/lib" >> "$GITHUB_ENV" # ---------- Build both variants in the same CMake tree ---------- - name: Build standard SDK diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cbe59d64..4306363e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -295,9 +295,6 @@ jobs: run: | echo "CXXFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" echo "CFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" - LLVM_ROOT="$(dirname "${CXX}")/.." - test -f "${LLVM_ROOT}/lib/libclang.so" - echo "LIBCLANG_PATH=${LLVM_ROOT}/lib" >> "$GITHUB_ENV" - name: Configure Unix crash diagnostics if: runner.os != 'Windows' @@ -585,11 +582,9 @@ jobs: # ---------- Build environment setup ---------- - name: Set build environment run: | - LLVM_ROOT="$(dirname "${CXX}")/.." - test -f "${LLVM_ROOT}/lib/libclang.so" - LLVM_COV="${LLVM_ROOT}/bin/llvm-cov" + test -d "${LIBCLANG_PATH}" + LLVM_COV="$(dirname "$(readlink -f "${CXX}")")/llvm-cov" test -x "${LLVM_COV}" - echo "LIBCLANG_PATH=${LLVM_ROOT}/lib" >> "$GITHUB_ENV" echo "GCOV_EXECUTABLE=${LLVM_COV} gcov" >> "$GITHUB_ENV" # ---------- Configure with upstream preset + coverage flag overrides ---------- From 14b2ef1a29674c52f986497e5211751848fd73bd Mon Sep 17 00:00:00 2001 From: Alan George Date: Fri, 30 Oct 2026 10:47:29 -0700 Subject: [PATCH 04/10] Update cmake version --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- AGENTS.md | 2 +- CMakeLists.txt | 2 +- CMakePresets.json | 2 +- README.md | 2 +- benchmarks/data_track_throughput/CMakeLists.txt | 2 +- benchmarks/data_track_throughput/README.md | 2 +- docs/building.md | 5 ++++- src/tests/CMakeLists.txt | 2 +- src/tests/packaging/CMakeLists.txt | 2 +- 10 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 898a1a88..84037b2b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -42,7 +42,7 @@ body: validations: { required: true } attributes: label: CMake Version - description: Output of `cmake --version` (must be ≥ 3.20). + description: Output of `cmake --version` (must be ≥ 3.25). placeholder: "3.28.1" - type: dropdown id: consumption diff --git a/AGENTS.md b/AGENTS.md index ed098da8..564b9b7d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -145,7 +145,7 @@ the source tree. Track capture Rust sources and shaders in build dependencies. The build scripts pass an explicit job count to `cmake --build --parallel`. Set `CMAKE_BUILD_PARALLEL_LEVEL` to override the default detected logical CPU count. -**Requirements:** CMake 3.20+, C++17, Rust toolchain (cargo), protoc. Linux +**Requirements:** CMake 3.25+, C++17, Rust toolchain (cargo), protoc. Linux source builds require clang/clang++ 21+ and a matching libclang runtime; `build.sh` sources `scripts/setup-linux-toolchain.sh` to discover versioned installations and validate the toolchain. Source that script before direct diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fa98a90..00d4bd32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25) if(NOT DEFINED LIVEKIT_VERSION OR LIVEKIT_VERSION STREQUAL "") set(LIVEKIT_VERSION "0.0.0") diff --git a/CMakePresets.json b/CMakePresets.json index a300698b..df267d8b 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -2,7 +2,7 @@ "version": 6, "cmakeMinimumRequired": { "major": 3, - "minor": 20, + "minor": 25, "patch": 0 }, "configurePresets": [ diff --git a/README.md b/README.md index dbd68fd2..243e1d3a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Use this SDK to add realtime video, audio and data features to your C++ app. By ## Using the SDK -[CMake](https://cmake.org/) (≥ 3.20) is used for building the SDK itself and for consuming it as a library. The +[CMake](https://cmake.org/) (≥ 3.25) is used for building the SDK itself and for consuming it as a library. The [**cpp-example-collection**](https://github.com/livekit-examples/cpp-example-collection) contains a reference [LiveKitSDK.cmake](https://github.com/livekit-examples/cpp-example-collection/blob/main/cmake/LiveKitSDK.cmake) which downloads the latest stable release at CMake configure time. See [docs/building.md](docs/building.md) for additional documentation on integrating LiveKit into your project. diff --git a/benchmarks/data_track_throughput/CMakeLists.txt b/benchmarks/data_track_throughput/CMakeLists.txt index 407ea02f..28cb8968 100644 --- a/benchmarks/data_track_throughput/CMakeLists.txt +++ b/benchmarks/data_track_throughput/CMakeLists.txt @@ -4,7 +4,7 @@ # All paths are relative to CMAKE_CURRENT_SOURCE_DIR so this directory # can be moved or renamed freely. -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25) project(DataTrackThroughput LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) diff --git a/benchmarks/data_track_throughput/README.md b/benchmarks/data_track_throughput/README.md index 26a55066..b761f579 100644 --- a/benchmarks/data_track_throughput/README.md +++ b/benchmarks/data_track_throughput/README.md @@ -125,7 +125,7 @@ One row per received frame. Raw observation data only: ## Prerequisites -- CMake 3.20+ +- CMake 3.25+ - C++17 compiler - The LiveKit C++ SDK, built and installed (see below) diff --git a/docs/building.md b/docs/building.md index 635a05f6..766ea597 100644 --- a/docs/building.md +++ b/docs/building.md @@ -8,7 +8,7 @@ CMake/vcpkg flows. ### Common to all platforms -- **CMake** ≥ 3.20 +- **CMake** ≥ 3.25 - **Rust / Cargo** — latest stable toolchain (for building the Rust FFI layer). Install via [rustup](https://rustup.rs/). - **Git/Submodules/LFS** — required to clone submodules and to pull test assets. @@ -106,6 +106,9 @@ sudo apt update && sudo apt install -y \ libglib2.0-dev libssl-dev libcurl4-openssl-dev \ wget ca-certificates gnupg lsb-release +# Ubuntu 22.04 provides CMake 3.22. Install CMake 3.25+ separately +# (for example, from https://apt.kitware.com/) before building. + # Ubuntu 22.04 ships clang 14 and Ubuntu 24.04 ships clang 18. Install # clang 21 and libclang from apt.llvm.org. sudo install -m 0755 -d /etc/apt/keyrings diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index c169fa1f..0abe5f55 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25) # ============================================================================ # Google Test Setup via FetchContent diff --git a/src/tests/packaging/CMakeLists.txt b/src/tests/packaging/CMakeLists.txt index 6573d786..c76f9768 100644 --- a/src/tests/packaging/CMakeLists.txt +++ b/src/tests/packaging/CMakeLists.txt @@ -9,7 +9,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25) project(livekit_packaging_tests LANGUAGES CXX) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 17) From a9b98b0efeff1787041c427ed4f407caa997ac28 Mon Sep 17 00:00:00 2001 From: Alan George Date: Fri, 30 Oct 2026 11:13:47 -0700 Subject: [PATCH 05/10] Add dependency table --- AGENTS.md | 2 + docs/building.md | 153 ++++++++++++++++++++++++++++------------------- 2 files changed, 94 insertions(+), 61 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 564b9b7d..e4bbd024 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -366,6 +366,8 @@ malformed table, missing `@param` on a documented function, …) fails the build | GStreamer | Capture builds / runtime | System libraries and plugins; accessed through Rust; not redistributed in SDK bundles | | Google Test | Test only | FetchContent in `src/tests/CMakeLists.txt` | +When a dependency is added, removed, upgraded, or used differently, update the +Dependencies table in `docs/building.md` in the same change. When adding a new private/vendored dependency to this table, also add a forbidden symbol pattern for it to `.github/scripts/check_no_private_symbols.py` so the "Symbol leak check" diff --git a/docs/building.md b/docs/building.md index 766ea597..83a8738a 100644 --- a/docs/building.md +++ b/docs/building.md @@ -6,14 +6,14 @@ CMake/vcpkg flows. ## Prerequisites -### Common to all platforms +### Core Tools - **CMake** ≥ 3.25 - **Rust / Cargo** — latest stable toolchain (for building the Rust FFI layer). Install via [rustup](https://rustup.rs/). - **Git/Submodules/LFS** — required to clone submodules and to pull test assets. -### Platform-specific toolchains +### Compilers | Platform | Compiler | Package manager | |----------|----------|-----------------| @@ -21,73 +21,40 @@ CMake/vcpkg flows. | macOS | Xcode 12+ Apple Clang (macOS 12.3+ for ScreenCaptureKit) | Homebrew | | Windows | Visual Studio 2019+ (MSBuild or Ninja) | vcpkg (see below) | - +### Dependencies -### Additional capture dependencies +These dependencies are linked by the SDK, used directly by its production C++ +sources, or support optional repository targets. -GStreamer is required only when the selected sources include `gstreamer`. -This includes `--capture` / `--capture=all` and release `-capture` bundles, -which enable all three sources. Standard SDK builds and builds selecting only -`pattern`, `clock`, or both do not require GStreamer. +| Dependency | Platform | Version | Source | How it is used | +|------------|----------|---------|--------|----------------| +| `client-sdk-rust` / `livekit_ffi` | All | `livekit_ffi` 0.13.3; pinned commit | Git submodule | Owns WebRTC, networking, media, and most business logic. The C++ SDK calls its C ABI and exchanges Protobuf FFI requests, responses, and events. Its shared library ships beside `liblivekit`. | +| Protobuf | All | 25.3 vendored; 5.29.5+ on Windows | Vendored / vcpkg | Generates and implements the FFI message types used throughout the C++ wrapper for rooms, tracks, streams, frames, statistics, RPC, encryption, and capture. | +| Abseil | All | 20240116.2 vendored; vcpkg-managed on Windows | Vendored / vcpkg | Supports the Protobuf build. Production C++ sources do not call Abseil APIs directly. | +| spdlog | All | 1.15.1 vendored; vcpkg-managed on Windows | Vendored / vcpkg | Implements the internal `LK_LOG_*` macros, default stderr logger, log-level filtering, and the public log callback adapter. | +| nlohmann/json | All | 3.12.0 vendored; vcpkg-managed on Windows | Vendored / vcpkg | Parses token-endpoint JSON responses and JWT payload claims. | +| Chromium trace-event code | All | Pinned source snapshot | Vendored source | Implements trace-event macros used by the production tracing API. Benchmark utilities consume the resulting Chromium-format traces, but Chromium is not a benchmark library dependency. | +| libcurl | Linux | System-provided | System library | Implements HTTP requests made by `TokenSource`. | +| OpenSSL | Linux | System-provided | System library | Linked into `liblivekit`. Current production C++ sources do not call OpenSSL APIs directly. | +| libcurl | Mac | System-provided | System library | Implements HTTP requests made by `TokenSource`. | +| Apple system frameworks | Mac | OS-provided | System frameworks | Supplies the audio, video, graphics, security, UI, and ScreenCaptureKit frameworks required by the media stack. | +| WinHTTP | Windows | OS-provided | System library | Implements HTTP requests made by `TokenSource`. | -For builds that include `gstreamer`, install GStreamer development libraries -at build time and GStreamer libraries at runtime. The SDK does not redistribute -these libraries or plugins. Install the runtime plugins required by your -pipeline too. Pattern and clock sources need a compatible GPU adapter at runtime. +### Capture Dependencies -**macOS:** Install both the official universal runtime and development packages -from the [GStreamer downloads page](https://gstreamer.freedesktop.org/download/#macos). -These packages support both x86_64 and arm64. Configure the framework paths: +| Dependency | Platform | Version | Source | How it is used | +|------------|----------|---------|--------|----------------| +| GStreamer | All | Platform-provided | System library | Used by the Rust `capture-gstreamer` backend. The C++ capture API reaches it through the FFI; GStreamer headers are not exposed publicly. | -```bash -export PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/bin:$PATH" -export PKG_CONFIG_PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" -``` +### Test Dependencies -Use one GStreamer installation method per machine to keep libraries and plugins -consistent. - -**Ubuntu / Debian:** Install the development packages and runtime plugins: +| Dependency | Platform | Version | Source | How it is used | +|------------|----------|---------|--------|----------------| +| GoogleTest | All | 1.14.0 | Vendored | Implements unit, integration, and stress test executables. It is not linked into SDK bundles. | -```bash -sudo apt install -y pkg-config libunwind-dev \ - libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - gstreamer1.0-plugins-base gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav -``` - -**Windows:** Install the MSVC x86_64 runtime and development components from the -[GStreamer downloads page](https://gstreamer.freedesktop.org/download/#windows). -Add the installation's `bin` directory to `PATH` and its `lib/pkgconfig` -directory to `PKG_CONFIG_PATH`. - -For GStreamer builds, development files must be discoverable through -`pkg-config`. You can verify -that they are available with: - -```bash -pkg-config --modversion gstreamer-1.0 gstreamer-app-1.0 -``` - -## Clone the repository - -The SDK uses recursive submodules for the [`Rust core`](https://github.com/livekit/rust-sdks), shared [C++ tooling](https://github.com/livekit/cpp-tools), and -the [C++ example collection](https://github.com/livekit-examples/cpp-example-collection). - -```bash -# Option 1: clone with submodules in one step -git clone --recurse-submodules https://github.com/livekit/client-sdk-cpp.git - -# Option 2: clone first, then initialize submodules -git clone https://github.com/livekit/client-sdk-cpp.git -cd client-sdk-cpp -git submodule update --init --recursive - -# Pull the media asset required by the test suite: -git lfs pull -``` + -## Recommended setup +## Installation This section outlines the recommended dependency/environmental setup for each supported platform. @@ -152,6 +119,24 @@ $env:VCPKG_ROOT = "$PWD\vcpkg" CMake's vcpkg manifest mode (below) reads `vcpkg.json` and installs the rest automatically the first time you configure. +## Clone the repository + +The SDK uses recursive submodules for the [`Rust core`](https://github.com/livekit/rust-sdks), shared [C++ tooling](https://github.com/livekit/cpp-tools), and +the [C++ example collection](https://github.com/livekit-examples/cpp-example-collection). + +```bash +# Option 1: clone with submodules in one step +git clone --recurse-submodules https://github.com/livekit/client-sdk-cpp.git + +# Option 2: clone first, then initialize submodules +git clone https://github.com/livekit/client-sdk-cpp.git +cd client-sdk-cpp +git submodule update --init --recursive + +# Pull the media asset required by the test suite: +git lfs pull +``` + ## Build scripts (recommended) The repo ships with `build.sh` (Linux/macOS) and `build.cmd` (Windows) that @@ -180,6 +165,52 @@ wrap the right CMake preset for your platform and pick sensible defaults. # ... same suffixes as build.sh ``` +### GStreamer Installation (LiveKit Capture) + +GStreamer is required only when the selected sources include `gstreamer`. +This includes `--capture` / `--capture=all` and release `-capture` bundles, +which enable all three sources. Standard SDK builds and builds selecting only +`pattern`, `clock`, or both do not require GStreamer. + +For builds that include `gstreamer`, install GStreamer development libraries +at build time and GStreamer libraries at runtime. The SDK does not redistribute +these libraries or plugins. Install the runtime plugins required by your +pipeline too. Pattern and clock sources need a compatible GPU adapter at runtime. + +**macOS:** Install both the official universal runtime and development packages +from the [GStreamer downloads page](https://gstreamer.freedesktop.org/download/#macos). +These packages support both x86_64 and arm64. Configure the framework paths: + +```bash +export PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/bin:$PATH" +export PKG_CONFIG_PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" +``` + +Use one GStreamer installation method per machine to keep libraries and plugins +consistent. + +**Ubuntu / Debian:** Install the development packages and runtime plugins: + +```bash +sudo apt install -y pkg-config libunwind-dev \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + gstreamer1.0-plugins-base gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav +``` + +**Windows:** Install the MSVC x86_64 runtime and development components from the +[GStreamer downloads page](https://gstreamer.freedesktop.org/download/#windows). +Add the installation's `bin` directory to `PATH` and its `lib/pkgconfig` +directory to `PKG_CONFIG_PATH`. + +For GStreamer builds, development files must be discoverable through +`pkg-config`. You can verify +that they are available with: + +```bash +pkg-config --modversion gstreamer-1.0 gstreamer-app-1.0 +``` + ### Create an SDK bundle To create an installable SDK bundle with public headers, runtime libraries, and From 6cb4a4a17e9adccf21cf149cdebb1c3f398ac40b Mon Sep 17 00:00:00 2001 From: Alan George Date: Fri, 30 Oct 2026 11:19:58 -0700 Subject: [PATCH 06/10] Fix docs --- docs/building.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/building.md b/docs/building.md index 83a8738a..2d3d735a 100644 --- a/docs/building.md +++ b/docs/building.md @@ -516,6 +516,8 @@ See [Capture sources](capture-sources.md) for dependencies and usage. ## Appendix + + ### Clang compiler usage on Linux The SDK compiler requirement moved from GCC to Clang 21 when the core Rust SDK From 9e995cf2293a121568d6758c0f09420bd102bc05 Mon Sep 17 00:00:00 2001 From: Alan George Date: Sun, 1 Nov 2026 13:44:12 -0800 Subject: [PATCH 07/10] Resolve devin.ai red comment --- build.sh | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index ba87de2c..254be046 100755 --- a/build.sh +++ b/build.sh @@ -116,6 +116,22 @@ validate_capture_value() { done } +canonicalize_path() { + local path="$1" + local resolved directory + + if resolved="$(readlink -f "${path}" 2>/dev/null)" && [[ -n "${resolved}" ]]; then + printf '%s\n' "${resolved}" + return + fi + + if directory="$(cd "$(dirname "${path}")" 2>/dev/null && pwd -P)"; then + printf '%s/%s\n' "${directory}" "$(basename "${path}")" + else + printf '%s\n' "${path}" + fi +} + parse_opts() { shift || true while [[ $# -gt 0 ]]; do @@ -196,16 +212,16 @@ parse_opts() { } configure() { - if [[ "${OS_TYPE}" == "linux" && -f "${BUILD_DIR}/CMakeCache.txt" ]]; then + if [[ -f "${BUILD_DIR}/CMakeCache.txt" ]]; then local cached_cc cached_cxx selected_cc selected_cxx cached_cc="$(awk -F= '$1 == "CMAKE_C_COMPILER:FILEPATH" { print $2; exit }' \ "${BUILD_DIR}/CMakeCache.txt")" cached_cxx="$(awk -F= '$1 == "CMAKE_CXX_COMPILER:FILEPATH" { print $2; exit }' \ "${BUILD_DIR}/CMakeCache.txt")" - selected_cc="$(readlink -f "${CC}")" - selected_cxx="$(readlink -f "${CXX}")" - if [[ -n "${cached_cc}" && "$(readlink -f "${cached_cc}")" != "${selected_cc}" ]] \ - || [[ -n "${cached_cxx}" && "$(readlink -f "${cached_cxx}")" != "${selected_cxx}" ]]; then + selected_cc="$(canonicalize_path "${CC}")" + selected_cxx="$(canonicalize_path "${CXX}")" + if [[ -n "${cached_cc}" && "$(canonicalize_path "${cached_cc}")" != "${selected_cc}" ]] \ + || [[ -n "${cached_cxx}" && "$(canonicalize_path "${cached_cxx}")" != "${selected_cxx}" ]]; then echo "ERROR: ${BUILD_DIR} was configured with a different compiler:" >&2 echo " cached CC=${cached_cc}" >&2 echo " cached CXX=${cached_cxx}" >&2 From ccd9d6c5b55a66af692f5b35168a0498bc1686cf Mon Sep 17 00:00:00 2001 From: Alan George Date: Sun, 1 Nov 2026 13:47:51 -0800 Subject: [PATCH 08/10] Fix remaining devin.ai comments --- .github/workflows/ci.yml | 2 ++ scripts/setup-linux-toolchain.sh | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c98caaf..e606e21d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,7 @@ jobs: - CMakePresets.json - build* - .build* + - scripts/setup-linux-toolchain.sh - vcpkg.json - .github/workflows/ci.yml - .github/workflows/builds.yml @@ -68,6 +69,7 @@ jobs: - cmake/** - scripts/set-test-tokens.sh - scripts/run-with-backtrace.sh + - scripts/setup-linux-toolchain.sh - CMakeLists.txt - CMakePresets.json - build* diff --git a/scripts/setup-linux-toolchain.sh b/scripts/setup-linux-toolchain.sh index c4372576..2048afd6 100755 --- a/scripts/setup-linux-toolchain.sh +++ b/scripts/setup-linux-toolchain.sh @@ -66,7 +66,7 @@ livekit_find_libclang_dir() { livekit_select_linux_clang_pair() { local candidate_cc="$1" local candidate_cxx="$2" - local resolved_cc resolved_cxx cc_major cxx_major llvm_root libclang_dir + local resolved_cc resolved_cxx real_cxx cc_major cxx_major llvm_root libclang_dir resolved_cc="$(livekit_resolve_compiler "${candidate_cc}")" || return 1 resolved_cxx="$(livekit_resolve_compiler "${candidate_cxx}")" || return 1 @@ -76,7 +76,8 @@ livekit_select_linux_clang_pair() { [[ -n "${cc_major}" && "${cc_major}" == "${cxx_major}" ]] || return 1 ((cc_major >= 21)) || return 1 - llvm_root="$(cd "$(dirname "${resolved_cxx}")/.." && pwd -P)" + real_cxx="$(readlink -f "${resolved_cxx}")" || return 1 + llvm_root="$(cd "$(dirname "${real_cxx}")/.." && pwd -P)" libclang_dir="$(livekit_find_libclang_dir "${llvm_root}" "${cxx_major}")" || return 1 CC="${resolved_cc}" From 5441bdbdbcd5ea62b46ca98b563af58e44f37f3f Mon Sep 17 00:00:00 2001 From: Alan George Date: Tue, 3 Nov 2026 06:08:03 -0800 Subject: [PATCH 09/10] Fix link position --- docs/building.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/building.md b/docs/building.md index 2d3d735a..a5ee4d2a 100644 --- a/docs/building.md +++ b/docs/building.md @@ -52,8 +52,6 @@ sources, or support optional repository targets. |------------|----------|---------|--------|----------------| | GoogleTest | All | 1.14.0 | Vendored | Implements unit, integration, and stress test executables. It is not linked into SDK bundles. | - - ## Installation This section outlines the recommended dependency/environmental setup for @@ -165,6 +163,8 @@ wrap the right CMake preset for your platform and pick sensible defaults. # ... same suffixes as build.sh ``` + + ### GStreamer Installation (LiveKit Capture) GStreamer is required only when the selected sources include `gstreamer`. From 8999525ecbf77a091e1eb63f06463bd4e7292ddb Mon Sep 17 00:00:00 2001 From: Alan George Date: Tue, 3 Nov 2026 10:58:14 -0800 Subject: [PATCH 10/10] PR feedback --- docs/building.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/building.md b/docs/building.md index a5ee4d2a..823f48e4 100644 --- a/docs/building.md +++ b/docs/building.md @@ -34,9 +34,8 @@ sources, or support optional repository targets. | spdlog | All | 1.15.1 vendored; vcpkg-managed on Windows | Vendored / vcpkg | Implements the internal `LK_LOG_*` macros, default stderr logger, log-level filtering, and the public log callback adapter. | | nlohmann/json | All | 3.12.0 vendored; vcpkg-managed on Windows | Vendored / vcpkg | Parses token-endpoint JSON responses and JWT payload claims. | | Chromium trace-event code | All | Pinned source snapshot | Vendored source | Implements trace-event macros used by the production tracing API. Benchmark utilities consume the resulting Chromium-format traces, but Chromium is not a benchmark library dependency. | -| libcurl | Linux | System-provided | System library | Implements HTTP requests made by `TokenSource`. | +| libcurl | Mac, Linux | System-provided | System library | Implements HTTP requests made by `TokenSource`. | | OpenSSL | Linux | System-provided | System library | Linked into `liblivekit`. Current production C++ sources do not call OpenSSL APIs directly. | -| libcurl | Mac | System-provided | System library | Implements HTTP requests made by `TokenSource`. | | Apple system frameworks | Mac | OS-provided | System frameworks | Supplies the audio, video, graphics, security, UI, and ScreenCaptureKit frameworks required by the media stack. | | WinHTTP | Windows | OS-provided | System library | Implements HTTP requests made by `TokenSource`. |