helpers.cmake 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. # OBS CMake macOS helper functions module
  2. # cmake-format: off
  3. # cmake-lint: disable=C0307
  4. # cmake-lint: disable=R0912
  5. # cmake-lint: disable=R0915
  6. # cmake-lint: disable=E1126
  7. # cmake-format: on
  8. include(helpers_common)
  9. # set_target_properties_obs: Set target properties for use in obs-studio
  10. function(set_target_properties_obs target)
  11. set(options "")
  12. set(oneValueArgs "")
  13. set(multiValueArgs PROPERTIES)
  14. cmake_parse_arguments(PARSE_ARGV 0 _STPO "${options}" "${oneValueArgs}" "${multiValueArgs}")
  15. message(DEBUG "Setting additional properties for target ${target}...")
  16. while(_STPO_PROPERTIES)
  17. list(POP_FRONT _STPO_PROPERTIES key value)
  18. set_property(TARGET ${target} PROPERTY ${key} "${value}")
  19. endwhile()
  20. get_target_property(target_type ${target} TYPE)
  21. # Target is a GUI or CLI application
  22. if(target_type STREQUAL EXECUTABLE)
  23. if(target STREQUAL obs-studio)
  24. _check_info_plist()
  25. set_target_properties(
  26. ${target}
  27. PROPERTIES OUTPUT_NAME OBS
  28. MACOSX_BUNDLE TRUE
  29. MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Info.plist.in"
  30. XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.obsproject.obs-studio
  31. XCODE_ATTRIBUTE_PRODUCT_NAME OBS
  32. XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AppIcon
  33. XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY YES
  34. XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY YES
  35. XCODE_EMBED_PLUGINS_REMOVE_HEADERS_ON_COPY YES
  36. XCODE_EMBED_PLUGINS_CODE_SIGN_ON_COPY YES
  37. XCODE_ATTRIBUTE_COPY_PHASE_STRIP NO
  38. XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
  39. XCODE_ATTRIBUTE_SKIP_INSTALL NO
  40. XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)")
  41. get_property(obs_dependencies GLOBAL PROPERTY _OBS_DEPENDENCIES)
  42. add_dependencies(${target} ${obs_dependencies})
  43. if(NOT XCODE)
  44. return()
  45. endif()
  46. get_property(obs_frameworks GLOBAL PROPERTY _OBS_FRAMEWORKS)
  47. set_property(
  48. TARGET ${target}
  49. APPEND
  50. PROPERTY XCODE_EMBED_FRAMEWORKS ${obs_frameworks})
  51. if(SPARKLE_APPCAST_URL AND SPARKLE_PUBLIC_KEY)
  52. set_property(
  53. TARGET ${target}
  54. APPEND
  55. PROPERTY XCODE_EMBED_FRAMEWORKS ${SPARKLE})
  56. endif()
  57. get_property(obs_executables GLOBAL PROPERTY _OBS_EXECUTABLES)
  58. add_dependencies(${target} ${obs_executables})
  59. foreach(executable IN LISTS obs_executables)
  60. set_property(
  61. TARGET ${executable} PROPERTY XCODE_ATTRIBUTE_INSTALL_PATH
  62. "$(LOCAL_APPS_DIR)/$<TARGET_BUNDLE_DIR_NAME:${target}>/Contents/MacOS")
  63. add_custom_command(
  64. TARGET ${target}
  65. POST_BUILD
  66. COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:${executable}>"
  67. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/MacOS/"
  68. COMMENT "Copy ${executable} to application bundle")
  69. endforeach()
  70. _check_entitlements()
  71. configure_file(cmake/macos/exportOptions.plist.in ${CMAKE_BINARY_DIR}/exportOptions.plist)
  72. add_custom_command(
  73. TARGET ${target}
  74. POST_BUILD
  75. COMMAND
  76. /usr/bin/sed -i '' 's/font-size: 10pt\;/font-size: 12pt\;/'
  77. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Resources/themes/Acri.qss"
  78. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Resources/themes/Grey.qss"
  79. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Resources/themes/Light.qss"
  80. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Resources/themes/Rachni.qss"
  81. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Resources/themes/Yami.qss"
  82. COMMENT "Patch Qt stylesheets to use larger default font size on macOS")
  83. add_custom_command(
  84. TARGET ${target}
  85. POST_BUILD
  86. COMMAND /bin/ln -fs obs-frontend-api.dylib libobs-frontend-api.1.dylib
  87. WORKING_DIRECTORY "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Frameworks"
  88. COMMENT "Create symlink for legacy obs-frontend-api")
  89. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/qt.conf")
  90. target_add_resource(${target} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/qt.conf")
  91. endif()
  92. target_add_resource(${target} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Assets.xcassets")
  93. target_add_resource(${target} "${CMAKE_CURRENT_SOURCE_DIR}/../AUTHORS")
  94. if(TARGET obs-dal-plugin)
  95. add_custom_command(
  96. TARGET ${target}
  97. POST_BUILD
  98. COMMAND "${CMAKE_COMMAND}" -E copy_directory "$<TARGET_BUNDLE_DIR:obs-dal-plugin>"
  99. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Resources/$<TARGET_BUNDLE_DIR_NAME:obs-dal-plugin>"
  100. COMMENT "Add OBS DAL plugin to application bundle")
  101. endif()
  102. if(TARGET obspython)
  103. add_custom_command(
  104. TARGET ${target}
  105. POST_BUILD
  106. COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE_DIR:obspython>/obspython.py"
  107. "$<TARGET_BUNDLE_CONTENT_DIR:${target}>/Resources"
  108. COMMENT "Add OBS::python import module")
  109. endif()
  110. _bundle_dependencies(${target})
  111. install(TARGETS ${target} BUNDLE DESTINATION "." COMPONENT Application)
  112. else()
  113. set_property(TARGET ${target} PROPERTY XCODE_ATTRIBUTE_SKIP_INSTALL NO)
  114. set_property(GLOBAL APPEND PROPERTY _OBS_EXECUTABLES ${target})
  115. set_property(GLOBAL APPEND PROPERTY _OBS_DEPENDENCIES ${target})
  116. endif()
  117. _add_entitlements()
  118. elseif(target_type STREQUAL SHARED_LIBRARY)
  119. set_target_properties(
  120. ${target}
  121. PROPERTIES NO_SONAME TRUE
  122. MACHO_COMPATIBILITY_VERSION 1.0
  123. MACHO_CURRENT_VERSION ${OBS_VERSION_MAJOR}
  124. SOVERSION 0
  125. VERSION 0
  126. XCODE_ATTRIBUTE_DYLIB_COMPATIBILITY_VERSION 1.0
  127. XCODE_ATTRIBUTE_DYLIB_CURRENT_VERSION ${OBS_VERSION_MAJOR}
  128. XCODE_ATTRIBUTE_PRODUCT_NAME ${target}
  129. XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.obsproject.${target}
  130. XCODE_ATTRIBUTE_SKIP_INSTALL YES)
  131. get_target_property(is_framework ${target} FRAMEWORK)
  132. if(is_framework)
  133. _check_info_plist()
  134. set_target_properties(
  135. ${target}
  136. PROPERTIES FRAMEWORK_VERSION A
  137. MACOSX_FRAMEWORK_IDENTIFIER com.obsproject.${target}
  138. MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Info.plist.in"
  139. XCODE_ATTRIBUTE_SKIP_INSTALL YES)
  140. endif()
  141. _add_entitlements()
  142. set_property(GLOBAL APPEND PROPERTY _OBS_FRAMEWORKS ${target})
  143. set_property(GLOBAL APPEND PROPERTY _OBS_DEPENDENCIES ${target})
  144. elseif(target_type STREQUAL MODULE_LIBRARY)
  145. if(target STREQUAL obspython)
  146. set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_PRODUCT_NAME ${target}
  147. XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.obsproject.${target})
  148. elseif(target STREQUAL obslua)
  149. set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_PRODUCT_NAME ${target}
  150. XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.obsproject.${target})
  151. elseif(target STREQUAL obs-dal-plugin)
  152. set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
  153. set_property(GLOBAL APPEND PROPERTY _OBS_DEPENDENCIES ${target})
  154. return()
  155. else()
  156. _check_info_plist()
  157. set_target_properties(
  158. ${target}
  159. PROPERTIES BUNDLE TRUE
  160. BUNDLE_EXTENSION plugin
  161. MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Info.plist.in"
  162. XCODE_ATTRIBUTE_PRODUCT_NAME ${target}
  163. XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.obsproject.${target})
  164. if(target STREQUAL obs-browser)
  165. # Good-enough for now as there are no other variants - in _theory_ we should only add the appropriate variant,
  166. # but that is only known at project generation and not build system configuration.
  167. get_target_property(imported_location CEF::Library IMPORTED_LOCATION_RELEASE)
  168. if(imported_location)
  169. list(APPEND cef_items "${imported_location}")
  170. endif()
  171. foreach(helper IN ITEMS _gpu _plugin _renderer "")
  172. if(TARGET OBS::browser-helper${helper})
  173. set_property(GLOBAL APPEND PROPERTY _OBS_DEPENDENCIES OBS::browser-helper${helper})
  174. list(APPEND cef_items OBS::browser-helper${helper})
  175. endif()
  176. endforeach()
  177. set_property(GLOBAL APPEND PROPERTY _OBS_FRAMEWORKS ${cef_items})
  178. endif()
  179. endif()
  180. set_property(GLOBAL APPEND PROPERTY OBS_MODULES_ENABLED ${target})
  181. set_property(GLOBAL APPEND PROPERTY _OBS_DEPENDENCIES ${target})
  182. endif()
  183. target_install_resources(${target})
  184. get_target_property(target_sources ${target} SOURCES)
  185. set(target_ui_files ${target_sources})
  186. list(FILTER target_ui_files INCLUDE REGEX ".+\\.(ui|qrc)")
  187. source_group(
  188. TREE "${CMAKE_CURRENT_SOURCE_DIR}"
  189. PREFIX "UI Files"
  190. FILES ${target_ui_files})
  191. if(${target} STREQUAL libobs)
  192. set(target_source_files ${target_sources})
  193. set(target_header_files ${target_sources})
  194. list(FILTER target_source_files INCLUDE REGEX ".+\\.(m|c[cp]?p?|swift)")
  195. list(FILTER target_header_files INCLUDE REGEX ".+\\.h(pp)?")
  196. source_group(
  197. TREE "${CMAKE_CURRENT_SOURCE_DIR}"
  198. PREFIX "Source Files"
  199. FILES ${target_source_files})
  200. source_group(
  201. TREE "${CMAKE_CURRENT_SOURCE_DIR}"
  202. PREFIX "Header Files"
  203. FILES ${target_header_files})
  204. endif()
  205. endfunction()
  206. # _check_info_plist: Macro to check if project ships with Info.plist template
  207. macro(_check_info_plist)
  208. if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Info.plist.in")
  209. message(FATAL_ERROR "Target ${target} is missing an Info.plist template in its cmake directory.")
  210. endif()
  211. endmacro()
  212. # _check_entitlements: Macro to check if project ships with entitlements plist
  213. macro(_check_entitlements)
  214. if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/entitlements.plist")
  215. message(FATAL_ERROR "Target ${target} is missing an entitlements.plist in its cmake directory.")
  216. endif()
  217. endmacro()
  218. # _add_entitlements: Macro to add entitlements shipped with project
  219. macro(_add_entitlements)
  220. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/entitlements.plist")
  221. set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS
  222. "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/entitlements.plist")
  223. endif()
  224. endmacro()
  225. # target_export: Helper function to export target as CMake package
  226. function(target_export target)
  227. # Exclude CMake package from 'ALL' target
  228. set(exclude_variant EXCLUDE_FROM_ALL)
  229. _target_export(${target})
  230. endfunction()
  231. # target_install_resources: Helper function to add resources into bundle
  232. function(target_install_resources target)
  233. message(DEBUG "Installing resources for target ${target}...")
  234. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/data")
  235. file(GLOB_RECURSE data_files "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
  236. foreach(data_file IN LISTS data_files)
  237. cmake_path(RELATIVE_PATH data_file BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/" OUTPUT_VARIABLE
  238. relative_path)
  239. cmake_path(GET relative_path PARENT_PATH relative_path)
  240. target_sources(${target} PRIVATE "${data_file}")
  241. set_property(SOURCE "${data_file}" PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${relative_path}")
  242. source_group("Resources/${relative_path}" FILES "${data_file}")
  243. endforeach()
  244. endif()
  245. endfunction()
  246. # target_add_resource: Helper function to add a specific resource to a bundle
  247. function(target_add_resource target resource)
  248. message(DEBUG "Add resource ${resource} to target ${target} at destination ${destination}...")
  249. target_sources(${target} PRIVATE "${resource}")
  250. set_property(SOURCE "${resource}" PROPERTY MACOSX_PACKAGE_LOCATION Resources)
  251. source_group("Resources" FILES "${resource}")
  252. endfunction()
  253. # _bundle_dependencies: Resolve 3rd party dependencies and add them to macOS app bundle
  254. function(_bundle_dependencies target)
  255. message(DEBUG "Discover dependencies of target ${target}...")
  256. set(found_dependencies)
  257. find_dependencies(TARGET ${target} FOUND_VAR found_dependencies)
  258. get_property(obs_module_list GLOBAL PROPERTY OBS_MODULES_ENABLED)
  259. list(LENGTH obs_module_list num_modules)
  260. if(num_modules GREATER 0)
  261. add_dependencies(${target} ${obs_module_list})
  262. set_property(
  263. TARGET ${target}
  264. APPEND
  265. PROPERTY XCODE_EMBED_PLUGINS ${obs_module_list})
  266. foreach(module IN LISTS obs_module_list)
  267. find_dependencies(TARGET ${module} FOUND_VAR found_dependencies)
  268. endforeach()
  269. endif()
  270. list(REMOVE_DUPLICATES found_dependencies)
  271. set(library_paths)
  272. set(plugins_list)
  273. file(GLOB sdk_library_paths /Applications/Xcode*.app)
  274. set(system_library_path "/usr/lib/")
  275. foreach(library IN LISTS found_dependencies)
  276. get_target_property(library_type ${library} TYPE)
  277. get_target_property(is_framework ${library} FRAMEWORK)
  278. get_target_property(is_imported ${library} IMPORTED)
  279. if(is_imported)
  280. get_target_property(imported_location ${library} LOCATION)
  281. if(NOT imported_location)
  282. continue()
  283. endif()
  284. set(is_xcode_framework FALSE)
  285. set(is_system_framework FALSE)
  286. foreach(sdk_library_path IN LISTS sdk_library_paths)
  287. if(is_xcode_framework)
  288. break()
  289. endif()
  290. cmake_path(IS_PREFIX sdk_library_path "${imported_location}" is_xcode_framework)
  291. endforeach()
  292. cmake_path(IS_PREFIX system_library_path "${imported_location}" is_system_framework)
  293. if(is_system_framework OR is_xcode_framework)
  294. continue()
  295. elseif(is_framework)
  296. file(REAL_PATH "../../.." library_location BASE_DIRECTORY "${imported_location}")
  297. elseif(NOT library_type STREQUAL "STATIC_LIBRARY")
  298. if(NOT imported_location MATCHES ".+\\.a")
  299. set(library_location "${imported_location}")
  300. else()
  301. continue()
  302. endif()
  303. else()
  304. continue()
  305. endif()
  306. if(library MATCHES "Qt[56]?::.+")
  307. find_qt_plugins(COMPONENT ${library} TARGET ${target} FOUND_VAR plugins_list)
  308. endif()
  309. list(APPEND library_paths ${library_location})
  310. elseif(NOT imported AND library_type STREQUAL "SHARED_LIBRARY")
  311. message(TRACE "${library} is a project target")
  312. list(APPEND library_paths ${library})
  313. endif()
  314. endforeach()
  315. list(REMOVE_DUPLICATES plugins_list)
  316. foreach(plugin IN LISTS plugins_list)
  317. cmake_path(GET plugin PARENT_PATH plugin_path)
  318. set(plugin_base_dir "${plugin_path}/../")
  319. cmake_path(SET plugin_stem_dir NORMALIZE "${plugin_base_dir}")
  320. cmake_path(RELATIVE_PATH plugin_path BASE_DIRECTORY "${plugin_stem_dir}" OUTPUT_VARIABLE plugin_file_name)
  321. target_sources(${target} PRIVATE "${plugin}")
  322. set_source_files_properties("${plugin}" PROPERTIES MACOSX_PACKAGE_LOCATION "plugins/${plugin_file_name}"
  323. XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
  324. source_group("Qt plugins" FILES "${plugin}")
  325. endforeach()
  326. list(REMOVE_DUPLICATES library_paths)
  327. set_property(
  328. TARGET ${target}
  329. APPEND
  330. PROPERTY XCODE_EMBED_FRAMEWORKS ${library_paths})
  331. endfunction()