mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-07 03:53:38 +00:00
Qt Gui virtualkeyboard plugin was removed in Qt 6.x. Qt Network Bearer Management was removed in Qt 6.0. Qt Multimedia mediaservice and audio plugins were removed in Qt 6.x.
502 lines
17 KiB
CMake
502 lines
17 KiB
CMake
# OBS CMake common helper functions module
|
|
|
|
# cmake-format: off
|
|
# cmake-lint: disable=C0103
|
|
# cmake-lint: disable=E1121
|
|
# cmake-format: on
|
|
|
|
include_guard(GLOBAL)
|
|
|
|
# message_configuration: Function to print configuration outcome
|
|
function(message_configuration)
|
|
include(FeatureSummary)
|
|
feature_summary(WHAT ALL VAR _feature_summary)
|
|
|
|
message(DEBUG "${_feature_summary}")
|
|
|
|
message(
|
|
NOTICE
|
|
" _ _ _ _ \n"
|
|
" ___ | |__ ___ ___| |_ _ _ __| (_) ___ \n"
|
|
" / _ \\| '_ \\/ __|_____/ __| __| | | |/ _` | |/ _ \\ \n"
|
|
" | (_) | |_) \\__ \\_____\\__ \\ |_| |_| | (_| | | (_) |\n"
|
|
" \\___/|_.__/|___/ |___/\\__|\\__,_|\\__,_|_|\\___/ \n"
|
|
"\nOBS: Application Version: ${OBS_VERSION} - Build Number: ${OBS_BUILD_NUMBER}\n"
|
|
"==================================================================================\n\n")
|
|
|
|
get_property(OBS_FEATURES_ENABLED GLOBAL PROPERTY OBS_FEATURES_ENABLED)
|
|
list(
|
|
SORT OBS_FEATURES_ENABLED
|
|
COMPARE NATURAL
|
|
CASE SENSITIVE
|
|
ORDER ASCENDING)
|
|
|
|
if(OBS_FEATURES_ENABLED)
|
|
message(NOTICE "------------------------ Enabled Features ------------------------")
|
|
foreach(feature IN LISTS OBS_FEATURES_ENABLED)
|
|
message(NOTICE " - ${feature}")
|
|
endforeach()
|
|
endif()
|
|
|
|
get_property(OBS_FEATURES_DISABLED GLOBAL PROPERTY OBS_FEATURES_DISABLED)
|
|
list(
|
|
SORT OBS_FEATURES_DISABLED
|
|
COMPARE NATURAL
|
|
CASE SENSITIVE
|
|
ORDER ASCENDING)
|
|
|
|
if(OBS_FEATURES_DISABLED)
|
|
message(NOTICE "------------------------ Disabled Features ------------------------")
|
|
foreach(feature IN LISTS OBS_FEATURES_DISABLED)
|
|
message(NOTICE " - ${feature}")
|
|
endforeach()
|
|
endif()
|
|
|
|
if(ENABLE_PLUGINS)
|
|
get_property(OBS_MODULES_ENABLED GLOBAL PROPERTY OBS_MODULES_ENABLED)
|
|
list(
|
|
SORT OBS_MODULES_ENABLED
|
|
COMPARE NATURAL
|
|
CASE SENSITIVE
|
|
ORDER ASCENDING)
|
|
|
|
if(OBS_MODULES_ENABLED)
|
|
message(NOTICE "------------------------ Enabled Modules ------------------------")
|
|
foreach(feature IN LISTS OBS_MODULES_ENABLED)
|
|
message(NOTICE " - ${feature}")
|
|
endforeach()
|
|
endif()
|
|
|
|
get_property(OBS_MODULES_DISABLED GLOBAL PROPERTY OBS_MODULES_DISABLED)
|
|
list(
|
|
SORT OBS_MODULES_DISABLED
|
|
COMPARE NATURAL
|
|
CASE SENSITIVE
|
|
ORDER ASCENDING)
|
|
|
|
if(OBS_MODULES_DISABLED)
|
|
message(NOTICE "------------------------ Disabled Modules ------------------------")
|
|
foreach(feature IN LISTS OBS_MODULES_DISABLED)
|
|
message(NOTICE " - ${feature}")
|
|
endforeach()
|
|
endif()
|
|
endif()
|
|
message(NOTICE "----------------------------------------------------------------------------------")
|
|
endfunction()
|
|
|
|
# target_enable_feature: Adds feature to list of enabled application features and sets optional compile definitions
|
|
function(target_enable_feature target feature_description)
|
|
set_property(GLOBAL APPEND PROPERTY OBS_FEATURES_ENABLED "${feature_description}")
|
|
|
|
if(ARGN)
|
|
target_compile_definitions(${target} PRIVATE ${ARGN})
|
|
endif()
|
|
endfunction()
|
|
|
|
# target_disable_feature: Adds feature to list of disabled application features and sets optional compile definitions
|
|
function(target_disable_feature target feature_description)
|
|
set_property(GLOBAL APPEND PROPERTY OBS_FEATURES_DISABLED "${feature_description}")
|
|
|
|
if(ARGN)
|
|
target_compile_definitions(${target} PRIVATE ${ARGN})
|
|
endif()
|
|
endfunction()
|
|
|
|
# target_disable: Adds target to list of disabled modules
|
|
function(target_disable target)
|
|
set_property(GLOBAL APPEND PROPERTY OBS_MODULES_DISABLED ${target})
|
|
endfunction()
|
|
|
|
# _handle_generator_expression_dependency: Helper function to yield dependency from a generator expression
|
|
function(_handle_generator_expression_dependency library)
|
|
set(oneValueArgs FOUND_VAR)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(var "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
set(${var_FOUND_VAR} "${var_FOUND_VAR}-NOTFOUND")
|
|
|
|
message(DEBUG "Checking ${library}...")
|
|
|
|
if(library MATCHES "\\$<\\$<PLATFORM_ID:[^>]+>:.+>" OR library MATCHES "\\$<\\$<NOT:\\$<PLATFORM_ID:[^>]+>>:.+>")
|
|
# Platform-dependent generator expression found. Platforms are a comma-separated list of CMake host OS identifiers.
|
|
# Convert to CMake list and check if current host OS is contained in list.
|
|
string(REGEX REPLACE "\\$<.*\\$<PLATFORM_ID:([^>]+)>>?:([^>]+)>" "\\1;\\2" gen_expression "${library}")
|
|
list(GET gen_expression 0 gen_platform)
|
|
list(GET gen_expression 1 gen_library)
|
|
string(REPLACE "," ";" gen_platform "${gen_platform}")
|
|
|
|
set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
|
|
|
|
if(library MATCHES "\\$<\\$<NOT:.+>.+>")
|
|
if(NOT CMAKE_SYSTEM_NAME IN_LIST gen_platform)
|
|
set(${var_FOUND_VAR} "${gen_library}")
|
|
endif()
|
|
else()
|
|
if(CMAKE_SYSTEM_NAME IN_LIST gen_platform)
|
|
set(${var_FOUND_VAR} "${gen_library}")
|
|
endif()
|
|
endif()
|
|
elseif(library MATCHES "\\$<\\$<BOOL:[^>]+>:.+>")
|
|
# Boolean generator expression found. Consider parameter a CMake variable that resolves into a CMake-like boolean
|
|
# value for a simple conditional check.
|
|
string(REGEX REPLACE "\\$<\\$<BOOL:([^>]+)>:([^>]+)>" "\\1;\\2" gen_expression "${library}")
|
|
list(GET gen_expression 0 gen_boolean)
|
|
list(GET gen_expression 1 gen_library)
|
|
|
|
set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
|
|
|
|
if(${gen_boolean})
|
|
set(${var_FOUND_VAR} "${gen_library}")
|
|
endif()
|
|
elseif(library MATCHES "\\$<TARGET_NAME_IF_EXISTS:[^>]+>")
|
|
# Target-dependent generator expression found. Consider parameter to be a CMake target identifier and check for
|
|
# target existence.
|
|
string(REGEX REPLACE "\\$<TARGET_NAME_IF_EXISTS:([^>]+)>" "\\1" gen_target "${library}")
|
|
|
|
set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
|
|
|
|
if(TARGET ${gen_target})
|
|
set(${var_FOUND_VAR} "${gen_target}")
|
|
endif()
|
|
elseif(library MATCHES "\\$<.*Qt6::EntryPointPrivate>" OR library MATCHES "\\$<.*Qt6::QDarwin.+PermissionPlugin>")
|
|
set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
|
|
else()
|
|
# Unknown or unimplemented generator expression found. Abort script run to either add to ignore list or implement
|
|
# detection.
|
|
message(FATAL_ERROR "${library} is an unsupported generator expression for linked libraries.")
|
|
endif()
|
|
|
|
if(CMAKE_VERSION VERSION_LESS 3.25)
|
|
set(${var_FOUND_VAR}
|
|
${var_FOUND_VAR}
|
|
PARENT_SCOPE)
|
|
else()
|
|
return(PROPAGATE ${var_FOUND_VAR})
|
|
endif()
|
|
endfunction()
|
|
|
|
# find_dependencies: Check linked interface and direct dependencies of target
|
|
function(find_dependencies)
|
|
set(oneValueArgs TARGET FOUND_VAR)
|
|
set(multiValueArgs)
|
|
cmake_parse_arguments(var "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
if(NOT DEFINED is_root)
|
|
# Root of recursive dependency resolution
|
|
set(is_root TRUE)
|
|
set(nested_depth 0)
|
|
else()
|
|
# Branch of recursive dependency resolution
|
|
set(is_root FALSE)
|
|
math(EXPR nested_depth "${nested_depth}+1")
|
|
endif()
|
|
|
|
# * LINK_LIBRARIES are direct dependencies
|
|
# * INTERFACE_LINK_LIBRARIES are transitive dependencies
|
|
get_target_property(linked_libraries ${var_TARGET} LINK_LIBRARIES)
|
|
get_target_property(interface_libraries ${var_TARGET} INTERFACE_LINK_LIBRARIES)
|
|
message(DEBUG "[${nested_depth}] Linked libraries in target ${var_TARGET}: ${linked_libraries}")
|
|
message(DEBUG "[${nested_depth}] Linked interface libraries in target ${var_TARGET}: ${interface_libraries}")
|
|
|
|
# Consider CMake targets only
|
|
list(FILTER linked_libraries INCLUDE REGEX ".+::.+")
|
|
list(FILTER interface_libraries INCLUDE REGEX ".+::.+")
|
|
|
|
foreach(library IN LISTS linked_libraries interface_libraries)
|
|
if(NOT library)
|
|
continue()
|
|
elseif(library MATCHES "\\$<.*:[^>]+>")
|
|
# Generator expression found
|
|
_handle_generator_expression_dependency(${library} FOUND_VAR found_library)
|
|
if(found_library STREQUAL found_library-SKIP)
|
|
continue()
|
|
elseif(found_library)
|
|
set(library ${found_library})
|
|
endif()
|
|
endif()
|
|
|
|
message(DEBUG "[${nested_depth}] Found ${library}...")
|
|
|
|
if(NOT library IN_LIST ${var_FOUND_VAR})
|
|
list(APPEND found_libraries ${library})
|
|
# Enter recursive branch
|
|
find_dependencies(TARGET ${library} FOUND_VAR ${var_FOUND_VAR})
|
|
endif()
|
|
endforeach()
|
|
|
|
if(NOT is_root)
|
|
# cmake-format: off
|
|
set(found_libraries ${found_libraries} PARENT_SCOPE)
|
|
# cmake-format: on
|
|
# Exit recursive branch
|
|
return()
|
|
endif()
|
|
|
|
list(REMOVE_DUPLICATES found_libraries)
|
|
list(APPEND ${var_FOUND_VAR} ${found_libraries})
|
|
# cmake-format: off
|
|
set(${var_FOUND_VAR} ${${var_FOUND_VAR}} PARENT_SCOPE)
|
|
# cmake-format: on
|
|
endfunction()
|
|
|
|
# find_qt_plugins: Find and add Qt plugin libraries associated with Qt component to target
|
|
function(find_qt_plugins)
|
|
set(oneValueArgs COMPONENT TARGET FOUND_VAR)
|
|
cmake_parse_arguments(var "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
string(REPLACE "::" ";" library_tuple "${var_COMPONENT}")
|
|
list(GET library_tuple 0 library_namespace)
|
|
list(GET library_tuple 1 library_name)
|
|
|
|
if(NOT ${library_namespace} MATCHES "Qt6?")
|
|
message(FATAL_ERROR "'find_qt_plugins' has to be called with a valid target from the Qt or Qt6 namespace.")
|
|
endif()
|
|
|
|
# cmake-format: off
|
|
list(APPEND qt_plugins_Core platforms printsupport styles imageformats iconengines)
|
|
# cmake-format: on
|
|
list(APPEND qt_plugins_Gui platforminputcontexts)
|
|
list(APPEND qt_plugins_Sql sqldrivers)
|
|
list(APPEND qt_plugins_3dRender sceneparsers geometryloaders)
|
|
list(APPEND qt_plugins_3dQuickRender renderplugins)
|
|
list(APPEND qt_plugins_Positioning position)
|
|
list(APPEND qt_plugins_Location geoservices)
|
|
list(APPEND qt_plugins_TextToSpeech texttospeech)
|
|
list(APPEND qt_plugins_WebView webview)
|
|
|
|
if(qt_plugins_${library_name})
|
|
get_target_property(library_location ${var_COMPONENT} IMPORTED_LOCATION)
|
|
get_target_property(is_framework ${var_COMPONENT} FRAMEWORK)
|
|
|
|
if(is_framework)
|
|
# Resolve Qt plugin location relative to framework binary location on macOS
|
|
set(plugins_location "../../../../../plugins")
|
|
cmake_path(ABSOLUTE_PATH plugins_location BASE_DIRECTORY "${library_location}" NORMALIZE)
|
|
else()
|
|
# Resolve Qt plugin location relative to dynamic library location
|
|
set(plugins_location "../../plugins")
|
|
cmake_path(ABSOLUTE_PATH plugins_location BASE_DIRECTORY "${library_location}" NORMALIZE)
|
|
endif()
|
|
|
|
foreach(plugin IN ITEMS ${qt_plugins_${library_name}})
|
|
if(NOT plugin IN_LIST plugins_list)
|
|
if(EXISTS "${plugins_location}/${plugin}")
|
|
# Gather all .dll or .dylib files in given plugin subdirectory
|
|
file(
|
|
GLOB plugin_libraries
|
|
RELATIVE "${plugins_location}/${plugin}"
|
|
"${plugins_location}/${plugin}/*.dylib" "${plugins_location}/${plugin}/*.dll")
|
|
message(DEBUG "Found Qt plugin ${plugin} libraries: ${plugin_libraries}")
|
|
foreach(plugin_library IN ITEMS ${plugin_libraries})
|
|
set(plugin_full_path "${plugins_location}/${plugin}/${plugin_library}")
|
|
list(APPEND plugins_list ${plugin_full_path})
|
|
endforeach()
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
# cmake-format: off
|
|
set(${var_FOUND_VAR} ${plugins_list} PARENT_SCOPE)
|
|
# cmake-format: on
|
|
endfunction()
|
|
|
|
# target_export: Helper function to export target as CMake package
|
|
function(target_export target)
|
|
if(NOT DEFINED exclude_variant)
|
|
set(exclude_variant EXCLUDE_FROM_ALL)
|
|
endif()
|
|
|
|
get_target_property(is_framework ${target} FRAMEWORK)
|
|
if(is_framework)
|
|
set(package_destination "Frameworks/${target}.framework/Resources/cmake")
|
|
set(include_destination "Frameworks/${target}.framework/Headers")
|
|
else()
|
|
set(package_destination "${OBS_CMAKE_DESTINATION}/${target}")
|
|
set(include_destination "${OBS_INCLUDE_DESTINATION}")
|
|
endif()
|
|
|
|
install(
|
|
TARGETS ${target}
|
|
EXPORT ${target}Targets
|
|
RUNTIME DESTINATION "${OBS_EXECUTABLE_DESTINATION}"
|
|
COMPONENT Development
|
|
${exclude_variant}
|
|
LIBRARY DESTINATION "${OBS_LIBRARY_DESTINATION}"
|
|
COMPONENT Development
|
|
${exclude_variant}
|
|
ARCHIVE DESTINATION "${OBS_LIBRARY_DESTINATION}"
|
|
COMPONENT Development
|
|
${exclude_variant}
|
|
FRAMEWORK DESTINATION Frameworks
|
|
COMPONENT Development
|
|
${exclude_variant}
|
|
INCLUDES
|
|
DESTINATION "${include_destination}"
|
|
PUBLIC_HEADER
|
|
DESTINATION "${include_destination}"
|
|
COMPONENT Development
|
|
${exclude_variant})
|
|
|
|
get_target_property(obs_public_headers ${target} OBS_PUBLIC_HEADERS)
|
|
|
|
if(obs_public_headers)
|
|
foreach(header IN LISTS obs_public_headers)
|
|
cmake_path(GET header PARENT_PATH header_dir)
|
|
if(header_dir)
|
|
if(NOT ${header_dir} IN_LIST header_dirs)
|
|
list(APPEND header_dirs ${header_dir})
|
|
endif()
|
|
list(APPEND headers_${header_dir} ${header})
|
|
else()
|
|
list(APPEND headers ${header})
|
|
endif()
|
|
endforeach()
|
|
|
|
foreach(header_dir IN LISTS header_dirs)
|
|
install(
|
|
FILES ${headers_${header_dir}}
|
|
DESTINATION "${include_destination}/${header_dir}"
|
|
COMPONENT Development
|
|
${exclude_variant})
|
|
endforeach()
|
|
|
|
if(headers)
|
|
install(
|
|
FILES ${headers}
|
|
DESTINATION "${include_destination}"
|
|
COMPONENT Development
|
|
${exclude_variant})
|
|
endif()
|
|
endif()
|
|
|
|
if(target STREQUAL libobs AND NOT EXISTS "${include_destination}/obsconfig.h")
|
|
install(
|
|
FILES "${CMAKE_BINARY_DIR}/config/obsconfig.h"
|
|
DESTINATION "${include_destination}"
|
|
COMPONENT Development
|
|
${exclude_variant})
|
|
endif()
|
|
|
|
get_target_property(target_type ${target} TYPE)
|
|
|
|
if(NOT target_type STREQUAL INTERFACE_LIBRARY)
|
|
message(DEBUG "Generating export header for target ${target} as ${target}_EXPORT.h...")
|
|
include(GenerateExportHeader)
|
|
generate_export_header(${target} EXPORT_FILE_NAME "${target}_EXPORT.h")
|
|
target_sources(${target} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/${target}_EXPORT.h>)
|
|
|
|
set_property(
|
|
TARGET ${target}
|
|
APPEND
|
|
PROPERTY PUBLIC_HEADER "${target}_EXPORT.h")
|
|
endif()
|
|
|
|
set(TARGETS_EXPORT_NAME ${target}Targets)
|
|
message(
|
|
DEBUG
|
|
"Generating CMake package configuration file ${target}Config.cmake with targets file ${TARGETS_EXPORT_NAME}...")
|
|
include(CMakePackageConfigHelpers)
|
|
configure_package_config_file(cmake/${target}Config.cmake.in ${target}Config.cmake
|
|
INSTALL_DESTINATION "${package_destination}")
|
|
|
|
message(DEBUG "Generating CMake package version configuration file ${target}ConfigVersion.cmake...")
|
|
write_basic_package_version_file(
|
|
"${target}ConfigVersion.cmake"
|
|
VERSION ${OBS_VERSION_CANONICAL}
|
|
COMPATIBILITY SameMajorVersion)
|
|
|
|
export(
|
|
EXPORT ${target}Targets
|
|
FILE "${TARGETS_EXPORT_NAME}.cmake"
|
|
NAMESPACE OBS::)
|
|
|
|
export(PACKAGE ${target})
|
|
|
|
install(
|
|
EXPORT ${TARGETS_EXPORT_NAME}
|
|
FILE ${TARGETS_EXPORT_NAME}.cmake
|
|
NAMESPACE OBS::
|
|
DESTINATION "${package_destination}"
|
|
COMPONENT Development
|
|
${exclude_variant})
|
|
|
|
install(
|
|
FILES "${CMAKE_CURRENT_BINARY_DIR}/${target}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${target}ConfigVersion.cmake"
|
|
DESTINATION "${package_destination}"
|
|
COMPONENT Development
|
|
${exclude_variant})
|
|
endfunction()
|
|
|
|
# check_uuid: Helper function to check for valid UUID
|
|
function(check_uuid uuid_string return_value)
|
|
set(valid_uuid TRUE)
|
|
set(uuid_token_lengths 8 4 4 4 12)
|
|
set(token_num 0)
|
|
|
|
string(REPLACE "-" ";" uuid_tokens ${uuid_string})
|
|
list(LENGTH uuid_tokens uuid_num_tokens)
|
|
|
|
if(uuid_num_tokens EQUAL 5)
|
|
message(DEBUG "UUID ${uuid_string} is valid with 5 tokens.")
|
|
foreach(uuid_token IN LISTS uuid_tokens)
|
|
list(GET uuid_token_lengths ${token_num} uuid_target_length)
|
|
string(LENGTH "${uuid_token}" uuid_actual_length)
|
|
if(uuid_actual_length EQUAL uuid_target_length)
|
|
string(REGEX MATCH "[0-9a-fA-F]+" uuid_hex_match ${uuid_token})
|
|
if(NOT uuid_hex_match STREQUAL uuid_token)
|
|
set(valid_uuid FALSE)
|
|
break()
|
|
endif()
|
|
else()
|
|
set(valid_uuid FALSE)
|
|
break()
|
|
endif()
|
|
math(EXPR token_num "${token_num}+1")
|
|
endforeach()
|
|
else()
|
|
set(valid_uuid FALSE)
|
|
endif()
|
|
message(DEBUG "UUID ${uuid_string} valid: ${valid_uuid}")
|
|
# cmake-format: off
|
|
set(${return_value} ${valid_uuid} PARENT_SCOPE)
|
|
# cmake-format: on
|
|
endfunction()
|
|
|
|
# legacy_check: Check if new CMake framework was not enabled and load legacy rules instead
|
|
macro(legacy_check)
|
|
if(OBS_CMAKE_VERSION VERSION_LESS 3.0.0)
|
|
message(FATAL_ERROR "CMake version changed between CMakeLists.txt.")
|
|
endif()
|
|
endmacro()
|
|
|
|
# add_obs_plugin: Add plugin subdirectory if host platform is in specified list of supported platforms
|
|
function(add_obs_plugin target)
|
|
set(options WITH_MESSAGE)
|
|
set(oneValueArgs "")
|
|
set(multiValueArgs PLATFORMS)
|
|
cmake_parse_arguments(PARSE_ARGV 0 _AOP "${options}" "${oneValueArgs}" "${multiValueArgs}")
|
|
|
|
set(found_platform FALSE)
|
|
list(LENGTH _AOP_PLATFORMS _AOP_NUM_PLATFORMS)
|
|
|
|
if(_AOP_NUM_PLATFORMS EQUAL 0)
|
|
set(found_platform TRUE)
|
|
else()
|
|
foreach(platform IN LISTS _AOP_PLATFORMS)
|
|
set(check_var_name "OS_${platform}")
|
|
if(${${check_var_name}})
|
|
set(found_platform TRUE)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
if(found_platform)
|
|
add_subdirectory(${target})
|
|
elseif(_AOP_WITH_MESSAGE)
|
|
add_custom_target(${target} COMMENT "Dummy target for unavailable module ${target}")
|
|
target_disable(${target})
|
|
endif()
|
|
endfunction()
|