Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 25 additions & 84 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -60,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$<$<CONFIG:Debug>:Debug>DLL")
# Force /MD or /MDd for ALL targets (including FetchContent subprojects)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL" CACHE STRING "" FORCE)
add_compile_options(/utf-8)
endif()

Expand All @@ -85,24 +84,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
"$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>"
"${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)
Expand Down Expand Up @@ -268,7 +275,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
Expand Down Expand Up @@ -318,8 +325,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}")
Expand Down Expand Up @@ -465,7 +471,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}
Expand All @@ -485,40 +491,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
Expand All @@ -535,7 +512,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)
Expand Down Expand Up @@ -582,42 +559,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
$<TARGET_PROPERTY:protobuf::libprotobuf,IMPORTED_IMPLIB_RELEASE>
DESTINATION ${CMAKE_INSTALL_LIBDIR}
CONFIGURATIONS Release RelWithDebInfo MinSizeRel
)
install(FILES
$<TARGET_PROPERTY:protobuf::libprotobuf,IMPORTED_IMPLIB_DEBUG>
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
$<TARGET_PROPERTY:absl::abseil_dll,IMPORTED_IMPLIB_RELEASE>
DESTINATION ${CMAKE_INSTALL_LIBDIR}
CONFIGURATIONS Release RelWithDebInfo MinSizeRel
)
install(FILES
$<TARGET_PROPERTY:absl::abseil_dll,IMPORTED_IMPLIB_DEBUG>
DESTINATION ${CMAKE_INSTALL_LIBDIR}
CONFIGURATIONS Debug
)
endif()
endif()

# Install public headers
Expand Down
8 changes: 0 additions & 8 deletions cmake/LiveKitConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -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")

130 changes: 130 additions & 0 deletions cmake/protobuf.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# 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: $<TARGET_FILE:protobuf::protoc>)
# - 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)

if(MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL" CACHE STRING "" FORCE)
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.
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 "$<TARGET_FILE:protobuf::protoc>" CACHE STRING "protoc (vendored)" FORCE)
elseif(TARGET protoc)
set(Protobuf_PROTOC_EXECUTABLE "$<TARGET_FILE:protoc>" 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}")
19 changes: 4 additions & 15 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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
)

Expand Down Expand Up @@ -107,7 +103,6 @@ target_link_libraries(SimpleRpc
PRIVATE
nlohmann_json::nlohmann_json
livekit
protobuf::libprotobuf
)

add_executable(SimpleDataStream
Expand All @@ -119,7 +114,6 @@ target_include_directories(SimpleDataStream PRIVATE ${EXAMPLES_PRIVATE_INCLUDE_D
target_link_libraries(SimpleDataStream
PRIVATE
livekit
protobuf::libprotobuf
)

add_custom_command(
Expand All @@ -135,14 +129,9 @@ if(WIN32)
# Get the livekit library output directory (where DLLs are copied during main build)
set(LIVEKIT_LIB_DIR $<TARGET_FILE_DIR:livekit>)

# Protobuf DLL name depends on configuration (libprotobufd.dll for Debug, libprotobuf.dll for Release)
set(PROTOBUF_DLL_NAME $<IF:$<CONFIG:Debug>,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
Expand Down
Loading