helpers_common.cmake 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. # OBS CMake common helper functions module
  2. # cmake-format: off
  3. # cmake-lint: disable=C0103
  4. # cmake-lint: disable=E1121
  5. # cmake-format: on
  6. include_guard(GLOBAL)
  7. # message_configuration: Function to print configuration outcome
  8. function(message_configuration)
  9. include(FeatureSummary)
  10. feature_summary(WHAT ALL VAR _feature_summary)
  11. message(DEBUG "${_feature_summary}")
  12. message(
  13. NOTICE
  14. " _ _ _ _ \n"
  15. " ___ | |__ ___ ___| |_ _ _ __| (_) ___ \n"
  16. " / _ \\| '_ \\/ __|_____/ __| __| | | |/ _` | |/ _ \\ \n"
  17. " | (_) | |_) \\__ \\_____\\__ \\ |_| |_| | (_| | | (_) |\n"
  18. " \\___/|_.__/|___/ |___/\\__|\\__,_|\\__,_|_|\\___/ \n"
  19. "\nOBS: Application Version: ${OBS_VERSION} - Build Number: ${OBS_BUILD_NUMBER}\n"
  20. "==================================================================================\n\n")
  21. get_property(OBS_FEATURES_ENABLED GLOBAL PROPERTY OBS_FEATURES_ENABLED)
  22. list(
  23. SORT OBS_FEATURES_ENABLED
  24. COMPARE NATURAL
  25. CASE SENSITIVE
  26. ORDER ASCENDING)
  27. if(OBS_FEATURES_ENABLED)
  28. message(NOTICE "------------------------ Enabled Features ------------------------")
  29. foreach(feature IN LISTS OBS_FEATURES_ENABLED)
  30. message(NOTICE " - ${feature}")
  31. endforeach()
  32. endif()
  33. get_property(OBS_FEATURES_DISABLED GLOBAL PROPERTY OBS_FEATURES_DISABLED)
  34. list(
  35. SORT OBS_FEATURES_DISABLED
  36. COMPARE NATURAL
  37. CASE SENSITIVE
  38. ORDER ASCENDING)
  39. if(OBS_FEATURES_DISABLED)
  40. message(NOTICE "------------------------ Disabled Features ------------------------")
  41. foreach(feature IN LISTS OBS_FEATURES_DISABLED)
  42. message(NOTICE " - ${feature}")
  43. endforeach()
  44. endif()
  45. if(ENABLE_PLUGINS)
  46. get_property(OBS_MODULES_ENABLED GLOBAL PROPERTY OBS_MODULES_ENABLED)
  47. list(
  48. SORT OBS_MODULES_ENABLED
  49. COMPARE NATURAL
  50. CASE SENSITIVE
  51. ORDER ASCENDING)
  52. if(OBS_MODULES_ENABLED)
  53. message(NOTICE "------------------------ Enabled Modules ------------------------")
  54. foreach(feature IN LISTS OBS_MODULES_ENABLED)
  55. message(NOTICE " - ${feature}")
  56. endforeach()
  57. endif()
  58. get_property(OBS_MODULES_DISABLED GLOBAL PROPERTY OBS_MODULES_DISABLED)
  59. list(
  60. SORT OBS_MODULES_DISABLED
  61. COMPARE NATURAL
  62. CASE SENSITIVE
  63. ORDER ASCENDING)
  64. if(OBS_MODULES_DISABLED)
  65. message(NOTICE "------------------------ Disabled Modules ------------------------")
  66. foreach(feature IN LISTS OBS_MODULES_DISABLED)
  67. message(NOTICE " - ${feature}")
  68. endforeach()
  69. endif()
  70. endif()
  71. message(NOTICE "----------------------------------------------------------------------------------")
  72. endfunction()
  73. # target_enable_feature: Adds feature to list of enabled application features and sets optional compile definitions
  74. function(target_enable_feature target feature_description)
  75. set_property(GLOBAL APPEND PROPERTY OBS_FEATURES_ENABLED "${feature_description}")
  76. if(ARGN)
  77. target_compile_definitions(${target} PRIVATE ${ARGN})
  78. endif()
  79. endfunction()
  80. # target_disable_feature: Adds feature to list of disabled application features and sets optional compile definitions
  81. function(target_disable_feature target feature_description)
  82. set_property(GLOBAL APPEND PROPERTY OBS_FEATURES_DISABLED "${feature_description}")
  83. if(ARGN)
  84. target_compile_definitions(${target} PRIVATE ${ARGN})
  85. endif()
  86. endfunction()
  87. # target_disable: Adds target to list of disabled modules
  88. function(target_disable target)
  89. set_property(GLOBAL APPEND PROPERTY OBS_MODULES_DISABLED ${target})
  90. endfunction()
  91. # find_qt: Macro to find best possible Qt version for use with the project:
  92. macro(find_qt)
  93. set(multiValueArgs COMPONENTS COMPONENTS_WIN COMPONENTS_MAC COMPONENTS_LINUX)
  94. cmake_parse_arguments(find_qt "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  95. # Do not use versionless targets in the first step to avoid Qt::Core being clobbered by later opportunistic
  96. # find_package runs
  97. set(QT_NO_CREATE_VERSIONLESS_TARGETS TRUE)
  98. message(DEBUG "Attempting to find Qt 6")
  99. find_package(
  100. Qt6
  101. COMPONENTS Core
  102. REQUIRED)
  103. # Enable versionless targets for the remaining Qt components
  104. set(QT_NO_CREATE_VERSIONLESS_TARGETS FALSE)
  105. set(qt_components ${find_qt_COMPONENTS})
  106. if(OS_WINDOWS)
  107. list(APPEND qt_components ${find_qt_COMPONENTS_WIN})
  108. elseif(OS_MACOS)
  109. list(APPEND qt_components ${find_qt_COMPONENTS_MAC})
  110. else()
  111. list(APPEND qt_components ${find_qt_COMPONENTS_LINUX})
  112. endif()
  113. message(DEBUG "Trying to find Qt components ${qt_components}...")
  114. find_package(Qt6 REQUIRED ${qt_components})
  115. list(APPEND qt_components Core)
  116. if("Gui" IN_LIST find_qt_COMPONENTS_LINUX)
  117. list(APPEND qt_components "GuiPrivate")
  118. endif()
  119. # Check for versionless targets of each requested component and create if necessary
  120. foreach(component IN LISTS qt_components)
  121. message(DEBUG "Checking for target Qt::${component}")
  122. if(NOT TARGET Qt::${component} AND TARGET Qt6::${component})
  123. add_library(Qt::${component} INTERFACE IMPORTED)
  124. set_target_properties(Qt::${component} PROPERTIES INTERFACE_LINK_LIBRARIES Qt6::${component})
  125. endif()
  126. endforeach()
  127. endmacro()
  128. # _handle_generator_expression_dependency: Helper function to yield dependency from a generator expression
  129. function(_handle_generator_expression_dependency library)
  130. set(oneValueArgs FOUND_VAR)
  131. set(multiValueArgs)
  132. cmake_parse_arguments(var "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  133. set(${var_FOUND_VAR} "${var_FOUND_VAR}-NOTFOUND")
  134. message(DEBUG "Checking ${library}...")
  135. if(library MATCHES "\\$<\\$<PLATFORM_ID:[^>]+>:.+>" OR library MATCHES "\\$<\\$<NOT:\\$<PLATFORM_ID:[^>]+>>:.+>")
  136. # Platform-dependent generator expression found. Platforms are a comma-separated list of CMake host OS identifiers.
  137. # Convert to CMake list and check if current host OS is contained in list.
  138. string(REGEX REPLACE "\\$<.*\\$<PLATFORM_ID:([^>]+)>>?:([^>]+)>" "\\1;\\2" gen_expression "${library}")
  139. list(GET gen_expression 0 gen_platform)
  140. list(GET gen_expression 1 gen_library)
  141. string(REPLACE "," ";" gen_platform "${gen_platform}")
  142. set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
  143. if(library MATCHES "\\$<\\$<NOT:.+>.+>")
  144. if(NOT CMAKE_SYSTEM_NAME IN_LIST gen_platform)
  145. set(${var_FOUND_VAR} "${gen_library}")
  146. endif()
  147. else()
  148. if(CMAKE_SYSTEM_NAME IN_LIST gen_platform)
  149. set(${var_FOUND_VAR} "${gen_library}")
  150. endif()
  151. endif()
  152. elseif(library MATCHES "\\$<\\$<BOOL:[^>]+>:.+>")
  153. # Boolean generator expression found. Consider parameter a CMake variable that resolves into a CMake-like boolean
  154. # value for a simple conditional check.
  155. string(REGEX REPLACE "\\$<\\$<BOOL:([^>]+)>:([^>]+)>" "\\1;\\2" gen_expression "${library}")
  156. list(GET gen_expression 0 gen_boolean)
  157. list(GET gen_expression 1 gen_library)
  158. set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
  159. if(${gen_boolean})
  160. set(${var_FOUND_VAR} "${gen_library}")
  161. endif()
  162. elseif(library MATCHES "\\$<TARGET_NAME_IF_EXISTS:[^>]+>")
  163. # Target-dependent generator expression found. Consider parameter to be a CMake target identifier and check for
  164. # target existence.
  165. string(REGEX REPLACE "\\$<TARGET_NAME_IF_EXISTS:([^>]+)>" "\\1" gen_target "${library}")
  166. set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
  167. if(TARGET ${gen_target})
  168. set(${var_FOUND_VAR} "${gen_target}")
  169. endif()
  170. elseif(library MATCHES "\\$<.*Qt6::EntryPointPrivate>" OR library MATCHES "\\$<.*Qt6::QDarwin.+PermissionPlugin>")
  171. set(${var_FOUND_VAR} "${var_FOUND_VAR}-SKIP")
  172. else()
  173. # Unknown or unimplemented generator expression found. Abort script run to either add to ignore list or implement
  174. # detection.
  175. message(FATAL_ERROR "${library} is an unsupported generator expression for linked libraries.")
  176. endif()
  177. if(CMAKE_VERSION VERSION_LESS 3.25)
  178. set(${var_FOUND_VAR}
  179. ${var_FOUND_VAR}
  180. PARENT_SCOPE)
  181. else()
  182. return(PROPAGATE ${var_FOUND_VAR})
  183. endif()
  184. endfunction()
  185. # find_dependencies: Check linked interface and direct dependencies of target
  186. function(find_dependencies)
  187. set(oneValueArgs TARGET FOUND_VAR)
  188. set(multiValueArgs)
  189. cmake_parse_arguments(var "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  190. if(NOT DEFINED is_root)
  191. # Root of recursive dependency resolution
  192. set(is_root TRUE)
  193. set(nested_depth 0)
  194. else()
  195. # Branch of recursive dependency resolution
  196. set(is_root FALSE)
  197. math(EXPR nested_depth "${nested_depth}+1")
  198. endif()
  199. # * LINK_LIBRARIES are direct dependencies
  200. # * INTERFACE_LINK_LIBRARIES are transitive dependencies
  201. get_target_property(linked_libraries ${var_TARGET} LINK_LIBRARIES)
  202. get_target_property(interface_libraries ${var_TARGET} INTERFACE_LINK_LIBRARIES)
  203. message(DEBUG "[${nested_depth}] Linked libraries in target ${var_TARGET}: ${linked_libraries}")
  204. message(DEBUG "[${nested_depth}] Linked interface libraries in target ${var_TARGET}: ${interface_libraries}")
  205. # Consider CMake targets only
  206. list(FILTER linked_libraries INCLUDE REGEX ".+::.+")
  207. list(FILTER interface_libraries INCLUDE REGEX ".+::.+")
  208. foreach(library IN LISTS linked_libraries interface_libraries)
  209. if(NOT library)
  210. continue()
  211. elseif(library MATCHES "\\$<.*:[^>]+>")
  212. # Generator expression found
  213. _handle_generator_expression_dependency(${library} FOUND_VAR found_library)
  214. if(found_library STREQUAL found_library-SKIP)
  215. continue()
  216. elseif(found_library)
  217. set(library ${found_library})
  218. endif()
  219. endif()
  220. message(DEBUG "[${nested_depth}] Found ${library}...")
  221. if(NOT library IN_LIST ${var_FOUND_VAR})
  222. list(APPEND found_libraries ${library})
  223. # Enter recursive branch
  224. find_dependencies(TARGET ${library} FOUND_VAR ${var_FOUND_VAR})
  225. endif()
  226. endforeach()
  227. if(NOT is_root)
  228. # cmake-format: off
  229. set(found_libraries ${found_libraries} PARENT_SCOPE)
  230. # cmake-format: on
  231. # Exit recursive branch
  232. return()
  233. endif()
  234. list(REMOVE_DUPLICATES found_libraries)
  235. list(APPEND ${var_FOUND_VAR} ${found_libraries})
  236. # cmake-format: off
  237. set(${var_FOUND_VAR} ${${var_FOUND_VAR}} PARENT_SCOPE)
  238. # cmake-format: on
  239. endfunction()
  240. # find_qt_plugins: Find and add Qt plugin libraries associated with Qt component to target
  241. function(find_qt_plugins)
  242. set(oneValueArgs COMPONENT TARGET FOUND_VAR)
  243. cmake_parse_arguments(var "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  244. string(REPLACE "::" ";" library_tuple "${var_COMPONENT}")
  245. list(GET library_tuple 0 library_namespace)
  246. list(GET library_tuple 1 library_name)
  247. if(NOT ${library_namespace} MATCHES "Qt6?")
  248. message(FATAL_ERROR "'find_qt_plugins' has to be called with a valid target from the Qt or Qt6 namespace.")
  249. endif()
  250. # cmake-format: off
  251. list(APPEND qt_plugins_Core platforms printsupport styles imageformats iconengines)
  252. # cmake-format: on
  253. list(APPEND qt_plugins_Gui platforminputcontexts virtualkeyboard)
  254. list(APPEND qt_plugins_Network bearer)
  255. list(APPEND qt_plugins_Sql sqldrivers)
  256. list(APPEND qt_plugins_Multimedia mediaservice audio)
  257. list(APPEND qt_plugins_3dRender sceneparsers geometryloaders)
  258. list(APPEND qt_plugins_3dQuickRender renderplugins)
  259. list(APPEND qt_plugins_Positioning position)
  260. list(APPEND qt_plugins_Location geoservices)
  261. list(APPEND qt_plugins_TextToSpeech texttospeech)
  262. list(APPEND qt_plugins_WebView webview)
  263. if(qt_plugins_${library_name})
  264. get_target_property(library_location ${var_COMPONENT} IMPORTED_LOCATION)
  265. get_target_property(is_framework ${var_COMPONENT} FRAMEWORK)
  266. if(is_framework)
  267. # Resolve Qt plugin location relative to framework binary location on macOS
  268. set(plugins_location "../../../../../plugins")
  269. cmake_path(ABSOLUTE_PATH plugins_location BASE_DIRECTORY "${library_location}" NORMALIZE)
  270. else()
  271. # Resolve Qt plugin location relative to dynamic library location
  272. set(plugins_location "../../plugins")
  273. cmake_path(ABSOLUTE_PATH plugins_location BASE_DIRECTORY "${library_location}" NORMALIZE)
  274. endif()
  275. foreach(plugin IN ITEMS ${qt_plugins_${library_name}})
  276. if(NOT plugin IN_LIST plugins_list)
  277. if(EXISTS "${plugins_location}/${plugin}")
  278. # Gather all .dll or .dylib files in given plugin subdirectory
  279. file(
  280. GLOB plugin_libraries
  281. RELATIVE "${plugins_location}/${plugin}"
  282. "${plugins_location}/${plugin}/*.dylib" "${plugins_location}/${plugin}/*.dll")
  283. message(DEBUG "Found Qt plugin ${plugin} libraries: ${plugin_libraries}")
  284. foreach(plugin_library IN ITEMS ${plugin_libraries})
  285. set(plugin_full_path "${plugins_location}/${plugin}/${plugin_library}")
  286. list(APPEND plugins_list ${plugin_full_path})
  287. endforeach()
  288. endif()
  289. endif()
  290. endforeach()
  291. endif()
  292. # cmake-format: off
  293. set(${var_FOUND_VAR} ${plugins_list} PARENT_SCOPE)
  294. # cmake-format: on
  295. endfunction()
  296. # target_export: Helper function to export target as CMake package
  297. function(target_export target)
  298. if(NOT DEFINED exclude_variant)
  299. set(exclude_variant EXCLUDE_FROM_ALL)
  300. endif()
  301. get_target_property(is_framework ${target} FRAMEWORK)
  302. if(is_framework)
  303. set(package_destination "Frameworks/${target}.framework/Resources/cmake")
  304. set(include_destination "Frameworks/${target}.framework/Headers")
  305. else()
  306. set(package_destination "${OBS_CMAKE_DESTINATION}/${target}")
  307. set(include_destination "${OBS_INCLUDE_DESTINATION}")
  308. endif()
  309. install(
  310. TARGETS ${target}
  311. EXPORT ${target}Targets
  312. RUNTIME DESTINATION "${OBS_EXECUTABLE_DESTINATION}"
  313. COMPONENT Development
  314. ${exclude_variant}
  315. LIBRARY DESTINATION "${OBS_LIBRARY_DESTINATION}"
  316. COMPONENT Development
  317. ${exclude_variant}
  318. ARCHIVE DESTINATION "${OBS_LIBRARY_DESTINATION}"
  319. COMPONENT Development
  320. ${exclude_variant}
  321. FRAMEWORK DESTINATION Frameworks
  322. COMPONENT Development
  323. ${exclude_variant}
  324. INCLUDES
  325. DESTINATION "${include_destination}"
  326. PUBLIC_HEADER
  327. DESTINATION "${include_destination}"
  328. COMPONENT Development
  329. ${exclude_variant})
  330. get_target_property(obs_public_headers ${target} OBS_PUBLIC_HEADERS)
  331. if(obs_public_headers)
  332. foreach(header IN LISTS obs_public_headers)
  333. cmake_path(GET header PARENT_PATH header_dir)
  334. if(header_dir)
  335. if(NOT ${header_dir} IN_LIST header_dirs)
  336. list(APPEND header_dirs ${header_dir})
  337. endif()
  338. list(APPEND headers_${header_dir} ${header})
  339. else()
  340. list(APPEND headers ${header})
  341. endif()
  342. endforeach()
  343. foreach(header_dir IN LISTS header_dirs)
  344. install(
  345. FILES ${headers_${header_dir}}
  346. DESTINATION "${include_destination}/${header_dir}"
  347. COMPONENT Development
  348. ${exclude_variant})
  349. endforeach()
  350. if(headers)
  351. install(
  352. FILES ${headers}
  353. DESTINATION "${include_destination}"
  354. COMPONENT Development
  355. ${exclude_variant})
  356. endif()
  357. endif()
  358. if(target STREQUAL libobs AND NOT EXISTS "${include_destination}/obsconfig.h")
  359. install(
  360. FILES "${CMAKE_BINARY_DIR}/config/obsconfig.h"
  361. DESTINATION "${include_destination}"
  362. COMPONENT Development
  363. ${exclude_variant})
  364. endif()
  365. get_target_property(target_type ${target} TYPE)
  366. if(NOT target_type STREQUAL INTERFACE_LIBRARY)
  367. message(DEBUG "Generating export header for target ${target} as ${target}_EXPORT.h...")
  368. include(GenerateExportHeader)
  369. generate_export_header(${target} EXPORT_FILE_NAME "${target}_EXPORT.h")
  370. target_sources(${target} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/${target}_EXPORT.h>)
  371. set_property(
  372. TARGET ${target}
  373. APPEND
  374. PROPERTY PUBLIC_HEADER "${target}_EXPORT.h")
  375. endif()
  376. set(TARGETS_EXPORT_NAME ${target}Targets)
  377. message(
  378. DEBUG
  379. "Generating CMake package configuration file ${target}Config.cmake with targets file ${TARGETS_EXPORT_NAME}...")
  380. include(CMakePackageConfigHelpers)
  381. configure_package_config_file(cmake/${target}Config.cmake.in ${target}Config.cmake
  382. INSTALL_DESTINATION "${package_destination}")
  383. message(DEBUG "Generating CMake package version configuration file ${target}ConfigVersion.cmake...")
  384. write_basic_package_version_file(
  385. "${target}ConfigVersion.cmake"
  386. VERSION ${OBS_VERSION_CANONICAL}
  387. COMPATIBILITY SameMajorVersion)
  388. export(
  389. EXPORT ${target}Targets
  390. FILE "${TARGETS_EXPORT_NAME}.cmake"
  391. NAMESPACE OBS::)
  392. export(PACKAGE ${target})
  393. install(
  394. EXPORT ${TARGETS_EXPORT_NAME}
  395. FILE ${TARGETS_EXPORT_NAME}.cmake
  396. NAMESPACE OBS::
  397. DESTINATION "${package_destination}"
  398. COMPONENT Development
  399. ${exclude_variant})
  400. install(
  401. FILES "${CMAKE_CURRENT_BINARY_DIR}/${target}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${target}ConfigVersion.cmake"
  402. DESTINATION "${package_destination}"
  403. COMPONENT Development
  404. ${exclude_variant})
  405. endfunction()
  406. # check_uuid: Helper function to check for valid UUID
  407. function(check_uuid uuid_string return_value)
  408. set(valid_uuid TRUE)
  409. set(uuid_token_lengths 8 4 4 4 12)
  410. set(token_num 0)
  411. string(REPLACE "-" ";" uuid_tokens ${uuid_string})
  412. list(LENGTH uuid_tokens uuid_num_tokens)
  413. if(uuid_num_tokens EQUAL 5)
  414. message(DEBUG "UUID ${uuid_string} is valid with 5 tokens.")
  415. foreach(uuid_token IN LISTS uuid_tokens)
  416. list(GET uuid_token_lengths ${token_num} uuid_target_length)
  417. string(LENGTH "${uuid_token}" uuid_actual_length)
  418. if(uuid_actual_length EQUAL uuid_target_length)
  419. string(REGEX MATCH "[0-9a-fA-F]+" uuid_hex_match ${uuid_token})
  420. if(NOT uuid_hex_match STREQUAL uuid_token)
  421. set(valid_uuid FALSE)
  422. break()
  423. endif()
  424. else()
  425. set(valid_uuid FALSE)
  426. break()
  427. endif()
  428. math(EXPR token_num "${token_num}+1")
  429. endforeach()
  430. else()
  431. set(valid_uuid FALSE)
  432. endif()
  433. message(DEBUG "UUID ${uuid_string} valid: ${valid_uuid}")
  434. # cmake-format: off
  435. set(${return_value} ${valid_uuid} PARENT_SCOPE)
  436. # cmake-format: on
  437. endfunction()
  438. # legacy_check: Check if new CMake framework was not enabled and load legacy rules instead
  439. macro(legacy_check)
  440. if(OBS_CMAKE_VERSION VERSION_LESS 3.0.0)
  441. message(FATAL_ERROR "CMake version changed between CMakeLists.txt.")
  442. endif()
  443. endmacro()
  444. # add_obs_plugin: Add plugin subdirectory if host platform is in specified list of supported platforms
  445. function(add_obs_plugin target)
  446. set(options WITH_MESSAGE)
  447. set(oneValueArgs "")
  448. set(multiValueArgs PLATFORMS)
  449. cmake_parse_arguments(PARSE_ARGV 0 _AOP "${options}" "${oneValueArgs}" "${multiValueArgs}")
  450. set(found_platform FALSE)
  451. list(LENGTH _AOP_PLATFORMS _AOP_NUM_PLATFORMS)
  452. if(_AOP_NUM_PLATFORMS EQUAL 0)
  453. set(found_platform TRUE)
  454. else()
  455. foreach(platform IN LISTS _AOP_PLATFORMS)
  456. set(check_var_name "OS_${platform}")
  457. if(${${check_var_name}})
  458. set(found_platform TRUE)
  459. break()
  460. endif()
  461. endforeach()
  462. endif()
  463. if(found_platform)
  464. add_subdirectory(${target})
  465. elseif(_AOP_WITH_MESSAGE)
  466. add_custom_target(${target} COMMENT "Dummy target for unavailable module ${target}")
  467. target_disable(${target})
  468. endif()
  469. endfunction()