test_core.cpp used bare assert(). CI builds Release, Release defines NDEBUG, and NDEBUG compiles assert() out entirely -- so that suite had been passing unconditionally, checking nothing. It now uses the same always-live ST_ASSERT harness as the other suites and reports a count (10 checks), and additionally asserts that core_version() really is the version CMake injected rather than a stale literal. macOS SDK, third iteration. The previous fix assumed OBS only wanted a version-carrying SDK filename. Reading OBS 30.0.2's cmake/macos/compilerconfig.cmake shows the actual pattern is stricter: ".+/MacOSX.platform/Developer/SDKs/MacOSX([0-9]+\.[0-9])+\.sdk$" which only ever matches a full-Xcode SDK path. A Command-Line-Tools-only install keeps its SDK at /Library/Developer/CommandLineTools/SDKs/MacOSX<ver>.sdk, with no MacOSX.platform/Developer/SDKs segment at all, so it can never match however it is named -- which is why the second attempt got past the "REGEX needs at least 5 arguments" error and still landed on "Your macOS SDK version () is too low", with the version still empty. _resolve_versioned_macos_sdk now builds a symlink tree under .deps/ whose shape matches that pattern and which points at exactly the same SDK, and uses the toolchain's own path untouched when it already matches (i.e. when real Xcode is installed). Nothing about the compilation changes -- only the spelling of the path, which is all OBS's check reads. Also refreshes the scaffold-era comments in core.h and core_c.h, which still described this library as a placeholder that would one day talk to livekit-ffi. Linux CI is green on the previous commit: real libobs adapter linked (ldd shows libobs.so.0 plus liblivekit/liblivekit_ffi resolving from the staged package directory), obs_module_load exported, ctest 6/6, artifact uploaded. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
330 lines
13 KiB
CMake
330 lines
13 KiB
CMake
# Adapted from obsproject/obs-plugintemplate (cmake/common/buildspec_common.cmake,
|
|
# master as of 2026-09-06). Deliberate changes from upstream, all recorded here
|
|
# so a future re-sync knows what to keep:
|
|
#
|
|
# 1. _setup_obs_studio builds and installs the `libobs` target, not
|
|
# `obs-frontend-api`. This plugin's properties UI is plain
|
|
# obs_properties_* and it never touches the frontend API, so building it
|
|
# would only drag Qt back in -- which is the whole point of dropping qt6
|
|
# from dependencies_list.
|
|
# 2. It passes -DENABLE_UI:BOOL=OFF and -DENABLE_SCRIPTING:BOOL=OFF as well
|
|
# as upstream's -DENABLE_FRONTEND:BOOL=OFF. The pinned OBS (30.0.2)
|
|
# predates the ENABLE_FRONTEND option and gates its Qt-dependent UI on
|
|
# ENABLE_UI instead; without this the sub-build configures the whole
|
|
# OBS UI and demands Qt.
|
|
# 3. Only the Release configuration is built and installed. Upstream builds
|
|
# Debug as well; nothing here consumes a debug libobs, and it doubles the
|
|
# slowest step in CI.
|
|
# 4. macOS uses the Ninja generator and a single architecture, not upstream's
|
|
# Xcode generator and forced universal build. See the comment at that
|
|
# branch: a runner with only the Command Line Tools has no xcodebuild.
|
|
# 5. Generator flags are built as CMake lists so each becomes its own argv
|
|
# entry, rather than upstream's space-separated strings passed unquoted.
|
|
#
|
|
|
|
include_guard(GLOBAL)
|
|
|
|
# _check_deps_version: Checks for obs-deps VERSION file in prefix paths
|
|
function(_check_deps_version version)
|
|
set(found FALSE)
|
|
|
|
foreach(path IN LISTS CMAKE_PREFIX_PATH)
|
|
if(EXISTS "${path}/share/obs-deps/VERSION")
|
|
if(dependency STREQUAL qt6 AND NOT EXISTS "${path}/lib/cmake/Qt6/Qt6Config.cmake")
|
|
set(found FALSE)
|
|
continue()
|
|
endif()
|
|
|
|
file(READ "${path}/share/obs-deps/VERSION" _check_version)
|
|
string(REPLACE "\n" "" _check_version "${_check_version}")
|
|
string(REPLACE "-" "." _check_version "${_check_version}")
|
|
string(REPLACE "-" "." version "${version}")
|
|
|
|
if(_check_version VERSION_EQUAL version)
|
|
set(found TRUE)
|
|
break()
|
|
elseif(_check_version VERSION_LESS version)
|
|
message(
|
|
AUTHOR_WARNING
|
|
"Older ${label} version detected in ${path}: \n"
|
|
"Found ${_check_version}, require ${version}"
|
|
)
|
|
list(REMOVE_ITEM CMAKE_PREFIX_PATH "${path}")
|
|
list(APPEND CMAKE_PREFIX_PATH "${path}")
|
|
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH})
|
|
continue()
|
|
else()
|
|
message(
|
|
AUTHOR_WARNING
|
|
"Newer ${label} version detected in ${path}: \n"
|
|
"Found ${_check_version}, require ${version}"
|
|
)
|
|
set(found TRUE)
|
|
break()
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
return(PROPAGATE found CMAKE_PREFIX_PATH)
|
|
endfunction()
|
|
|
|
# _resolve_versioned_macos_sdk: return an SDK path that satisfies OBS's own
|
|
# macOS SDK version check.
|
|
#
|
|
# Not upstream. OBS 30.0.2's cmake/macos/compilerconfig.cmake reads the SDK
|
|
# version straight out of CMAKE_OSX_SYSROOT with this regex:
|
|
#
|
|
# ".+/MacOSX.platform/Developer/SDKs/MacOSX([0-9]+\\.[0-9])+\\.sdk$"
|
|
#
|
|
# and hard-fails if it does not match ("Your macOS SDK version () is too low",
|
|
# with an empty version, which is the tell). That pattern only ever matches a
|
|
# full-Xcode SDK path; a Command-Line-Tools-only install has its SDK at
|
|
# /Library/Developer/CommandLineTools/SDKs/MacOSX<ver>.sdk, with no
|
|
# MacOSX.platform/Developer/SDKs segment at all, and can never match.
|
|
#
|
|
# Upstream never hits this because it uses the Xcode generator, where
|
|
# CMAKE_OSX_SYSROOT stays the literal string "macosx" and Xcode resolves it
|
|
# late. This project uses Ninja (the CI runner has no xcodebuild), so CMake
|
|
# resolves the sysroot eagerly and the regex runs against a real path.
|
|
#
|
|
# So: if the toolchain's own SDK path already matches, use it untouched.
|
|
# Otherwise build a symlink tree under .deps/ whose shape matches the regex
|
|
# and which points at exactly the same SDK. Nothing about the compilation
|
|
# changes -- only the spelling of the path, which is all the check reads.
|
|
function(_resolve_versioned_macos_sdk out_path)
|
|
set(${out_path} "" PARENT_SCOPE)
|
|
|
|
execute_process(
|
|
COMMAND xcrun --show-sdk-path
|
|
OUTPUT_VARIABLE _sdk
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
RESULT_VARIABLE _rc
|
|
ERROR_QUIET
|
|
)
|
|
if(NOT _rc EQUAL 0 OR NOT _sdk)
|
|
message(WARNING "Could not determine the macOS SDK path via xcrun; leaving CMAKE_OSX_SYSROOT alone.")
|
|
return()
|
|
endif()
|
|
|
|
if(_sdk MATCHES "/MacOSX\\.platform/Developer/SDKs/MacOSX[0-9]+\\.[0-9]+\\.sdk$")
|
|
set(${out_path} "${_sdk}" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
execute_process(
|
|
COMMAND xcrun --show-sdk-version
|
|
OUTPUT_VARIABLE _sdk_version
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
RESULT_VARIABLE _rc
|
|
ERROR_QUIET
|
|
)
|
|
if(NOT _rc EQUAL 0 OR NOT _sdk_version MATCHES "^([0-9]+)\\.([0-9]+)")
|
|
message(WARNING "Could not determine the macOS SDK version via xcrun (got '${_sdk_version}').")
|
|
return()
|
|
endif()
|
|
set(_short "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}")
|
|
|
|
set(_link_dir "${dependencies_dir}/sdk/MacOSX.platform/Developer/SDKs")
|
|
set(_link "${_link_dir}/MacOSX${_short}.sdk")
|
|
file(MAKE_DIRECTORY "${_link_dir}")
|
|
if(NOT EXISTS "${_link}")
|
|
file(CREATE_LINK "${_sdk}" "${_link}" SYMBOLIC)
|
|
endif()
|
|
if(EXISTS "${_link}")
|
|
message(STATUS "macOS SDK ${_short} at ${_sdk}; presenting it to OBS as ${_link}")
|
|
set(${out_path} "${_link}" PARENT_SCOPE)
|
|
else()
|
|
message(WARNING "Could not create the versioned macOS SDK symlink at ${_link}.")
|
|
endif()
|
|
endfunction()
|
|
|
|
# _setup_obs_studio: Create obs-studio build project, then build libobs and obs-frontend-api
|
|
function(_setup_obs_studio)
|
|
if(NOT libobs_DIR)
|
|
set(_is_fresh --fresh)
|
|
endif()
|
|
|
|
# Every generator-specific flag is built as a proper CMake list, so each
|
|
# element becomes its own argv entry. Upstream packs several flags into one
|
|
# space-separated string and passes it unquoted, which execute_process hands
|
|
# to cmake as a single argument -- it happens not to matter there because
|
|
# those flags are optional, but -DCMAKE_BUILD_TYPE is not.
|
|
set(_cmake_arch "")
|
|
set(_cmake_extra "")
|
|
|
|
if(OS_WINDOWS)
|
|
set(_cmake_generator "${CMAKE_GENERATOR}")
|
|
if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION)
|
|
list(APPEND _cmake_arch -A "${arch},version=${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
|
|
else()
|
|
list(APPEND _cmake_arch -A "${arch}")
|
|
endif()
|
|
list(APPEND _cmake_extra "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}")
|
|
elseif(OS_MACOS)
|
|
# Ninja, not upstream's Xcode generator. A runner with only the Command
|
|
# Line Tools installed has no xcodebuild, and the Xcode generator then
|
|
# fails the OBS sub-configure outright with "No CMAKE_C_COMPILER could be
|
|
# found" -- observed on the `home-mac` CI runner. Ninja is single-config,
|
|
# hence the explicit CMAKE_BUILD_TYPE below.
|
|
set(_cmake_generator "Ninja")
|
|
# Single-architecture, not upstream's forced universal build: this plugin
|
|
# is built for one architecture anyway (client-sdk-cpp ships single-arch
|
|
# dylibs), so building libobs universal would double the slowest step in
|
|
# CI for a slice nothing links against.
|
|
if(CMAKE_OSX_ARCHITECTURES)
|
|
list(APPEND _cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}")
|
|
endif()
|
|
list(APPEND _cmake_extra "-DCMAKE_BUILD_TYPE=Release")
|
|
if(CMAKE_OSX_DEPLOYMENT_TARGET)
|
|
list(APPEND _cmake_extra "-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
|
endif()
|
|
_resolve_versioned_macos_sdk(_sdk_path)
|
|
if(_sdk_path)
|
|
list(APPEND _cmake_extra "-DCMAKE_OSX_SYSROOT=${_sdk_path}")
|
|
endif()
|
|
endif()
|
|
|
|
message(STATUS "Configure ${label} (${arch})")
|
|
execute_process(
|
|
COMMAND
|
|
"${CMAKE_COMMAND}" -S "${dependencies_dir}/${_obs_destination}" -B
|
|
"${dependencies_dir}/${_obs_destination}/build_${arch}" -G ${_cmake_generator} ${_cmake_arch}
|
|
-DOBS_CMAKE_VERSION:STRING=3.0.0 -DENABLE_PLUGINS:BOOL=OFF -DENABLE_FRONTEND:BOOL=OFF
|
|
-DENABLE_UI:BOOL=OFF -DENABLE_SCRIPTING:BOOL=OFF -DENABLE_BROWSER:BOOL=OFF
|
|
-DOBS_VERSION_OVERRIDE:STRING=${_obs_version} "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${_is_fresh}
|
|
${_cmake_extra}
|
|
RESULT_VARIABLE _process_result
|
|
COMMAND_ERROR_IS_FATAL ANY
|
|
)
|
|
message(STATUS "Configure ${label} (${arch}) - done")
|
|
|
|
message(STATUS "Build ${label} (Release - ${arch})")
|
|
execute_process(
|
|
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target libobs --config Release --parallel
|
|
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
|
RESULT_VARIABLE _process_result
|
|
COMMAND_ERROR_IS_FATAL ANY
|
|
)
|
|
message(STATUS "Build ${label} (Release - ${arch}) - done")
|
|
|
|
message(STATUS "Install ${label} (${arch})")
|
|
execute_process(
|
|
COMMAND
|
|
"${CMAKE_COMMAND}" --install build_${arch} --component Development --config Release --prefix "${dependencies_dir}"
|
|
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
|
RESULT_VARIABLE _process_result
|
|
COMMAND_ERROR_IS_FATAL ANY
|
|
)
|
|
message(STATUS "Install ${label} (${arch}) - done")
|
|
endfunction()
|
|
|
|
# _check_dependencies: Fetch and extract pre-built OBS build dependencies
|
|
function(_check_dependencies)
|
|
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/buildspec.json" buildspec)
|
|
|
|
string(JSON dependency_data GET ${buildspec} dependencies)
|
|
|
|
foreach(dependency IN LISTS dependencies_list)
|
|
string(JSON data GET ${dependency_data} ${dependency})
|
|
string(JSON version GET ${data} version)
|
|
string(JSON hash GET ${data} hashes ${platform})
|
|
string(JSON url GET ${data} baseUrl)
|
|
string(JSON label GET ${data} label)
|
|
string(JSON revision ERROR_VARIABLE error GET ${data} revision ${platform})
|
|
|
|
message(STATUS "Setting up ${label} (${arch})")
|
|
|
|
set(file "${${dependency}_filename}")
|
|
set(destination "${${dependency}_destination}")
|
|
string(REPLACE "VERSION" "${version}" file "${file}")
|
|
string(REPLACE "VERSION" "${version}" destination "${destination}")
|
|
string(REPLACE "ARCH" "${arch}" file "${file}")
|
|
string(REPLACE "ARCH" "${arch}" destination "${destination}")
|
|
if(revision)
|
|
string(REPLACE "_REVISION" "_v${revision}" file "${file}")
|
|
string(REPLACE "-REVISION" "-v${revision}" file "${file}")
|
|
else()
|
|
string(REPLACE "_REVISION" "" file "${file}")
|
|
string(REPLACE "-REVISION" "" file "${file}")
|
|
endif()
|
|
|
|
if(EXISTS "${dependencies_dir}/.dependency_${dependency}_${arch}.sha256")
|
|
file(
|
|
READ
|
|
"${dependencies_dir}/.dependency_${dependency}_${arch}.sha256"
|
|
OBS_DEPENDENCY_${dependency}_${arch}_HASH
|
|
)
|
|
endif()
|
|
|
|
set(skip FALSE)
|
|
if(dependency STREQUAL prebuilt OR dependency STREQUAL qt6)
|
|
if(OBS_DEPENDENCY_${dependency}_${arch}_HASH STREQUAL ${hash})
|
|
_check_deps_version(${version})
|
|
|
|
if(found)
|
|
set(skip TRUE)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(skip)
|
|
message(STATUS "Setting up ${label} (${arch}) - skipped")
|
|
continue()
|
|
endif()
|
|
|
|
if(dependency STREQUAL obs-studio)
|
|
set(url ${url}/${file})
|
|
else()
|
|
set(url ${url}/${version}/${file})
|
|
endif()
|
|
|
|
if(NOT EXISTS "${dependencies_dir}/${file}")
|
|
message(STATUS "Downloading ${url}")
|
|
file(DOWNLOAD "${url}" "${dependencies_dir}/${file}" STATUS download_status EXPECTED_HASH SHA256=${hash})
|
|
|
|
list(GET download_status 0 error_code)
|
|
list(GET download_status 1 error_message)
|
|
if(error_code GREATER 0)
|
|
message(STATUS "Downloading ${url} - Failure")
|
|
message(FATAL_ERROR "Unable to download ${url}, failed with error: ${error_message}")
|
|
file(REMOVE "${dependencies_dir}/${file}")
|
|
else()
|
|
message(STATUS "Downloading ${url} - done")
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT OBS_DEPENDENCY_${dependency}_${arch}_HASH STREQUAL ${hash})
|
|
file(REMOVE_RECURSE "${dependencies_dir}/${destination}")
|
|
endif()
|
|
|
|
if(NOT EXISTS "${dependencies_dir}/${destination}")
|
|
file(MAKE_DIRECTORY "${dependencies_dir}/${destination}")
|
|
if(dependency STREQUAL obs-studio)
|
|
file(ARCHIVE_EXTRACT INPUT "${dependencies_dir}/${file}" DESTINATION "${dependencies_dir}")
|
|
else()
|
|
file(ARCHIVE_EXTRACT INPUT "${dependencies_dir}/${file}" DESTINATION "${dependencies_dir}/${destination}")
|
|
endif()
|
|
endif()
|
|
|
|
file(WRITE "${dependencies_dir}/.dependency_${dependency}_${arch}.sha256" "${hash}")
|
|
|
|
if(dependency STREQUAL prebuilt)
|
|
list(APPEND CMAKE_PREFIX_PATH "${dependencies_dir}/${destination}")
|
|
elseif(dependency STREQUAL qt6)
|
|
list(APPEND CMAKE_PREFIX_PATH "${dependencies_dir}/${destination}")
|
|
elseif(dependency STREQUAL obs-studio)
|
|
set(_obs_version ${version})
|
|
set(_obs_destination "${destination}")
|
|
list(APPEND CMAKE_PREFIX_PATH "${dependencies_dir}")
|
|
endif()
|
|
|
|
message(STATUS "Setting up ${label} (${arch}) - done")
|
|
endforeach()
|
|
|
|
list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH)
|
|
|
|
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} CACHE PATH "CMake prefix search path" FORCE)
|
|
|
|
_setup_obs_studio()
|
|
endfunction()
|