From 9fa723c744d187b2d720e80e5651f5a6834fa9e8 Mon Sep 17 00:00:00 2001 From: shijing xian Date: Mon, 12 Jan 2026 23:48:23 +0800 Subject: [PATCH 1/5] change liblivekit to dll and link protobuf statically --- CMakeLists.txt | 103 +++++++--------------------- cmake/LiveKitConfig.cmake.in | 8 --- cmake/protobuf.cmake | 126 +++++++++++++++++++++++++++++++++++ examples/CMakeLists.txt | 19 ++---- 4 files changed, 153 insertions(+), 103 deletions(-) create mode 100644 cmake/protobuf.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ac0b39..a30caca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ project(livekit VERSION ${LIVEKIT_VERSION} LANGUAGES C CXX) set(LIVEKIT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(LIVEKIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") option(LIVEKIT_BUILD_EXAMPLES "Build LiveKit examples" OFF) @@ -85,24 +86,32 @@ set(FFI_PROTO_FILES set(PROTO_BINARY_DIR ${LIVEKIT_BINARY_DIR}/generated) file(MAKE_DIRECTORY ${PROTO_BINARY_DIR}) -# Try to find Protobuf via CONFIG mode first (vcpkg), then fall back to MODULE mode (apt/brew) -find_package(Protobuf CONFIG QUIET) -if(NOT Protobuf_FOUND) - find_package(Protobuf REQUIRED) -endif() +# Livekit static protobuf. +include(protobuf) -# Ensure protoc executable is found (some systems may not set Protobuf_PROTOC_EXECUTABLE) +# Ensure protoc executable is found (when using Livekit Protobuf, it should set Protobuf_PROTOC_EXECUTABLE already) if(NOT Protobuf_PROTOC_EXECUTABLE) find_program(Protobuf_PROTOC_EXECUTABLE NAMES protoc REQUIRED) endif() message(STATUS "Using protoc: ${Protobuf_PROTOC_EXECUTABLE}") add_library(livekit_proto OBJECT ${FFI_PROTO_FILES}) +if(TARGET protobuf::libprotobuf) + set(LIVEKIT_PROTOBUF_TARGET protobuf::libprotobuf) +else() + message(FATAL_ERROR "No protobuf library target found (expected protobuf::libprotobuf)") +endif() target_include_directories(livekit_proto PRIVATE - "$" + "${PROTO_BINARY_DIR}" ${Protobuf_INCLUDE_DIRS} ) -target_link_libraries(livekit_proto PRIVATE protobuf::libprotobuf) +target_link_libraries(livekit_proto PRIVATE ${LIVEKIT_PROTOBUF_TARGET}) +if(TARGET absl::base) + get_target_property(_absl_inc absl::base INTERFACE_INCLUDE_DIRECTORIES) + if(_absl_inc) + target_include_directories(livekit_proto PRIVATE ${_absl_inc}) + endif() +endif() # Manually generate protobuf files to avoid path prefix issues set(PROTO_SRCS) @@ -268,7 +277,7 @@ add_custom_target(build_rust_ffi # Note: protozero_plugin.o removal is no longer needed since we use dynamic libraries on Unix -add_library(livekit STATIC +add_library(livekit SHARED src/audio_frame.cpp src/audio_source.cpp src/audio_stream.cpp @@ -318,8 +327,7 @@ target_include_directories(livekit target_link_libraries(livekit PRIVATE livekit_ffi - PUBLIC - protobuf::libprotobuf + ${LIVEKIT_PROTOBUF_TARGET} ) message(STATUS "Protobuf: version=${Protobuf_VERSION}; protoc=${Protobuf_PROTOC_EXECUTABLE}") @@ -465,7 +473,7 @@ if(APPLE) find_library(FW_METALKIT MetalKit REQUIRED) find_library(FW_SCREENCAPTUREKIT ScreenCaptureKit REQUIRED) - target_link_libraries(livekit PUBLIC + target_link_libraries(livekit PRIVATE ${FW_COREAUDIO} ${FW_AUDIOTOOLBOX} ${FW_COREFOUNDATION} @@ -485,40 +493,11 @@ if(APPLE) ${FW_SCREENCAPTUREKIT} ) - target_link_options(livekit INTERFACE "LINKER:-ObjC") -endif() - -if(Protobuf_VERSION VERSION_GREATER_EQUAL 6.0) - find_package(absl CONFIG QUIET) - if(NOT absl_FOUND) - find_package(Abseil QUIET) - endif() - - if(absl_FOUND) - target_link_libraries(livekit PUBLIC - absl::log - absl::check - absl::strings - absl::base - ) - elseif(Abseil_FOUND) - target_link_libraries(livekit PUBLIC - Abseil::log - Abseil::check - Abseil::strings - Abseil::base - ) - else() - message(FATAL_ERROR - "Protobuf ${Protobuf_VERSION} requires Abseil but no CMake package was found.\n" - "Install Abseil or use Protobuf < 6.") - endif() -else() - message(STATUS "Protobuf < 6 detected; skipping Abseil linking.") + target_link_options(livekit PRIVATE "LINKER:-ObjC") endif() if(WIN32) - target_link_libraries(livekit PUBLIC + target_link_libraries(livekit PRIVATE ntdll userenv winmm @@ -535,7 +514,7 @@ endif() if(UNIX AND NOT APPLE) find_package(OpenSSL REQUIRED) - target_link_libraries(livekit PUBLIC OpenSSL::SSL OpenSSL::Crypto) + target_link_libraries(livekit PRIVATE OpenSSL::SSL OpenSSL::Crypto) endif() if(MSVC) @@ -582,42 +561,6 @@ if(WIN32) CONFIGURATIONS Debug ) endif() - - # Protobuf - if(TARGET protobuf::libprotobuf) - install(IMPORTED_RUNTIME_ARTIFACTS protobuf::libprotobuf - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) - install(FILES - $ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - CONFIGURATIONS Release RelWithDebInfo MinSizeRel - ) - install(FILES - $ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - CONFIGURATIONS Debug - ) - endif() - - # Abseil - if(TARGET absl::abseil_dll) - install(IMPORTED_RUNTIME_ARTIFACTS absl::abseil_dll - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) - install(FILES - $ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - CONFIGURATIONS Release RelWithDebInfo MinSizeRel - ) - install(FILES - $ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - CONFIGURATIONS Debug - ) - endif() endif() # Install public headers diff --git a/cmake/LiveKitConfig.cmake.in b/cmake/LiveKitConfig.cmake.in index f5fcd4a..b5805e4 100644 --- a/cmake/LiveKitConfig.cmake.in +++ b/cmake/LiveKitConfig.cmake.in @@ -1,12 +1,4 @@ @PACKAGE_INIT@ -include(CMakeFindDependencyMacro) - -find_dependency(Protobuf CONFIG REQUIRED) -find_dependency(absl CONFIG QUIET) -if(NOT absl_FOUND) - find_dependency(Abseil REQUIRED) -endif() - include("${CMAKE_CURRENT_LIST_DIR}/LiveKitTargets.cmake") diff --git a/cmake/protobuf.cmake b/cmake/protobuf.cmake new file mode 100644 index 0000000..791e21c --- /dev/null +++ b/cmake/protobuf.cmake @@ -0,0 +1,126 @@ +# cmake/protobuf.cmake +# +# Vendored Protobuf (static) + protobuf-lite + protoc for codegen. +# Also fetches Abseil because protobuf >= 22 commonly requires it. +# +# Exposes: +# - Protobuf_PROTOC_EXECUTABLE (generator expression: $) +# - Protobuf_INCLUDE_DIRS (best-effort; prefer target include dirs) +# - Target protobuf::libprotobuf-lite +# - Target protobuf::protoc + +include(FetchContent) + +option(LIVEKIT_USE_SYSTEM_PROTOBUF "Use system-installed Protobuf instead of vendoring" OFF) + +set(LIVEKIT_PROTOBUF_VERSION "25.3" CACHE STRING "Vendored Protobuf version") +set(LIVEKIT_ABSEIL_VERSION "20240116.2" CACHE STRING "Vendored Abseil version") + +if(LIVEKIT_USE_SYSTEM_PROTOBUF) + find_package(Protobuf CONFIG QUIET) + if(NOT Protobuf_FOUND) + find_package(Protobuf REQUIRED) + endif() + + if(NOT Protobuf_PROTOC_EXECUTABLE) + find_program(Protobuf_PROTOC_EXECUTABLE NAMES protoc REQUIRED) + endif() + message(STATUS "Using system protoc: ${Protobuf_PROTOC_EXECUTABLE}") + return() +endif() + +# ---- Abseil (needed by protobuf on many versions) ---- +# Fetch Abseil and make it available as CMake targets (absl::...) +FetchContent_Declare( + livekit_abseil + URL "https://github.com/abseil/abseil-cpp/archive/refs/tags/${LIVEKIT_ABSEIL_VERSION}.tar.gz" + DOWNLOAD_EXTRACT_TIMESTAMP TRUE +) + +# ---- Protobuf ---- +FetchContent_Declare( + livekit_protobuf + URL "https://github.com/protocolbuffers/protobuf/releases/download/v${LIVEKIT_PROTOBUF_VERSION}/protobuf-${LIVEKIT_PROTOBUF_VERSION}.tar.gz" + DOWNLOAD_EXTRACT_TIMESTAMP TRUE +) + +# Configure protobuf build: static libs, no tests/examples. +# Build static only +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + +# Disable installs/exports in subprojects (avoids export-set errors) +set(protobuf_INSTALL OFF CACHE BOOL "" FORCE) +set(ABSL_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) +set(utf8_range_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) + +set(protobuf_BUILD_TESTS OFF CACHE BOOL "" FORCE) +set(protobuf_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +set(protobuf_BUILD_CONFORMANCE OFF CACHE BOOL "" FORCE) +set(protobuf_BUILD_PROTOC_BINARIES ON CACHE BOOL "" FORCE) +set(protobuf_WITH_ZLIB OFF CACHE BOOL "" FORCE) + +set(protobuf_ABSL_PROVIDER "package" CACHE STRING "" FORCE) + +# Make abseil available first so protobuf can find absl:: targets. +FetchContent_MakeAvailable(livekit_abseil) + +# A workaround to remove the -Xarch_x86_64 / -msse4 flags that could fail the compilation. +if(APPLE AND (CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")) + foreach(t + absl_random_internal_randen_hwaes_impl + absl_random_internal_randen_hwaes + ) + if(TARGET ${t}) + foreach(prop COMPILE_OPTIONS INTERFACE_COMPILE_OPTIONS) + get_target_property(_opts ${t} ${prop}) + if(_opts) + list(FILTER _opts EXCLUDE REGEX "^-Xarch_x86_64$") + list(FILTER _opts EXCLUDE REGEX "^-msse4\\.1$") + list(FILTER _opts EXCLUDE REGEX "^-maes$") + set_target_properties(${t} PROPERTIES ${prop} "${_opts}") + endif() + endforeach() + endif() + endforeach() +endif() + + + +# Some protobuf versions look for absl via find_package(absl CONFIG). +# The abseil project usually provides targets directly, but not a config package. +# To help protobuf, ensure absl targets exist (they should after MakeAvailable). +if(NOT TARGET absl::base) + message(FATAL_ERROR "Abseil targets not found after FetchContent_MakeAvailable(livekit_abseil)") +endif() + +# Now make protobuf available. +FetchContent_MakeAvailable(livekit_protobuf) + +# Protobuf targets: modern protobuf exports protobuf::protoc etc. +if(TARGET protobuf::protoc) + set(Protobuf_PROTOC_EXECUTABLE "$" CACHE STRING "protoc (vendored)" FORCE) +elseif(TARGET protoc) + set(Protobuf_PROTOC_EXECUTABLE "$" CACHE STRING "protoc (vendored)" FORCE) +else() + message(FATAL_ERROR "Vendored protobuf did not create a protoc target") +endif() + +# Prefer protobuf-lite +if(TARGET protobuf::libprotobuf-lite) + # ok +elseif(TARGET libprotobuf-lite) + add_library(protobuf::libprotobuf-lite ALIAS libprotobuf-lite) +else() + message(FATAL_ERROR "Vendored protobuf did not create protobuf-lite target") +endif() + +# Include dirs: prefer target usage; keep this var for your existing CMakeLists. +get_target_property(_pb_includes protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES) +if(NOT _pb_includes) + # common fallback + set(_pb_includes "${livekit_protobuf_SOURCE_DIR}/src") +endif() +set(Protobuf_INCLUDE_DIRS "${_pb_includes}" CACHE STRING "Protobuf include dirs" FORCE) + +message(STATUS "Using vendored Protobuf v${LIVEKIT_PROTOBUF_VERSION}") +message(STATUS "Using vendored protoc: ${Protobuf_PROTOC_EXECUTABLE}") diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 082aba1..3d36664 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,14 +8,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # This ensures SDL3 and other shared libs are loaded from bin/ not _deps/ if(UNIX) if(APPLE) - set(CMAKE_BUILD_RPATH "@executable_path") - set(CMAKE_INSTALL_RPATH "@executable_path") + set(CMAKE_BUILD_RPATH "@loader_path;@loader_path/../lib") + set(CMAKE_INSTALL_RPATH "@loader_path;@loader_path/../lib") else() - set(CMAKE_BUILD_RPATH "$ORIGIN") - set(CMAKE_INSTALL_RPATH "$ORIGIN") + set(CMAKE_BUILD_RPATH "$ORIGIN:$ORIGIN/../lib") + set(CMAKE_INSTALL_RPATH "$ORIGIN:$ORIGIN/../lib") endif() set(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE) - # Disable using the default RPATH from linked libraries set(CMAKE_SKIP_BUILD_RPATH FALSE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) endif() @@ -47,12 +46,9 @@ add_executable(SimpleRoom target_include_directories(SimpleRoom PRIVATE ${EXAMPLES_PRIVATE_INCLUDE_DIRS}) -# Link protobuf::libprotobuf directly to get proper include directories -# (livekit links it PRIVATELY so its headers aren't propagated) target_link_libraries(SimpleRoom PRIVATE livekit - protobuf::libprotobuf SDL3::SDL3 ) @@ -107,7 +103,6 @@ target_link_libraries(SimpleRpc PRIVATE nlohmann_json::nlohmann_json livekit - protobuf::libprotobuf ) add_executable(SimpleDataStream @@ -119,7 +114,6 @@ target_include_directories(SimpleDataStream PRIVATE ${EXAMPLES_PRIVATE_INCLUDE_D target_link_libraries(SimpleDataStream PRIVATE livekit - protobuf::libprotobuf ) add_custom_command( @@ -135,14 +129,9 @@ if(WIN32) # Get the livekit library output directory (where DLLs are copied during main build) set(LIVEKIT_LIB_DIR $) - # Protobuf DLL name depends on configuration (libprotobufd.dll for Debug, libprotobuf.dll for Release) - set(PROTOBUF_DLL_NAME $,libprotobufd.dll,libprotobuf.dll>) - # List of DLLs to copy (using generator expressions for config-dependent names) set(REQUIRED_DLLS "livekit_ffi.dll" - "${PROTOBUF_DLL_NAME}" - "abseil_dll.dll" ) # Copy DLLs to each example's output directory From dae70d533464b32fccee68dbe9d0886907cca0bd Mon Sep 17 00:00:00 2001 From: shijing xian Date: Tue, 13 Jan 2026 12:37:58 +0800 Subject: [PATCH 2/5] a try to fix the windows build --- CMakeLists.txt | 6 ++---- cmake/protobuf.cmake | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a30caca..a5dac54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,10 +61,8 @@ endif() if(MSVC) - # Use dynamic CRT (/MD) for compatibility with Qt and other /MD libraries. - # The livekit_ffi.dll isolates the /MT libwebrtc dependency, so livekit.lib - # can safely use /MD. - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + # Force /MD or /MDd for ALL targets (including FetchContent subprojects) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE STRING "" FORCE) add_compile_options(/utf-8) endif() diff --git a/cmake/protobuf.cmake b/cmake/protobuf.cmake index 791e21c..715552e 100644 --- a/cmake/protobuf.cmake +++ b/cmake/protobuf.cmake @@ -61,6 +61,10 @@ set(protobuf_WITH_ZLIB OFF CACHE BOOL "" FORCE) set(protobuf_ABSL_PROVIDER "package" CACHE STRING "" FORCE) +if(MSVC) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE STRING "" FORCE) +endif() + # Make abseil available first so protobuf can find absl:: targets. FetchContent_MakeAvailable(livekit_abseil) From b6bb5ed3f160e7f306be3aaf54ab2331d7ede654 Mon Sep 17 00:00:00 2001 From: shijing xian Date: Tue, 13 Jan 2026 18:27:39 +0800 Subject: [PATCH 3/5] another try to fix the windows build --- .github/workflows/builds.yml | 2 + .github/workflows/make-release.yml | 2 + CMakeLists.txt | 73 +++----------------- CMakePresets.json | 6 +- cmake/protobuf.cmake | 107 +++++++++++++++++++++++------ 5 files changed, 103 insertions(+), 87 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 43013f5..3bf2368 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -33,6 +33,8 @@ env: CARGO_TERM_COLOR: always # vcpkg binary caching for Windows VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + VCPKG_DEFAULT_TRIPLET: x64-windows-static-md + VCPKG_TARGET_TRIPLET: x64-windows-static-md jobs: build: diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index 8f35b61..b21de8b 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -14,6 +14,8 @@ on: env: CARGO_TERM_COLOR: always VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + VCPKG_DEFAULT_TRIPLET: x64-windows-static-md + VCPKG_TARGET_TRIPLET: x64-windows-static-md jobs: build: diff --git a/CMakeLists.txt b/CMakeLists.txt index a5dac54..dcc5456 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,13 @@ option(LIVEKIT_BUILD_EXAMPLES "Build LiveKit examples" OFF) # vcpkg is only used on Windows; Linux/macOS use system package managers if(WIN32) option(LIVEKIT_USE_VCPKG "Use vcpkg for dependency management (Windows only)" ON) + set(LIVEKIT_USE_SYSTEM_PROTOBUF ON CACHE BOOL "Use system protobuf (vcpkg) on Windows" FORCE) + # Force /MD or /MDd for ALL targets (including FetchContent subprojects) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE STRING "" FORCE) + add_compile_options(/utf-8) else() option(LIVEKIT_USE_VCPKG "Use vcpkg for dependency management" OFF) + set(LIVEKIT_USE_SYSTEM_PROTOBUF OFF CACHE BOOL "Use vendored protobuf on non-Windows" FORCE) endif() set(CMAKE_CXX_STANDARD 17) @@ -59,13 +64,6 @@ if(LIVEKIT_IS_TOPLEVEL) endforeach() endif() - -if(MSVC) - # Force /MD or /MDd for ALL targets (including FetchContent subprojects) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE STRING "" FORCE) - add_compile_options(/utf-8) -endif() - set(FFI_PROTO_DIR ${LIVEKIT_ROOT_DIR}/client-sdk-rust/livekit-ffi/protocol) set(FFI_PROTO_FILES ${FFI_PROTO_DIR}/handle.proto @@ -86,9 +84,10 @@ file(MAKE_DIRECTORY ${PROTO_BINARY_DIR}) # Livekit static protobuf. include(protobuf) - -# Ensure protoc executable is found (when using Livekit Protobuf, it should set Protobuf_PROTOC_EXECUTABLE already) -if(NOT Protobuf_PROTOC_EXECUTABLE) +# Ensure protoc executable is found. +if(TARGET protobuf::protoc) + set(Protobuf_PROTOC_EXECUTABLE "$") +elseif(NOT Protobuf_PROTOC_EXECUTABLE) find_program(Protobuf_PROTOC_EXECUTABLE NAMES protoc REQUIRED) endif() message(STATUS "Using protoc: ${Protobuf_PROTOC_EXECUTABLE}") @@ -392,60 +391,6 @@ if(LIVEKIT_IS_TOPLEVEL) COMMENT "Copying liblivekit_ffi.so to output directory" ) endif() - - # Copy third-party DLL and LIB dependencies to lib directory (Windows only) - if(WIN32 AND LIVEKIT_USE_VCPKG) - # Determine vcpkg directories based on configuration - set(VCPKG_BIN_DIR_DEBUG "${LIVEKIT_ROOT_DIR}/vcpkg_installed/x64-windows/debug/bin") - set(VCPKG_BIN_DIR_RELEASE "${LIVEKIT_ROOT_DIR}/vcpkg_installed/x64-windows/bin") - set(VCPKG_LIB_DIR_DEBUG "${LIVEKIT_ROOT_DIR}/vcpkg_installed/x64-windows/debug/lib") - set(VCPKG_LIB_DIR_RELEASE "${LIVEKIT_ROOT_DIR}/vcpkg_installed/x64-windows/lib") - - # vcpkg uses 'd' suffix for debug builds (e.g., libprotobufd.dll) - # We need to copy with the correct source name but keep the output name consistent - - # abseil_dll.dll (same name for both debug and release) - add_custom_command( - TARGET livekit POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "$,${VCPKG_BIN_DIR_DEBUG}/abseil_dll.dll,${VCPKG_BIN_DIR_RELEASE}/abseil_dll.dll>" - "$/abseil_dll.dll" - COMMENT "Copying abseil_dll.dll to lib directory" - VERBATIM - ) - - # libprotobuf.dll - debug version has 'd' suffix - add_custom_command( - TARGET livekit POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "$,${VCPKG_BIN_DIR_DEBUG}/libprotobufd.dll,${VCPKG_BIN_DIR_RELEASE}/libprotobuf.dll>" - "$/$,libprotobufd.dll,libprotobuf.dll>" - COMMENT "Copying libprotobuf DLL to lib directory" - VERBATIM - ) - - # abseil_dll.lib (same name for both debug and release) - add_custom_command( - TARGET livekit POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "$,${VCPKG_LIB_DIR_DEBUG}/abseil_dll.lib,${VCPKG_LIB_DIR_RELEASE}/abseil_dll.lib>" - "$/abseil_dll.lib" - COMMENT "Copying abseil_dll.lib to lib directory" - VERBATIM - ) - - # libprotobuf.lib - debug version has 'd' suffix - add_custom_command( - TARGET livekit POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "$,${VCPKG_LIB_DIR_DEBUG}/libprotobufd.lib,${VCPKG_LIB_DIR_RELEASE}/libprotobuf.lib>" - "$/$,libprotobufd.lib,libprotobuf.lib>" - COMMENT "Copying libprotobuf LIB to lib directory" - VERBATIM - ) - - message(STATUS "Third-party dependencies will be copied to lib directory") - endif() endif() if(APPLE) diff --git a/CMakePresets.json b/CMakePresets.json index 53a31a5..b193651 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -15,7 +15,8 @@ "value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" }, "VCPKG_INSTALLED_DIR": "${sourceDir}/vcpkg_installed", - "LIVEKIT_USE_VCPKG": "ON" + "LIVEKIT_USE_VCPKG": "ON", + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md" } }, { @@ -26,6 +27,9 @@ "architecture": { "value": "x64", "strategy": "set" + }, + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md" } }, { diff --git a/cmake/protobuf.cmake b/cmake/protobuf.cmake index 715552e..42901db 100644 --- a/cmake/protobuf.cmake +++ b/cmake/protobuf.cmake @@ -1,13 +1,13 @@ # cmake/protobuf.cmake # -# Vendored Protobuf (static) + protobuf-lite + protoc for codegen. -# Also fetches Abseil because protobuf >= 22 commonly requires it. +# Windows: use vcpkg Protobuf (static-md triplet) + vcpkg protoc +# macOS/Linux: vendored Protobuf (static) + vendored Abseil + vendored protoc # # Exposes: -# - Protobuf_PROTOC_EXECUTABLE (generator expression: $) -# - Protobuf_INCLUDE_DIRS (best-effort; prefer target include dirs) -# - Target protobuf::libprotobuf-lite -# - Target protobuf::protoc +# - Protobuf_PROTOC_EXECUTABLE +# - Protobuf_INCLUDE_DIRS +# - Target protobuf::libprotobuf (and optionally protobuf::libprotobuf-lite) +# - Target protobuf::protoc (on vendored path; on Windows we may only have an executable) include(FetchContent) @@ -16,6 +16,70 @@ option(LIVEKIT_USE_SYSTEM_PROTOBUF "Use system-installed Protobuf instead of ven set(LIVEKIT_PROTOBUF_VERSION "25.3" CACHE STRING "Vendored Protobuf version") set(LIVEKIT_ABSEIL_VERSION "20240116.2" CACHE STRING "Vendored Abseil version") +# --------------------------------------------------------------------------- +# Windows path: prefer vcpkg static-md protobuf to avoid /MT vs /MD mismatches. +# This assumes you configure CMake with: +# -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake +# -DVCPKG_TARGET_TRIPLET=x64-windows-static-md +# +# (or set VCPKG_TARGET_TRIPLET in the environment before configuring) +# --------------------------------------------------------------------------- +if(WIN32 AND NOT LIVEKIT_USE_SYSTEM_PROTOBUF) + # If the user forgot the triplet, fail fast with a helpful message. + if(DEFINED VCPKG_TARGET_TRIPLET AND NOT VCPKG_TARGET_TRIPLET STREQUAL "x64-windows-static-md") + message(FATAL_ERROR + "On Windows, LiveKit expects vcpkg triplet x64-windows-static-md for static protobuf + /MD.\n" + "You have VCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}'.\n" + "Reconfigure with -DVCPKG_TARGET_TRIPLET=x64-windows-static-md." + ) + elseif(NOT DEFINED VCPKG_TARGET_TRIPLET) + message(WARNING + "VCPKG_TARGET_TRIPLET is not set. On Windows you should configure with:\n" + " -DVCPKG_TARGET_TRIPLET=x64-windows-static-md\n" + "to get static protobuf built against /MD." + ) + endif() + + # Ensure /MD for everything in this top-level build. + if(MSVC) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE STRING "" FORCE) + endif() + + # Use vcpkg's Protobuf package (CONFIG mode provides imported targets). + # This should give protobuf::libprotobuf and protobuf::protoc. + find_package(Protobuf CONFIG REQUIRED) + + # Prefer protoc target if available; else fall back to locating protoc. + if(TARGET protobuf::protoc) + set(Protobuf_PROTOC_EXECUTABLE "$" CACHE STRING "protoc (vcpkg)" FORCE) + elseif(DEFINED Protobuf_PROTOC_EXECUTABLE AND Protobuf_PROTOC_EXECUTABLE) + # Some find modules populate this var + set(Protobuf_PROTOC_EXECUTABLE "${Protobuf_PROTOC_EXECUTABLE}" CACHE STRING "protoc (vcpkg/module)" FORCE) + else() + find_program(Protobuf_PROTOC_EXECUTABLE NAMES protoc REQUIRED) + set(Protobuf_PROTOC_EXECUTABLE "${Protobuf_PROTOC_EXECUTABLE}" CACHE STRING "protoc (found)" FORCE) + endif() + + # Include dirs: prefer the imported target usage requirements. + if(TARGET protobuf::libprotobuf) + get_target_property(_pb_includes protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES) + elseif(TARGET protobuf::protobuf) # some protobuf builds use protobuf::protobuf + get_target_property(_pb_includes protobuf::protobuf INTERFACE_INCLUDE_DIRECTORIES) + endif() + if(NOT _pb_includes) + # Best-effort fallback: Protobuf_INCLUDE_DIRS is commonly set by ProtobufConfig + set(_pb_includes "${Protobuf_INCLUDE_DIRS}") + endif() + set(Protobuf_INCLUDE_DIRS "${_pb_includes}" CACHE STRING "Protobuf include dirs" FORCE) + + message(STATUS "Windows: using vcpkg Protobuf (expect triplet x64-windows-static-md)") + message(STATUS "Windows: protoc = ${Protobuf_PROTOC_EXECUTABLE}") + return() +endif() + +# --------------------------------------------------------------------------- +# Optional "system protobuf" path (non-vcpkg use, or user wants system package) +# --------------------------------------------------------------------------- if(LIVEKIT_USE_SYSTEM_PROTOBUF) find_package(Protobuf CONFIG QUIET) if(NOT Protobuf_FOUND) @@ -29,8 +93,11 @@ if(LIVEKIT_USE_SYSTEM_PROTOBUF) return() endif() -# ---- Abseil (needed by protobuf on many versions) ---- -# Fetch Abseil and make it available as CMake targets (absl::...) +# --------------------------------------------------------------------------- +# macOS/Linux path: vendored Abseil + vendored Protobuf (static) + vendored protoc +# --------------------------------------------------------------------------- + +# ---- Abseil ---- FetchContent_Declare( livekit_abseil URL "https://github.com/abseil/abseil-cpp/archive/refs/tags/${LIVEKIT_ABSEIL_VERSION}.tar.gz" @@ -45,13 +112,12 @@ FetchContent_Declare( ) # Configure protobuf build: static libs, no tests/examples. -# Build static only set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) # Disable installs/exports in subprojects (avoids export-set errors) set(protobuf_INSTALL OFF CACHE BOOL "" FORCE) set(ABSL_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) -set(utf8_range_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) +set(utf8_range_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) set(protobuf_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(protobuf_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) @@ -61,6 +127,7 @@ set(protobuf_WITH_ZLIB OFF CACHE BOOL "" FORCE) set(protobuf_ABSL_PROVIDER "package" CACHE STRING "" FORCE) +# Keep /MD for MSVC, though this branch is not Windows by default. if(MSVC) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE STRING "" FORCE) endif() @@ -68,7 +135,7 @@ endif() # Make abseil available first so protobuf can find absl:: targets. FetchContent_MakeAvailable(livekit_abseil) -# A workaround to remove the -Xarch_x86_64 / -msse4 flags that could fail the compilation. +# Workaround for some abseil flags on Apple Silicon. if(APPLE AND (CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")) foreach(t absl_random_internal_randen_hwaes_impl @@ -88,11 +155,6 @@ if(APPLE AND (CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")) endforeach() endif() - - -# Some protobuf versions look for absl via find_package(absl CONFIG). -# The abseil project usually provides targets directly, but not a config package. -# To help protobuf, ensure absl targets exist (they should after MakeAvailable). if(NOT TARGET absl::base) message(FATAL_ERROR "Abseil targets not found after FetchContent_MakeAvailable(livekit_abseil)") endif() @@ -109,22 +171,23 @@ else() message(FATAL_ERROR "Vendored protobuf did not create a protoc target") endif() -# Prefer protobuf-lite +# Prefer protobuf-lite (optional; keep libprotobuf around too) if(TARGET protobuf::libprotobuf-lite) # ok elseif(TARGET libprotobuf-lite) add_library(protobuf::libprotobuf-lite ALIAS libprotobuf-lite) else() - message(FATAL_ERROR "Vendored protobuf did not create protobuf-lite target") + message(WARNING "Vendored protobuf did not create protobuf-lite target; continuing with libprotobuf only") endif() # Include dirs: prefer target usage; keep this var for your existing CMakeLists. -get_target_property(_pb_includes protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES) +if(TARGET protobuf::libprotobuf) + get_target_property(_pb_includes protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES) +endif() if(NOT _pb_includes) - # common fallback set(_pb_includes "${livekit_protobuf_SOURCE_DIR}/src") endif() set(Protobuf_INCLUDE_DIRS "${_pb_includes}" CACHE STRING "Protobuf include dirs" FORCE) -message(STATUS "Using vendored Protobuf v${LIVEKIT_PROTOBUF_VERSION}") -message(STATUS "Using vendored protoc: ${Protobuf_PROTOC_EXECUTABLE}") +message(STATUS "macOS/Linux: using vendored Protobuf v${LIVEKIT_PROTOBUF_VERSION}") +message(STATUS "macOS/Linux: vendored protoc: ${Protobuf_PROTOC_EXECUTABLE}") From f063ecf3c6aceabbf38df76ab5e20457001430eb Mon Sep 17 00:00:00 2001 From: shijing xian Date: Tue, 13 Jan 2026 19:53:25 +0800 Subject: [PATCH 4/5] fix the windows problem that we have two protobuf versions --- .github/workflows/builds.yml | 2 +- .github/workflows/make-release.yml | 1 + CMakePresets.json | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 3bf2368..766cec5 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -32,8 +32,8 @@ on: env: CARGO_TERM_COLOR: always # vcpkg binary caching for Windows - VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_DEFAULT_TRIPLET: x64-windows-static-md + VCPKG_DEFAULT_HOST_TRIPLET: x64-windows-static-md VCPKG_TARGET_TRIPLET: x64-windows-static-md jobs: diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index b21de8b..db43e75 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -15,6 +15,7 @@ env: CARGO_TERM_COLOR: always VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_DEFAULT_TRIPLET: x64-windows-static-md + VCPKG_DEFAULT_HOST_TRIPLET: x64-windows-static-md VCPKG_TARGET_TRIPLET: x64-windows-static-md jobs: diff --git a/CMakePresets.json b/CMakePresets.json index b193651..a15603a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -16,7 +16,8 @@ }, "VCPKG_INSTALLED_DIR": "${sourceDir}/vcpkg_installed", "LIVEKIT_USE_VCPKG": "ON", - "VCPKG_TARGET_TRIPLET": "x64-windows-static-md" + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md", + "VCPKG_HOST_TRIPLET": "x64-windows-static-md" } }, { From 8d98944bfb7c3b5480732f7ce924b0cd5124aecc Mon Sep 17 00:00:00 2001 From: shijing xian Date: Tue, 13 Jan 2026 20:39:44 +0800 Subject: [PATCH 5/5] fix the cannot open input file '..\lib\livekit.lib' --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dcc5456..6d5e57c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,6 +307,10 @@ add_library(livekit SHARED src/video_utils.cpp src/video_utils.h ) +if(WIN32) + set_target_properties(livekit PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + target_sources(livekit PRIVATE $)