From 46a4fab6a9b938b9a097e5cab0c306c28b444732 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 9 Sep 2026 16:21:06 -0600 Subject: [PATCH 1/7] Better uniffi --- CMakeLists.txt | 7 ++ client-sdk-rust | 2 +- cmake/uniffi_cpp.cmake | 115 +++++++++++++++++++++++++++++++++ src/tests/CMakeLists.txt | 2 + src/tests/unit/test_uniffi.cpp | 32 +++++++++ 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 cmake/uniffi_cpp.cmake create mode 100644 src/tests/unit/test_uniffi.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c7b244c..603694d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,6 +269,10 @@ endif() message(STATUS \"[run_cargo.cmake] CFG=\${CFG} CARGO=\${CARGO} PROTOC=\${PROTOC_PATH}\") set(ENV{PROTOC} \"\${PROTOC_PATH}\") +if(DEFINED CARGO_TARGET_DIR AND NOT CARGO_TARGET_DIR STREQUAL \"\") + set(ENV{CARGO_TARGET_DIR} \"\${CARGO_TARGET_DIR}\") +endif() + if(DEFINED GCC_LIB_DIR AND NOT GCC_LIB_DIR STREQUAL \"\") set(ENV{RUSTFLAGS} \"-L \${GCC_LIB_DIR} \$ENV{RUSTFLAGS}\") set(ENV{LD_LIBRARY_PATH} \"\${GCC_LIB_DIR}:\$ENV{LD_LIBRARY_PATH}\") @@ -368,6 +372,8 @@ add_custom_target(build_rust_ffi DEPENDS "${RUST_LIB_DEBUG}" "${RUST_LIB_RELEASE}" ) +include(uniffi_cpp) + # Note: protozero_plugin.o removal is no longer needed since we use dynamic libraries on Unix add_library(livekit SHARED @@ -466,6 +472,7 @@ target_link_libraries(livekit PRIVATE spdlog::spdlog nlohmann_json::nlohmann_json + livekit_uniffi_cpp livekit_ffi ${LIVEKIT_PROTOBUF_TARGET} ) diff --git a/client-sdk-rust b/client-sdk-rust index 8066415f..e7bc2c42 160000 --- a/client-sdk-rust +++ b/client-sdk-rust @@ -1 +1 @@ -Subproject commit 8066415f8faa09a0ec0a6643e6cfdaa825167c65 +Subproject commit e7bc2c42caf0d1bc321a1a193cf960b67505d87b diff --git a/cmake/uniffi_cpp.cmake b/cmake/uniffi_cpp.cmake new file mode 100644 index 00000000..f655d511 --- /dev/null +++ b/cmake/uniffi_cpp.cmake @@ -0,0 +1,115 @@ +# 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. + +set(LIVEKIT_UNIFFI_CPP_GENERATED_DIR "${LIVEKIT_BINARY_DIR}/generated/uniffi") +set(LIVEKIT_UNIFFI_CPP_SOURCE + "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}/livekit_ffi.cpp") +set(LIVEKIT_UNIFFI_CPP_HEADER + "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}/livekit_ffi.hpp") +set(LIVEKIT_UNIFFI_CPP_SCAFFOLDING_HEADER + "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}/livekit_ffi_scaffolding.hpp") + +# Generate from an unstripped host library. Release Linux builds strip the +# UniFFI metadata symbols, while generated C++ source is platform-independent. +set(LIVEKIT_UNIFFI_METADATA_TARGET_DIR + "${RUST_ROOT}/target/uniffi-cpp-metadata") +if(WIN32) + set(LIVEKIT_UNIFFI_METADATA_LIBRARY + "${LIVEKIT_UNIFFI_METADATA_TARGET_DIR}/debug/livekit_ffi.dll") +elseif(APPLE) + set(LIVEKIT_UNIFFI_METADATA_LIBRARY + "${LIVEKIT_UNIFFI_METADATA_TARGET_DIR}/debug/liblivekit_ffi.dylib") +else() + set(LIVEKIT_UNIFFI_METADATA_LIBRARY + "${LIVEKIT_UNIFFI_METADATA_TARGET_DIR}/debug/liblivekit_ffi.so") +endif() + +file(GLOB_RECURSE LIVEKIT_UNIFFI_RUST_SOURCES CONFIGURE_DEPENDS + "${RUST_ROOT}/livekit-ffi/src/*.rs" + "${RUST_ROOT}/livekit-ffi/Cargo.toml" +) +list(APPEND LIVEKIT_UNIFFI_RUST_SOURCES + "${RUST_ROOT}/Cargo.toml" + "${RUST_ROOT}/Cargo.lock" + "${RUST_ROOT}/rust-toolchain.toml" +) + +file(GLOB_RECURSE LIVEKIT_UNIFFI_BINDGEN_SOURCES CONFIGURE_DEPENDS + "${RUST_ROOT}/tools/bindgens/src/*.rs" + "${RUST_ROOT}/tools/bindgens/Cargo.toml" +) + +add_custom_command( + OUTPUT "${LIVEKIT_UNIFFI_METADATA_LIBRARY}" + COMMAND "${CMAKE_COMMAND}" + -DCFG=Debug + -DRUST_ROOT=${RUST_ROOT} + -DCARGO=${CARGO_EXECUTABLE} + -DPROTOC_PATH=${Protobuf_PROTOC_EXECUTABLE} + -DGCC_LIB_DIR=${GCC_LIB_DIR} + -DCARGO_TARGET_DIR=${LIVEKIT_UNIFFI_METADATA_TARGET_DIR} + -P "${RUN_CARGO_SCRIPT}" + WORKING_DIRECTORY "${RUST_ROOT}" + DEPENDS ${LIVEKIT_UNIFFI_RUST_SOURCES} + COMMENT "Building unstripped livekit-ffi metadata library" + VERBATIM +) +add_custom_target(build_livekit_ffi_metadata + DEPENDS "${LIVEKIT_UNIFFI_METADATA_LIBRARY}") + +add_custom_command( + OUTPUT + "${LIVEKIT_UNIFFI_CPP_SOURCE}" + "${LIVEKIT_UNIFFI_CPP_HEADER}" + "${LIVEKIT_UNIFFI_CPP_SCAFFOLDING_HEADER}" + COMMAND "${CMAKE_COMMAND}" -E make_directory + "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}" + COMMAND "${CMAKE_COMMAND}" -E env + "CARGO_TARGET_DIR=${RUST_ROOT}/target/bindgens" + "${CARGO_EXECUTABLE}" run --locked + --package bindgens + --bin uniffi-bindgen-cpp + -- + --library "${LIVEKIT_UNIFFI_METADATA_LIBRARY}" + --out-dir "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}" + WORKING_DIRECTORY "${RUST_ROOT}" + DEPENDS + build_livekit_ffi_metadata + ${LIVEKIT_UNIFFI_RUST_SOURCES} + ${LIVEKIT_UNIFFI_BINDGEN_SOURCES} + COMMENT "Generating UniFFI C++ bindings" + VERBATIM +) +add_custom_target(generate_livekit_ffi_uniffi_cpp + DEPENDS + "${LIVEKIT_UNIFFI_CPP_SOURCE}" + "${LIVEKIT_UNIFFI_CPP_HEADER}" + "${LIVEKIT_UNIFFI_CPP_SCAFFOLDING_HEADER}" +) + +set_source_files_properties( + "${LIVEKIT_UNIFFI_CPP_SOURCE}" + "${LIVEKIT_UNIFFI_CPP_HEADER}" + "${LIVEKIT_UNIFFI_CPP_SCAFFOLDING_HEADER}" + PROPERTIES GENERATED TRUE +) + +add_library(livekit_uniffi_cpp OBJECT + "${LIVEKIT_UNIFFI_CPP_SOURCE}" +) +add_dependencies(livekit_uniffi_cpp generate_livekit_ffi_uniffi_cpp) +target_include_directories(livekit_uniffi_cpp + PUBLIC "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}" +) +target_link_libraries(livekit_uniffi_cpp PRIVATE livekit_ffi) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 9583af73..0544ef0a 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -89,6 +89,8 @@ if(UNIT_TEST_SOURCES) target_link_libraries(livekit_unit_tests PRIVATE livekit + livekit_uniffi_cpp + livekit_ffi spdlog::spdlog ${LIVEKIT_PROTOBUF_TARGET} GTest::gtest_main diff --git a/src/tests/unit/test_uniffi.cpp b/src/tests/unit/test_uniffi.cpp new file mode 100644 index 00000000..a8067783 --- /dev/null +++ b/src/tests/unit/test_uniffi.cpp @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include + +#include + +namespace livekit { +namespace { + +TEST(UniFfiTest, BuildVersion) { + const auto version = livekit_ffi::build_version(); + std::cout << "build_version: " << version << std::endl; + EXPECT_FALSE(version.empty()); + EXPECT_NE(version, "unknown"); +} + +} // namespace +} // namespace livekit From f916cf2367cbb5e70176216b8d926c9ec0eddf12 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 9 Sep 2026 17:16:11 -0600 Subject: [PATCH 2/7] Build order --- cmake/uniffi_cpp.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/uniffi_cpp.cmake b/cmake/uniffi_cpp.cmake index f655d511..57c553bd 100644 --- a/cmake/uniffi_cpp.cmake +++ b/cmake/uniffi_cpp.cmake @@ -67,6 +67,9 @@ add_custom_command( ) add_custom_target(build_livekit_ffi_metadata DEPENDS "${LIVEKIT_UNIFFI_METADATA_LIBRARY}") +# Both commands invoke rustup/Cargo and share toolchain state. Keep them +# serialized so fresh CI runners cannot race while installing the toolchain. +add_dependencies(build_livekit_ffi_metadata build_rust_ffi) add_custom_command( OUTPUT From 96d64da3aaf4eafebf919a12f5dbaff89fb5f903 Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 10 Sep 2026 08:56:36 -0600 Subject: [PATCH 3/7] maybe fix CI builds --- cmake/uniffi_cpp.cmake | 64 ++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/cmake/uniffi_cpp.cmake b/cmake/uniffi_cpp.cmake index 57c553bd..cb38fc6c 100644 --- a/cmake/uniffi_cpp.cmake +++ b/cmake/uniffi_cpp.cmake @@ -20,17 +20,13 @@ set(LIVEKIT_UNIFFI_CPP_HEADER set(LIVEKIT_UNIFFI_CPP_SCAFFOLDING_HEADER "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}/livekit_ffi_scaffolding.hpp") -# Generate from an unstripped host library. Release Linux builds strip the -# UniFFI metadata symbols, while generated C++ source is platform-independent. -set(LIVEKIT_UNIFFI_METADATA_TARGET_DIR - "${RUST_ROOT}/target/uniffi-cpp-metadata") -if(WIN32) - set(LIVEKIT_UNIFFI_METADATA_LIBRARY - "${LIVEKIT_UNIFFI_METADATA_TARGET_DIR}/debug/livekit_ffi.dll") -elseif(APPLE) - set(LIVEKIT_UNIFFI_METADATA_LIBRARY - "${LIVEKIT_UNIFFI_METADATA_TARGET_DIR}/debug/liblivekit_ffi.dylib") -else() +# Release Linux builds strip the UniFFI metadata symbols, so generate from a +# separate unstripped Debug library there. PE and Mach-O retain the metadata, +# allowing Windows and macOS to reuse the livekit-ffi library already built for +# the selected CMake configuration. +if(UNIX AND NOT APPLE) + set(LIVEKIT_UNIFFI_METADATA_TARGET_DIR + "${RUST_ROOT}/target/uniffi-cpp-metadata") set(LIVEKIT_UNIFFI_METADATA_LIBRARY "${LIVEKIT_UNIFFI_METADATA_TARGET_DIR}/debug/liblivekit_ffi.so") endif() @@ -50,25 +46,31 @@ file(GLOB_RECURSE LIVEKIT_UNIFFI_BINDGEN_SOURCES CONFIGURE_DEPENDS "${RUST_ROOT}/tools/bindgens/Cargo.toml" ) -add_custom_command( - OUTPUT "${LIVEKIT_UNIFFI_METADATA_LIBRARY}" - COMMAND "${CMAKE_COMMAND}" - -DCFG=Debug - -DRUST_ROOT=${RUST_ROOT} - -DCARGO=${CARGO_EXECUTABLE} - -DPROTOC_PATH=${Protobuf_PROTOC_EXECUTABLE} - -DGCC_LIB_DIR=${GCC_LIB_DIR} - -DCARGO_TARGET_DIR=${LIVEKIT_UNIFFI_METADATA_TARGET_DIR} - -P "${RUN_CARGO_SCRIPT}" - WORKING_DIRECTORY "${RUST_ROOT}" - DEPENDS ${LIVEKIT_UNIFFI_RUST_SOURCES} - COMMENT "Building unstripped livekit-ffi metadata library" - VERBATIM -) -add_custom_target(build_livekit_ffi_metadata - DEPENDS "${LIVEKIT_UNIFFI_METADATA_LIBRARY}") -# Both commands invoke rustup/Cargo and share toolchain state. Keep them -# serialized so fresh CI runners cannot race while installing the toolchain. +if(UNIX AND NOT APPLE) + add_custom_command( + OUTPUT "${LIVEKIT_UNIFFI_METADATA_LIBRARY}" + COMMAND "${CMAKE_COMMAND}" + -DCFG=Debug + -DRUST_ROOT=${RUST_ROOT} + -DCARGO=${CARGO_EXECUTABLE} + -DPROTOC_PATH=${Protobuf_PROTOC_EXECUTABLE} + -DGCC_LIB_DIR=${GCC_LIB_DIR} + -DCARGO_TARGET_DIR=${LIVEKIT_UNIFFI_METADATA_TARGET_DIR} + -P "${RUN_CARGO_SCRIPT}" + WORKING_DIRECTORY "${RUST_ROOT}" + DEPENDS ${LIVEKIT_UNIFFI_RUST_SOURCES} + COMMENT "Building unstripped livekit-ffi metadata library" + VERBATIM + ) + add_custom_target(build_livekit_ffi_metadata + DEPENDS "${LIVEKIT_UNIFFI_METADATA_LIBRARY}") +else() + set(LIVEKIT_UNIFFI_METADATA_LIBRARY "$") + add_custom_target(build_livekit_ffi_metadata) +endif() + +# Keep Cargo invocations serialized on fresh runners, and ensure the selected +# livekit-ffi library exists before it is inspected on Windows and macOS. add_dependencies(build_livekit_ffi_metadata build_rust_ffi) add_custom_command( @@ -80,6 +82,8 @@ add_custom_command( "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}" COMMAND "${CMAKE_COMMAND}" -E env "CARGO_TARGET_DIR=${RUST_ROOT}/target/bindgens" + "CARGO_ENCODED_RUSTFLAGS=" + "RUSTFLAGS=" "${CARGO_EXECUTABLE}" run --locked --package bindgens --bin uniffi-bindgen-cpp From 65cb23bd9bfcab4c5dcb080002e89e1ee748d57b Mon Sep 17 00:00:00 2001 From: Alan George Date: Mon, 14 Sep 2026 10:06:05 -0600 Subject: [PATCH 4/7] Move to adapter model --- CMakeLists.txt | 13 ++++++++++-- client-sdk-rust | 2 +- src/tests/CMakeLists.txt | 2 -- src/tests/unit/test_uniffi.cpp | 12 ++++++----- src/uniffi_bindgen_adapter.cpp | 31 +++++++++++++++++++++++++++ src/uniffi_bindgen_adapter.h | 38 ++++++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 src/uniffi_bindgen_adapter.cpp create mode 100644 src/uniffi_bindgen_adapter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b8d3116..7fe6943d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ set(FFI_PROTO_FILES ${FFI_PROTO_DIR}/track.proto ${FFI_PROTO_DIR}/video_frame.proto ${FFI_PROTO_DIR}/audio_frame.proto + ${FFI_PROTO_DIR}/capture.proto ${FFI_PROTO_DIR}/e2ee.proto ${FFI_PROTO_DIR}/stats.proto ${FFI_PROTO_DIR}/data_stream.proto @@ -407,6 +408,7 @@ add_library(livekit SHARED src/token_source_json.cpp src/token_source_jwt.cpp src/token_source_internal.h + src/uniffi_bindgen_adapter.cpp src/local_participant.cpp src/remote_participant.cpp src/stats.cpp @@ -451,7 +453,14 @@ if(UNIX AND NOT APPLE) endif() -target_sources(livekit PRIVATE $) +target_sources(livekit PRIVATE + $ + $ +) +set_source_files_properties( + ${LIVEKIT_ROOT_DIR}/src/uniffi_bindgen_adapter.cpp + PROPERTIES OBJECT_DEPENDS ${LIVEKIT_UNIFFI_CPP_HEADER} +) target_include_directories(livekit PUBLIC @@ -460,6 +469,7 @@ target_include_directories(livekit PRIVATE ${LIVEKIT_ROOT_DIR}/src ${LIVEKIT_ROOT_DIR}/src/trace + ${LIVEKIT_UNIFFI_CPP_GENERATED_DIR} ${LIVEKIT_PROTOBUF_DEP_INCLUDE_DIRS} ) @@ -473,7 +483,6 @@ target_link_libraries(livekit PRIVATE spdlog::spdlog nlohmann_json::nlohmann_json - livekit_uniffi_cpp livekit_ffi ${LIVEKIT_PROTOBUF_TARGET} ) diff --git a/client-sdk-rust b/client-sdk-rust index ae7899db..235ba5a9 160000 --- a/client-sdk-rust +++ b/client-sdk-rust @@ -1 +1 @@ -Subproject commit ae7899db4f2b950d1eeef2d101b53b100963f9e3 +Subproject commit 235ba5a9521a92774cc80afd80fd94185e0a6589 diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 0544ef0a..9583af73 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -89,8 +89,6 @@ if(UNIT_TEST_SOURCES) target_link_libraries(livekit_unit_tests PRIVATE livekit - livekit_uniffi_cpp - livekit_ffi spdlog::spdlog ${LIVEKIT_PROTOBUF_TARGET} GTest::gtest_main diff --git a/src/tests/unit/test_uniffi.cpp b/src/tests/unit/test_uniffi.cpp index a8067783..50c4adfb 100644 --- a/src/tests/unit/test_uniffi.cpp +++ b/src/tests/unit/test_uniffi.cpp @@ -16,16 +16,18 @@ #include -#include +#include "uniffi_bindgen_adapter.h" namespace livekit { namespace { TEST(UniFfiTest, BuildVersion) { - const auto version = livekit_ffi::build_version(); - std::cout << "build_version: " << version << std::endl; - EXPECT_FALSE(version.empty()); - EXPECT_NE(version, "unknown"); + const auto version = uniffiBindgenBuildVersion(); + + ASSERT_TRUE(version.has_value()) << "Generated UniFFI binding did not return a build version"; + + EXPECT_FALSE(version.value().empty()); + EXPECT_NE(version.value(), "unknown"); } } // namespace diff --git a/src/uniffi_bindgen_adapter.cpp b/src/uniffi_bindgen_adapter.cpp new file mode 100644 index 00000000..bcdc1b9a --- /dev/null +++ b/src/uniffi_bindgen_adapter.cpp @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#include "uniffi_bindgen_adapter.h" + +#include "livekit_ffi.hpp" + +namespace livekit { + +std::optional uniffiBindgenBuildVersion() { + auto version = livekit_ffi::build_version(); + if (version.empty() || version == "unknown") { + return std::nullopt; + } + return version; +} + +} // namespace livekit diff --git a/src/uniffi_bindgen_adapter.h b/src/uniffi_bindgen_adapter.h new file mode 100644 index 00000000..d3a56c94 --- /dev/null +++ b/src/uniffi_bindgen_adapter.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +/// +/// Note: This adapter is a temporary internal translation unit for exercising UniFFI +/// bindings. It will be removed when the represented UniFFI APIs are migrated to actual +/// SDK features. +/// + +#include "livekit/visibility.h" + +namespace livekit { + +/// @brief Gets the build version through the generated UniFFI binding. +/// +/// @return The generated binding's build version, or no value if it is invalid +/// or the binding call fails. +LIVEKIT_INTERNAL_API std::optional uniffiBindgenBuildVersion(); + +} // namespace livekit From c7250a7d564b9ead3b6ef8198d60aeb1720add7a Mon Sep 17 00:00:00 2001 From: Alan George Date: Mon, 14 Sep 2026 10:55:15 -0600 Subject: [PATCH 5/7] Devin.ai suggestions --- .github/scripts/check_no_private_symbols.py | 12 ++++++++++-- AGENTS.md | 5 +++-- build.cmd | 13 ++++--------- build.sh | 7 ++----- cmake/uniffi_cpp.cmake | 5 +++++ 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/.github/scripts/check_no_private_symbols.py b/.github/scripts/check_no_private_symbols.py index d5224be0..f73645f8 100755 --- a/.github/scripts/check_no_private_symbols.py +++ b/.github/scripts/check_no_private_symbols.py @@ -14,7 +14,7 @@ # limitations under the License. # """ -Verify that liblivekit's exported ABI does not leak private dependency symbols. +Verify that liblivekit's exported ABI does not leak private implementation symbols. The LiveKit SDK statically links several private dependencies (spdlog, fmt, google::protobuf, absl, nlohmann/json). When those symbols escape the dynamic symbol table @@ -23,6 +23,10 @@ rcl_logging_spdlog ABI-clashing with our vendored spdlog and crashing inside spdlog::pattern_formatter). +The generated UniFFI C++ bindings are also private implementation details. +Their generated API and runtime symbols must remain hidden behind the SDK's +public ABI. + This script lists exported defined symbols from the supplied shared library using the platform-appropriate tool and fails (exit code 1) if any of them match a forbidden pattern. @@ -53,6 +57,10 @@ "google::protobuf", "absl::", "nlohmann::", + # Generated UniFFI C++ binding API and runtime implementation. + "livekit_ffi::", + "uniffi::", + "uniffi_", ] MAX_REPORTED_LEAKS = 20 @@ -237,7 +245,7 @@ def main(argv: list[str]) -> int: "(set LIVEKIT_SYMBOL_CHECK_VERBOSE=1 to see all)") print( - "\nliblivekit must not re-export private dependency symbols.\n" + "\nliblivekit must not re-export private dependency or UniFFI implementation symbols.\n" "If you intentionally added a public symbol that triggered this, mark\n" "it with LIVEKIT_API in include/livekit/visibility.h and rebuild.\n" ) diff --git a/AGENTS.md b/AGENTS.md index 55da0430..45c875eb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -234,8 +234,9 @@ The exported ABI is enforced by `.github/scripts/check_no_private_symbols.py`, run from the `make-release.yml` "Symbol leak check" CI step so a leak blocks the release build itself (it does not run on regular pushes/PRs). The script fails if `nm`/`dumpbin` reports any exported symbol matching a forbidden -substring (currently `spdlog::`, `fmt::v`, `google::protobuf`, `absl::`). To -run it locally, point it at the built shared library: +substring (including private dependency namespaces and generated UniFFI +symbols such as `livekit_ffi::`, `uniffi::`, and `uniffi_`). To run it locally, +point it at the built shared library: ```bash python3 .github/scripts/check_no_private_symbols.py \ diff --git a/build.cmd b/build.cmd index 4869ebe7..e91d2483 100644 --- a/build.cmd +++ b/build.cmd @@ -336,15 +336,10 @@ if exist "%LOCAL_INSTALL_DIR%" ( rmdir /s /q "%LOCAL_INSTALL_DIR%" 2>nul ) -echo Removing Rust debug artifacts... -if exist "%PROJECT_ROOT%\client-sdk-rust\target\debug" ( - rmdir /s /q "%PROJECT_ROOT%\client-sdk-rust\target\debug" 2>nul -) - -echo Removing Rust release artifacts... -if exist "%PROJECT_ROOT%\client-sdk-rust\target\release" ( - rmdir /s /q "%PROJECT_ROOT%\client-sdk-rust\target\release" 2>nul -) +echo Removing Rust target directory... +if exist "%PROJECT_ROOT%\client-sdk-rust\target" ( + rmdir /s /q "%PROJECT_ROOT%\client-sdk-rust\target" 2>nul +) echo ==^> Clean-all complete. goto :eof diff --git a/build.sh b/build.sh index c3257394..48cb27f1 100755 --- a/build.sh +++ b/build.sh @@ -347,11 +347,8 @@ clean_all() { echo "Removing local-install directory..." rm -rf "${LOCAL_INSTALL_DIR}" || true - echo "Removing Rust debug artifacts..." - rm -rf "${PROJECT_ROOT}/client-sdk-rust/target/debug" || true - - echo "Removing Rust release artifacts..." - rm -rf "${PROJECT_ROOT}/client-sdk-rust/target/release" || true + echo "Removing Rust target directory..." + rm -rf "${PROJECT_ROOT}/client-sdk-rust/target" || true echo "==> Clean-all complete." } diff --git a/cmake/uniffi_cpp.cmake b/cmake/uniffi_cpp.cmake index cb38fc6c..1061bd05 100644 --- a/cmake/uniffi_cpp.cmake +++ b/cmake/uniffi_cpp.cmake @@ -115,6 +115,11 @@ set_source_files_properties( add_library(livekit_uniffi_cpp OBJECT "${LIVEKIT_UNIFFI_CPP_SOURCE}" ) +set_target_properties(livekit_uniffi_cpp PROPERTIES + CXX_VISIBILITY_PRESET hidden + C_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON +) add_dependencies(livekit_uniffi_cpp generate_livekit_ffi_uniffi_cpp) target_include_directories(livekit_uniffi_cpp PUBLIC "${LIVEKIT_UNIFFI_CPP_GENERATED_DIR}" From fdad12a77a2fc9263b4fb456aea0df9a29e7175f Mon Sep 17 00:00:00 2001 From: Alan George Date: Mon, 14 Sep 2026 11:20:58 -0600 Subject: [PATCH 6/7] Use official fork for bindgen --- client-sdk-rust | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-sdk-rust b/client-sdk-rust index 235ba5a9..8fc8585f 160000 --- a/client-sdk-rust +++ b/client-sdk-rust @@ -1 +1 @@ -Subproject commit 235ba5a9521a92774cc80afd80fd94185e0a6589 +Subproject commit 8fc8585fd0efbfd3d409dbe64bd47bbc5cdec6fe From 2ce640adf31e589f5c1ea50c637bbd278b2943e6 Mon Sep 17 00:00:00 2001 From: Alan George Date: Mon, 14 Sep 2026 11:46:01 -0600 Subject: [PATCH 7/7] Fix clang-tidy --- .github/workflows/cpp-tools.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cpp-tools.yml b/.github/workflows/cpp-tools.yml index 5ba316bc..5136e153 100644 --- a/.github/workflows/cpp-tools.yml +++ b/.github/workflows/cpp-tools.yml @@ -113,6 +113,9 @@ jobs: - name: Generate protobuf headers run: cmake --build build-release --target livekit_proto + - name: Generate UniFFI C++ bindings + run: cmake --build build-release --target generate_livekit_ffi_uniffi_cpp + - name: Run clang-tidy env: TIDY_BLOB_SHA: ${{ github.event.pull_request.head.sha || github.sha }}