The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2108 lines
87KB

  1. # ==============================================================================
  2. #
  3. # This file is part of the JUCE 7 technical preview.
  4. # Copyright (c) 2022 - Raw Material Software Limited
  5. #
  6. # You may use this code under the terms of the GPL v3
  7. # (see www.gnu.org/licenses).
  8. #
  9. # For the technical preview this file cannot be licensed commercially.
  10. #
  11. # JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  12. # EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  13. # DISCLAIMED.
  14. #
  15. # ==============================================================================
  16. # ==================================================================================================
  17. # JUCE Target Support Helper Functions
  18. #
  19. # In this file, functions intended for use by end-users have the prefix `juce_`.
  20. # Functions beginning with an underscore should be considered private and susceptible to
  21. # change, so don't call them directly.
  22. #
  23. # See the readme at `docs/CMake API.md` for more information about CMake usage,
  24. # including documentation of the public functions in this file.
  25. # ==================================================================================================
  26. include_guard(GLOBAL)
  27. cmake_minimum_required(VERSION 3.15)
  28. define_property(TARGET PROPERTY JUCE_COMPANY_NAME INHERITED
  29. BRIEF_DOCS "The company name for a particular target"
  30. FULL_DOCS "This can be found in ProjectInfo::companyName in a generated JuceHeader.h")
  31. set_property(GLOBAL PROPERTY JUCE_COMPANY_NAME "yourcompany")
  32. define_property(TARGET PROPERTY JUCE_COMPANY_WEBSITE INHERITED
  33. BRIEF_DOCS "The company website for a particular target"
  34. FULL_DOCS "This will be placed in the Info.plist for the target")
  35. set_property(GLOBAL PROPERTY JUCE_COMPANY_WEBSITE "")
  36. define_property(TARGET PROPERTY JUCE_COMPANY_EMAIL INHERITED
  37. BRIEF_DOCS "The company email address for a particular target"
  38. FULL_DOCS "This will be placed in the Info.plist for the target")
  39. set_property(GLOBAL PROPERTY JUCE_COMPANY_EMAIL "")
  40. define_property(TARGET PROPERTY JUCE_COMPANY_COPYRIGHT INHERITED
  41. BRIEF_DOCS "The company copyright for a particular target"
  42. FULL_DOCS "This will be placed in the Info.plist for the target")
  43. set_property(GLOBAL PROPERTY JUCE_COMPANY_COPYRIGHT "")
  44. define_property(TARGET PROPERTY JUCE_VST_COPY_DIR INHERITED
  45. BRIEF_DOCS "Install location for VST2 plugins"
  46. FULL_DOCS "This is where the plugin will be copied if plugin copying is enabled")
  47. define_property(TARGET PROPERTY JUCE_VST3_COPY_DIR INHERITED
  48. BRIEF_DOCS "Install location for VST3 plugins"
  49. FULL_DOCS "This is where the plugin will be copied if plugin copying is enabled")
  50. define_property(TARGET PROPERTY JUCE_AU_COPY_DIR INHERITED
  51. BRIEF_DOCS "Install location for AU plugins"
  52. FULL_DOCS "This is where the plugin will be copied if plugin copying is enabled")
  53. define_property(TARGET PROPERTY JUCE_AAX_COPY_DIR INHERITED
  54. BRIEF_DOCS "Install location for AAX plugins"
  55. FULL_DOCS "This is where the plugin will be copied if plugin copying is enabled")
  56. define_property(TARGET PROPERTY JUCE_UNITY_COPY_DIR INHERITED
  57. BRIEF_DOCS "Install location for Unity plugins"
  58. FULL_DOCS "This is where the plugin will be copied if plugin copying is enabled")
  59. define_property(TARGET PROPERTY JUCE_LV2_COPY_DIR INHERITED
  60. BRIEF_DOCS "Install location for LV2 plugins"
  61. FULL_DOCS "This is where the plugin will be copied if plugin copying is enabled")
  62. define_property(TARGET PROPERTY JUCE_COPY_PLUGIN_AFTER_BUILD INHERITED
  63. BRIEF_DOCS "Whether or not plugins should be copied after building"
  64. FULL_DOCS "Whether or not plugins should be copied after building")
  65. set_property(GLOBAL PROPERTY JUCE_COPY_PLUGIN_AFTER_BUILD FALSE)
  66. if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD"))
  67. _juce_create_pkgconfig_target(JUCE_CURL_LINUX_DEPS libcurl)
  68. _juce_create_pkgconfig_target(JUCE_BROWSER_LINUX_DEPS webkit2gtk-4.0 gtk+-x11-3.0)
  69. elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  70. find_program(JUCE_XCRUN xcrun)
  71. if(NOT JUCE_XCRUN)
  72. message(WARNING "failed to find xcrun; older resource-based AU plug-ins may not work correctly")
  73. endif()
  74. endif()
  75. # We set up default/fallback copy dirs here. If you need different copy dirs, use
  76. # set_directory_properties or set_target_properties to adjust the values of `JUCE_*_COPY_DIR` at
  77. # the appropriate scope.
  78. function(_juce_set_default_properties)
  79. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  80. set_property(GLOBAL PROPERTY JUCE_LV2_COPY_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/LV2")
  81. set_property(GLOBAL PROPERTY JUCE_VST_COPY_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/VST")
  82. set_property(GLOBAL PROPERTY JUCE_VST3_COPY_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/VST3")
  83. set_property(GLOBAL PROPERTY JUCE_AU_COPY_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/Components")
  84. set_property(GLOBAL PROPERTY JUCE_UNITY_COPY_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/Unity")
  85. set_property(GLOBAL PROPERTY JUCE_AAX_COPY_DIR "/Library/Application Support/Avid/Audio/Plug-Ins")
  86. elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  87. if(CMAKE_SIZEOF_VOID_P EQUAL 8)
  88. set_property(GLOBAL PROPERTY JUCE_VST_COPY_DIR "$ENV{ProgramW6432}/Steinberg/Vstplugins")
  89. set(prefix "$ENV{CommonProgramW6432}")
  90. else()
  91. set_property(GLOBAL PROPERTY JUCE_VST_COPY_DIR "$ENV{programfiles\(x86\)}/Steinberg/Vstplugins")
  92. set(prefix "$ENV{CommonProgramFiles\(x86\)}")
  93. endif()
  94. set_property(GLOBAL PROPERTY JUCE_VST3_COPY_DIR "${prefix}/VST3")
  95. set_property(GLOBAL PROPERTY JUCE_AAX_COPY_DIR "${prefix}/Avid/Audio/Plug-Ins")
  96. set_property(GLOBAL PROPERTY JUCE_LV2_COPY_DIR "$ENV{APPDATA}/LV2")
  97. set_property(GLOBAL PROPERTY JUCE_UNITY_COPY_DIR "$ENV{APPDATA}/Unity")
  98. elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD"))
  99. set_property(GLOBAL PROPERTY JUCE_LV2_COPY_DIR "$ENV{HOME}/.lv2")
  100. set_property(GLOBAL PROPERTY JUCE_VST_COPY_DIR "$ENV{HOME}/.vst")
  101. set_property(GLOBAL PROPERTY JUCE_VST3_COPY_DIR "$ENV{HOME}/.vst3")
  102. set_property(GLOBAL PROPERTY JUCE_UNITY_COPY_DIR "$ENV{HOME}/.unity")
  103. endif()
  104. endfunction()
  105. _juce_set_default_properties()
  106. # ==================================================================================================
  107. function(juce_add_bundle_resources_directory target folder)
  108. _juce_make_absolute(folder)
  109. if(NOT EXISTS "${folder}")
  110. message(FATAL_ERROR "Could not find resource folder ${folder}")
  111. endif()
  112. get_filename_component(folder_parent_path "${folder}" DIRECTORY)
  113. file(GLOB_RECURSE resources RELATIVE "${folder_parent_path}" "${folder}/*")
  114. foreach(file IN LISTS resources)
  115. target_sources(${target} PRIVATE "${folder_parent_path}/${file}")
  116. get_filename_component(resource_parent_path "${file}" DIRECTORY)
  117. set_source_files_properties("${folder_parent_path}/${file}" PROPERTIES
  118. HEADER_FILE_ONLY TRUE
  119. MACOSX_PACKAGE_LOCATION "Resources/${resource_parent_path}")
  120. endforeach()
  121. endfunction()
  122. # ==================================================================================================
  123. function(_juce_add_au_resource_fork shared_code_target au_target)
  124. if(NOT JUCE_XCRUN)
  125. return()
  126. endif()
  127. get_target_property(product_name ${shared_code_target} JUCE_PRODUCT_NAME)
  128. get_target_property(module_sources juce::juce_audio_plugin_client_AU INTERFACE_SOURCES)
  129. list(FILTER module_sources INCLUDE REGEX "/juce_audio_plugin_client_AU.r$")
  130. if(NOT module_sources)
  131. message(FATAL_ERROR "Failed to find AU resource file input")
  132. endif()
  133. list(GET module_sources 0 au_rez_sources)
  134. get_target_property(juce_library_code ${shared_code_target} JUCE_GENERATED_SOURCES_DIRECTORY)
  135. # We don't want our AU AppConfig.h to end up on peoples' include paths if we can help it
  136. set(secret_au_resource_dir "${juce_library_code}/${au_target}/secret")
  137. set(secret_au_plugindefines "${secret_au_resource_dir}/JucePluginDefines.h")
  138. set(au_rez_output "${secret_au_resource_dir}/${product_name}.rsrc")
  139. target_sources(${au_target} PRIVATE "${au_rez_output}")
  140. set_source_files_properties("${au_rez_output}" PROPERTIES
  141. GENERATED TRUE
  142. MACOSX_PACKAGE_LOCATION Resources)
  143. set(defs_file $<GENEX_EVAL:$<TARGET_PROPERTY:${shared_code_target},JUCE_DEFS_FILE>>)
  144. # Passing all our compile definitions using generator expressions is really painful
  145. # because some of the definitions have pipes and quotes and dollars and goodness-knows
  146. # what else that the shell would very much like to claim for itself, thank you very much.
  147. # CMake definitely knows how to escape all these things, because it's perfectly happy to pass
  148. # them to compiler invocations, but I have no idea how to get it to escape them
  149. # in a custom command.
  150. # In the end, it's simplest to generate a special single-purpose appconfig just for the
  151. # resource compiler.
  152. add_custom_command(OUTPUT "${secret_au_plugindefines}"
  153. COMMAND juce::juceaide auplugindefines "${defs_file}" "${secret_au_plugindefines}"
  154. DEPENDS "${defs_file}"
  155. VERBATIM)
  156. add_custom_command(OUTPUT "${au_rez_output}"
  157. COMMAND "${JUCE_XCRUN}" Rez
  158. -d "ppc_$ppc" -d "i386_$i386" -d "ppc64_$ppc64" -d "x86_64_$x86_64" -d "arm64_$arm64"
  159. -I "${secret_au_resource_dir}"
  160. -I "/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers"
  161. -I "${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/AudioUnit.framework/Headers"
  162. -isysroot "${CMAKE_OSX_SYSROOT}"
  163. "${au_rez_sources}"
  164. -useDF
  165. -o "${au_rez_output}"
  166. DEPENDS "${secret_au_plugindefines}"
  167. VERBATIM)
  168. set(au_resource_directory "$<TARGET_BUNDLE_DIR:${au_target}>/Contents/Resources")
  169. endfunction()
  170. # ==================================================================================================
  171. # Ideally, we'd check the preprocessor defs on the target to see whether
  172. # JUCE_USE_CURL, JUCE_WEB_BROWSER, or JUCE_IN_APP_PURCHASES have been explicitly turned off,
  173. # and then link libraries as appropriate.
  174. # Unfortunately, this doesn't work, because linking a new library (curl/webkit/StoreKit)
  175. # updates the target's compile defs, which results in a recursion/circular-dependency.
  176. # Instead, we ask the user to explicitly request curl/webkit/StoreKit linking if they
  177. # know they need it. Otherwise, we won't link anything.
  178. # See the NEEDS_CURL, NEEDS_WEB_BROWSER, and NEEDS_STORE_KIT options in the CMake/readme.md.
  179. function(_juce_link_optional_libraries target)
  180. if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD"))
  181. get_target_property(needs_curl ${target} JUCE_NEEDS_CURL)
  182. if(needs_curl)
  183. target_link_libraries(${target} PRIVATE juce::pkgconfig_JUCE_CURL_LINUX_DEPS)
  184. endif()
  185. get_target_property(needs_browser ${target} JUCE_NEEDS_WEB_BROWSER)
  186. if(needs_browser)
  187. target_link_libraries(${target} PRIVATE juce::pkgconfig_JUCE_BROWSER_LINUX_DEPS)
  188. endif()
  189. elseif(APPLE)
  190. get_target_property(needs_storekit ${target} JUCE_NEEDS_STORE_KIT)
  191. if(needs_storekit)
  192. _juce_link_frameworks("${target}" PRIVATE StoreKit)
  193. endif()
  194. get_target_property(needs_camera ${target} JUCE_CAMERA_PERMISSION_ENABLED)
  195. if(CMAKE_SYSTEM_NAME STREQUAL "iOS" AND needs_camera)
  196. _juce_link_frameworks("${target}" PRIVATE ImageIO)
  197. endif()
  198. endif()
  199. endfunction()
  200. # ==================================================================================================
  201. function(_juce_get_module_definitions target filter out_var)
  202. set(compile_defs $<TARGET_GENEX_EVAL:${target},$<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>>)
  203. if(filter)
  204. set(${out_var} $<FILTER:${compile_defs},EXCLUDE,JucePlugin_Build_|JUCE_SHARED_CODE> PARENT_SCOPE)
  205. else()
  206. set(${out_var} ${compile_defs} PARENT_SCOPE)
  207. endif()
  208. endfunction()
  209. function(_juce_append_record output key)
  210. string(ASCII 30 RS)
  211. string(ASCII 31 US)
  212. set(${output} "${${output}}${key}${US}${ARGN}${RS}" PARENT_SCOPE)
  213. endfunction()
  214. function(_juce_append_target_property output key target property)
  215. get_target_property(prop ${target} ${property})
  216. if(prop STREQUAL "prop-NOTFOUND")
  217. set(prop)
  218. endif()
  219. _juce_append_record(${output} ${key} ${prop})
  220. set(${output} "${${output}}" PARENT_SCOPE)
  221. endfunction()
  222. # This is all info that should be known at configure time (i.e. no generator expressions here!)
  223. # We use this info to generate plists and entitlements files, also at configure time.
  224. function(_juce_write_configure_time_info target)
  225. _juce_append_target_property(file_content EXECUTABLE_NAME ${target} JUCE_PRODUCT_NAME)
  226. _juce_append_target_property(file_content VERSION ${target} JUCE_VERSION)
  227. _juce_append_target_property(file_content BUILD_VERSION ${target} JUCE_BUILD_VERSION)
  228. _juce_append_target_property(file_content PLIST_TO_MERGE ${target} JUCE_PLIST_TO_MERGE)
  229. _juce_append_target_property(file_content BUNDLE_ID ${target} JUCE_BUNDLE_ID)
  230. _juce_append_target_property(file_content XCODE_EXTRA_PLIST_ENTRIES ${target} JUCE_XCODE_EXTRA_PLIST_ENTRIES)
  231. _juce_append_target_property(file_content MICROPHONE_PERMISSION_ENABLED ${target} JUCE_MICROPHONE_PERMISSION_ENABLED)
  232. _juce_append_target_property(file_content MICROPHONE_PERMISSION_TEXT ${target} JUCE_MICROPHONE_PERMISSION_TEXT)
  233. _juce_append_target_property(file_content CAMERA_PERMISSION_ENABLED ${target} JUCE_CAMERA_PERMISSION_ENABLED)
  234. _juce_append_target_property(file_content CAMERA_PERMISSION_TEXT ${target} JUCE_CAMERA_PERMISSION_TEXT)
  235. _juce_append_target_property(file_content BLUETOOTH_PERMISSION_ENABLED ${target} JUCE_BLUETOOTH_PERMISSION_ENABLED)
  236. _juce_append_target_property(file_content BLUETOOTH_PERMISSION_TEXT ${target} JUCE_BLUETOOTH_PERMISSION_TEXT)
  237. _juce_append_target_property(file_content SEND_APPLE_EVENTS_PERMISSION_ENABLED ${target} JUCE_SEND_APPLE_EVENTS_PERMISSION_ENABLED)
  238. _juce_append_target_property(file_content SEND_APPLE_EVENTS_PERMISSION_TEXT ${target} JUCE_SEND_APPLE_EVENTS_PERMISSION_TEXT)
  239. _juce_append_target_property(file_content SHOULD_ADD_STORYBOARD ${target} JUCE_SHOULD_ADD_STORYBOARD)
  240. _juce_append_target_property(file_content LAUNCH_STORYBOARD_FILE ${target} JUCE_LAUNCH_STORYBOARD_FILE)
  241. _juce_append_target_property(file_content ICON_FILE ${target} JUCE_ICON_FILE)
  242. _juce_append_target_property(file_content PROJECT_NAME ${target} JUCE_PRODUCT_NAME)
  243. _juce_append_target_property(file_content COMPANY_COPYRIGHT ${target} JUCE_COMPANY_COPYRIGHT)
  244. _juce_append_target_property(file_content COMPANY_NAME ${target} JUCE_COMPANY_NAME)
  245. _juce_append_target_property(file_content DOCUMENT_EXTENSIONS ${target} JUCE_DOCUMENT_EXTENSIONS)
  246. _juce_append_target_property(file_content FILE_SHARING_ENABLED ${target} JUCE_FILE_SHARING_ENABLED)
  247. _juce_append_target_property(file_content DOCUMENT_BROWSER_ENABLED ${target} JUCE_DOCUMENT_BROWSER_ENABLED)
  248. _juce_append_target_property(file_content STATUS_BAR_HIDDEN ${target} JUCE_STATUS_BAR_HIDDEN)
  249. _juce_append_target_property(file_content REQUIRES_FULL_SCREEN ${target} JUCE_REQUIRES_FULL_SCREEN)
  250. _juce_append_target_property(file_content BACKGROUND_AUDIO_ENABLED ${target} JUCE_BACKGROUND_AUDIO_ENABLED)
  251. _juce_append_target_property(file_content BACKGROUND_BLE_ENABLED ${target} JUCE_BACKGROUND_BLE_ENABLED)
  252. _juce_append_target_property(file_content PUSH_NOTIFICATIONS_ENABLED ${target} JUCE_PUSH_NOTIFICATIONS_ENABLED)
  253. _juce_append_target_property(file_content NETWORK_MULTICAST_ENABLED ${target} JUCE_NETWORK_MULTICAST_ENABLED)
  254. _juce_append_target_property(file_content PLUGIN_MANUFACTURER_CODE ${target} JUCE_PLUGIN_MANUFACTURER_CODE)
  255. _juce_append_target_property(file_content PLUGIN_CODE ${target} JUCE_PLUGIN_CODE)
  256. _juce_append_target_property(file_content IPHONE_SCREEN_ORIENTATIONS ${target} JUCE_IPHONE_SCREEN_ORIENTATIONS)
  257. _juce_append_target_property(file_content IPAD_SCREEN_ORIENTATIONS ${target} JUCE_IPAD_SCREEN_ORIENTATIONS)
  258. _juce_append_target_property(file_content PLUGIN_NAME ${target} JUCE_PLUGIN_NAME)
  259. _juce_append_target_property(file_content PLUGIN_MANUFACTURER ${target} JUCE_COMPANY_NAME)
  260. _juce_append_target_property(file_content PLUGIN_DESCRIPTION ${target} JUCE_DESCRIPTION)
  261. _juce_append_target_property(file_content PLUGIN_AU_EXPORT_PREFIX ${target} JUCE_AU_EXPORT_PREFIX)
  262. _juce_append_target_property(file_content PLUGIN_AU_MAIN_TYPE ${target} JUCE_AU_MAIN_TYPE_CODE)
  263. _juce_append_target_property(file_content IS_AU_SANDBOX_SAFE ${target} JUCE_AU_SANDBOX_SAFE)
  264. _juce_append_target_property(file_content IS_PLUGIN_SYNTH ${target} JUCE_IS_SYNTH)
  265. _juce_append_target_property(file_content SUPPRESS_AU_PLIST_RESOURCE_USAGE ${target} JUCE_SUPPRESS_AU_PLIST_RESOURCE_USAGE)
  266. _juce_append_target_property(file_content HARDENED_RUNTIME_ENABLED ${target} JUCE_HARDENED_RUNTIME_ENABLED)
  267. _juce_append_target_property(file_content APP_SANDBOX_ENABLED ${target} JUCE_APP_SANDBOX_ENABLED)
  268. _juce_append_target_property(file_content APP_SANDBOX_INHERIT ${target} JUCE_APP_SANDBOX_INHERIT)
  269. _juce_append_target_property(file_content HARDENED_RUNTIME_OPTIONS ${target} JUCE_HARDENED_RUNTIME_OPTIONS)
  270. _juce_append_target_property(file_content APP_SANDBOX_OPTIONS ${target} JUCE_APP_SANDBOX_OPTIONS)
  271. _juce_append_target_property(file_content APP_SANDBOX_FILE_ACCESS_HOME_RO ${target} JUCE_APP_SANDBOX_FILE_ACCESS_HOME_RO)
  272. _juce_append_target_property(file_content APP_SANDBOX_FILE_ACCESS_HOME_RW ${target} JUCE_APP_SANDBOX_FILE_ACCESS_HOME_RW)
  273. _juce_append_target_property(file_content APP_SANDBOX_FILE_ACCESS_ABS_RO ${target} JUCE_APP_SANDBOX_FILE_ACCESS_ABS_RO)
  274. _juce_append_target_property(file_content APP_SANDBOX_FILE_ACCESS_ABS_RW ${target} JUCE_APP_SANDBOX_FILE_ACCESS_ABS_RW)
  275. _juce_append_target_property(file_content APP_GROUPS_ENABLED ${target} JUCE_APP_GROUPS_ENABLED)
  276. _juce_append_target_property(file_content APP_GROUP_IDS ${target} JUCE_APP_GROUP_IDS)
  277. _juce_append_target_property(file_content IS_PLUGIN ${target} JUCE_IS_PLUGIN)
  278. _juce_append_target_property(file_content ICLOUD_PERMISSIONS_ENABLED ${target} JUCE_ICLOUD_PERMISSIONS_ENABLED)
  279. if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
  280. _juce_append_record(file_content IS_IOS 1)
  281. else()
  282. _juce_append_record(file_content IS_IOS 0)
  283. endif()
  284. get_target_property(juce_library_code ${target} JUCE_GENERATED_SOURCES_DIRECTORY)
  285. set(info_file "${juce_library_code}/Info.txt")
  286. file(WRITE "${info_file}" "${file_content}")
  287. set_target_properties(${target} PROPERTIES JUCE_INFO_FILE "${info_file}")
  288. endfunction()
  289. # In this file, we put things that CMake is only able to divine at generate time, like preprocessor definitions.
  290. # We use the target preprocessor definitions to work out which JUCE modules should go in the JuceHeader.h.
  291. function(_juce_write_generate_time_info target)
  292. _juce_get_module_definitions(${target} OFF module_defs)
  293. _juce_append_record(defs MODULE_DEFINITIONS ${module_defs})
  294. _juce_append_target_property(defs EXECUTABLE_NAME ${target} JUCE_PRODUCT_NAME)
  295. _juce_append_target_property(defs PROJECT_NAME ${target} JUCE_PRODUCT_NAME)
  296. _juce_append_target_property(defs VERSION ${target} JUCE_VERSION)
  297. _juce_append_target_property(defs COMPANY_NAME ${target} JUCE_COMPANY_NAME)
  298. get_target_property(juce_library_code ${target} JUCE_GENERATED_SOURCES_DIRECTORY)
  299. set(defs_file "${juce_library_code}/$<CONFIG>/Defs.txt")
  300. file(GENERATE OUTPUT "${defs_file}" CONTENT "${defs}")
  301. set_target_properties(${target} PROPERTIES JUCE_DEFS_FILE "${defs_file}")
  302. endfunction()
  303. # ==================================================================================================
  304. function(juce_add_binary_data target)
  305. set(one_value_args NAMESPACE HEADER_NAME)
  306. set(multi_value_args SOURCES)
  307. cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN})
  308. list(LENGTH JUCE_ARG_SOURCES num_binary_files)
  309. if(${num_binary_files} LESS 1)
  310. message(FATAL_ERROR "juce_add_binary_data must be passed at least one file to encode")
  311. endif()
  312. add_library(${target} STATIC)
  313. set(juce_binary_data_folder "${CMAKE_CURRENT_BINARY_DIR}/juce_binarydata_${target}/JuceLibraryCode")
  314. set(binary_file_names)
  315. foreach(index RANGE 1 ${num_binary_files})
  316. list(APPEND binary_file_names "${juce_binary_data_folder}/BinaryData${index}.cpp")
  317. endforeach()
  318. file(MAKE_DIRECTORY ${juce_binary_data_folder})
  319. if(NOT JUCE_ARG_NAMESPACE)
  320. set(JUCE_ARG_NAMESPACE BinaryData)
  321. endif()
  322. if(NOT JUCE_ARG_HEADER_NAME)
  323. set(JUCE_ARG_HEADER_NAME BinaryData.h)
  324. endif()
  325. list(APPEND binary_file_names "${juce_binary_data_folder}/${JUCE_ARG_HEADER_NAME}")
  326. set(newline_delimited_input)
  327. foreach(name IN LISTS JUCE_ARG_SOURCES)
  328. _juce_make_absolute_and_check(name)
  329. set(newline_delimited_input "${newline_delimited_input}${name}\n")
  330. endforeach()
  331. set(input_file_list "${juce_binary_data_folder}/input_file_list")
  332. file(WRITE "${input_file_list}" "${newline_delimited_input}")
  333. add_custom_command(OUTPUT ${binary_file_names}
  334. COMMAND juce::juceaide binarydata "${JUCE_ARG_NAMESPACE}" "${JUCE_ARG_HEADER_NAME}"
  335. ${juce_binary_data_folder} "${input_file_list}"
  336. WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
  337. DEPENDS "${input_file_list}"
  338. VERBATIM)
  339. target_sources(${target} PRIVATE "${binary_file_names}")
  340. target_include_directories(${target} INTERFACE ${juce_binary_data_folder})
  341. target_compile_features(${target} PRIVATE cxx_std_14)
  342. # This fixes an issue where Xcode is unable to find binary data during archive.
  343. if(CMAKE_GENERATOR STREQUAL "Xcode")
  344. set_target_properties(${target} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "./")
  345. endif()
  346. if(JUCE_ARG_HEADER_NAME STREQUAL "BinaryData.h")
  347. target_compile_definitions(${target} INTERFACE JUCE_TARGET_HAS_BINARY_DATA=1)
  348. endif()
  349. endfunction()
  350. # ==================================================================================================
  351. function(_juce_version_code version_in out_var)
  352. string(REGEX REPLACE "\\." ";" version_list ${version_in})
  353. list(LENGTH version_list num_version_components)
  354. set(version_major 0)
  355. set(version_minor 0)
  356. set(version_patch 0)
  357. if(num_version_components GREATER 0)
  358. list(GET version_list 0 version_major)
  359. endif()
  360. if(num_version_components GREATER 1)
  361. list(GET version_list 1 version_minor)
  362. endif()
  363. if(num_version_components GREATER 2)
  364. list(GET version_list 2 version_patch)
  365. endif()
  366. math(EXPR hex "(${version_major} << 16) + (${version_minor} << 8) + ${version_patch}"
  367. OUTPUT_FORMAT HEXADECIMAL)
  368. set(${out_var} "${hex}" PARENT_SCOPE)
  369. endfunction()
  370. function(_juce_to_char_literal str out_var help_text)
  371. string(LENGTH "${str}" string_length)
  372. if(NOT "${string_length}" EQUAL "4")
  373. message(WARNING "The ${help_text} code must contain exactly four characters, but it was set to '${str}'")
  374. endif()
  375. # Round-tripping through a file is the simplest way to convert a string to hex...
  376. string(SUBSTRING "${str}" 0 4 four_chars)
  377. string(RANDOM LENGTH 16 random_string)
  378. set(scratch_file "${CMAKE_CURRENT_BINARY_DIR}/${random_string}_ascii_conversion.txt")
  379. file(WRITE "${scratch_file}" "${four_chars}")
  380. file(READ "${scratch_file}" four_chars_hex HEX)
  381. file(REMOVE "${scratch_file}")
  382. string(SUBSTRING "${four_chars_hex}00000000" 0 8 four_chars_hex)
  383. set(${out_var} "${four_chars_hex}" PARENT_SCOPE)
  384. endfunction()
  385. # ==================================================================================================
  386. function(juce_generate_juce_header target)
  387. get_target_property(juce_library_code ${target} JUCE_GENERATED_SOURCES_DIRECTORY)
  388. if(NOT juce_library_code)
  389. message(FATAL_ERROR "Target ${target} does not have a generated sources directory. Ensure it was created with a juce_add_* function")
  390. endif()
  391. set(juce_header ${juce_library_code}/JuceHeader.h)
  392. target_sources(${target} PRIVATE ${juce_header})
  393. set(defs_file $<GENEX_EVAL:$<TARGET_PROPERTY:${target},JUCE_DEFS_FILE>>)
  394. set(extra_args)
  395. add_custom_command(OUTPUT "${juce_header}"
  396. COMMAND juce::juceaide header "${defs_file}" "${juce_header}" ${extra_args}
  397. DEPENDS "${defs_file}"
  398. VERBATIM)
  399. endfunction()
  400. # ==================================================================================================
  401. function(_juce_execute_juceaide)
  402. if(NOT TARGET juce::juceaide)
  403. message(FATAL_ERROR "The juceaide target does not exist")
  404. endif()
  405. get_target_property(juceaide_location juce::juceaide IMPORTED_LOCATION)
  406. if(NOT EXISTS "${juceaide_location}")
  407. message(FATAL_ERROR "juceaide was imported, but it doesn't exist!")
  408. endif()
  409. execute_process(COMMAND "${juceaide_location}" ${ARGN}
  410. RESULT_VARIABLE result_variable
  411. OUTPUT_VARIABLE output
  412. ERROR_VARIABLE output)
  413. if(result_variable)
  414. message(FATAL_ERROR "Running juceaide failed:\n${output}")
  415. endif()
  416. endfunction()
  417. function(_juce_set_output_name target name)
  418. if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
  419. set_target_properties(${target} PROPERTIES
  420. OUTPUT_NAME ${name}
  421. XCODE_ATTRIBUTE_PRODUCT_NAME ${name})
  422. endif()
  423. endfunction()
  424. function(_juce_check_icon_files_exist icon_files)
  425. foreach(file IN LISTS icon_files)
  426. if(NOT EXISTS "${file}")
  427. message(FATAL_ERROR "Could not find icon file: ${file}")
  428. endif()
  429. endforeach()
  430. endfunction()
  431. function(_juce_generate_icon source_target dest_target)
  432. get_target_property(juce_library_code ${source_target} JUCE_GENERATED_SOURCES_DIRECTORY)
  433. get_target_property(juce_property_icon_big ${source_target} JUCE_ICON_BIG)
  434. get_target_property(juce_property_icon_small ${source_target} JUCE_ICON_SMALL)
  435. set(icon_args)
  436. if(juce_property_icon_big)
  437. list(APPEND icon_args "${juce_property_icon_big}")
  438. endif()
  439. if(juce_property_icon_small)
  440. list(APPEND icon_args "${juce_property_icon_small}")
  441. endif()
  442. set(generated_icon)
  443. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  444. if(NOT icon_args)
  445. return()
  446. endif()
  447. _juce_check_icon_files_exist("${icon_args}")
  448. set(generated_icon "${juce_library_code}/Icon.icns")
  449. # To get compiled properly, we need the icon before the plist is generated!
  450. _juce_execute_juceaide(macicon "${generated_icon}" ${icon_args})
  451. set_source_files_properties(${generated_icon} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
  452. elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  453. if(NOT icon_args)
  454. return()
  455. endif()
  456. _juce_check_icon_files_exist("${icon_args}")
  457. set(generated_icon "${juce_library_code}/icon.ico")
  458. _juce_execute_juceaide(winicon "${generated_icon}" ${icon_args})
  459. elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
  460. get_target_property(generated_icon ${source_target} JUCE_CUSTOM_XCASSETS_FOLDER)
  461. if(icon_args AND (NOT generated_icon))
  462. _juce_check_icon_files_exist("${icon_args}")
  463. set(out_path "${juce_library_code}/${dest_target}")
  464. set(generated_icon "${out_path}/Images.xcassets")
  465. # To get compiled properly, we need iOS assets at configure time!
  466. _juce_execute_juceaide(iosassets "${out_path}" ${icon_args})
  467. endif()
  468. if(NOT generated_icon)
  469. return()
  470. endif()
  471. set_target_properties(${dest_target} PROPERTIES
  472. XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon")
  473. get_target_property(add_storyboard ${source_target} JUCE_SHOULD_ADD_STORYBOARD)
  474. if(NOT add_storyboard)
  475. set_target_properties(${dest_target} PROPERTIES
  476. XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME "LaunchImage")
  477. endif()
  478. endif()
  479. if(generated_icon)
  480. _juce_check_icon_files_exist("${generated_icon}")
  481. target_sources(${dest_target} PRIVATE ${generated_icon})
  482. set_target_properties(${source_target} ${dest_target} PROPERTIES
  483. JUCE_ICON_FILE "${generated_icon}"
  484. RESOURCE "${generated_icon}")
  485. endif()
  486. endfunction()
  487. function(_juce_add_xcode_entitlements source_target dest_target)
  488. get_target_property(juce_kind_string ${dest_target} JUCE_TARGET_KIND_STRING)
  489. get_target_property(input_info_file ${source_target} JUCE_INFO_FILE)
  490. get_target_property(juce_library_code ${source_target} JUCE_GENERATED_SOURCES_DIRECTORY)
  491. set(entitlements_file "${juce_library_code}/${dest_target}.entitlements")
  492. _juce_execute_juceaide(entitlements "${juce_kind_string}" "${input_info_file}" "${entitlements_file}")
  493. set_target_properties(${dest_target} PROPERTIES
  494. XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${entitlements_file}")
  495. endfunction()
  496. function(_juce_configure_bundle source_target dest_target)
  497. _juce_generate_icon(${source_target} ${dest_target})
  498. _juce_write_configure_time_info(${source_target})
  499. if(NOT APPLE)
  500. return()
  501. endif()
  502. get_target_property(generated_icon ${source_target} JUCE_ICON_FILE)
  503. set(icon_dependency)
  504. if(generated_icon)
  505. set(icon_dependency "${generated_icon}")
  506. endif()
  507. get_target_property(juce_library_code ${source_target} JUCE_GENERATED_SOURCES_DIRECTORY)
  508. get_target_property(input_info_file ${source_target} JUCE_INFO_FILE)
  509. set(this_output_info_dir "${juce_library_code}/${dest_target}")
  510. set(this_output_pkginfo "${this_output_info_dir}/PkgInfo")
  511. set(this_output_plist "${this_output_info_dir}/Info.plist")
  512. get_target_property(juce_kind_string ${dest_target} JUCE_TARGET_KIND_STRING)
  513. _juce_execute_juceaide(plist "${juce_kind_string}" "${input_info_file}" "${this_output_plist}")
  514. set_target_properties(${dest_target} PROPERTIES
  515. BUNDLE TRUE
  516. MACOSX_BUNDLE_INFO_PLIST "${this_output_plist}")
  517. add_custom_command(OUTPUT "${this_output_pkginfo}"
  518. COMMAND juce::juceaide pkginfo "${juce_kind_string}" "${this_output_pkginfo}"
  519. VERBATIM)
  520. set(output_folder "$<TARGET_BUNDLE_CONTENT_DIR:${dest_target}>")
  521. target_sources(${dest_target} PRIVATE "${this_output_pkginfo}")
  522. set_source_files_properties("${this_output_pkginfo}" PROPERTIES
  523. HEADER_FILE_ONLY TRUE
  524. GENERATED TRUE)
  525. add_custom_command(TARGET ${dest_target} POST_BUILD
  526. COMMAND "${CMAKE_COMMAND}" -E copy "${this_output_pkginfo}" "${output_folder}"
  527. DEPENDS "${this_output_pkginfo}"
  528. VERBATIM)
  529. _juce_add_xcode_entitlements(${source_target} ${dest_target})
  530. if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
  531. get_target_property(add_storyboard ${source_target} JUCE_SHOULD_ADD_STORYBOARD)
  532. if(add_storyboard)
  533. get_target_property(storyboard_file ${source_target} JUCE_LAUNCH_STORYBOARD_FILE)
  534. if(NOT EXISTS "${storyboard_file}")
  535. message(FATAL_ERROR "Could not find storyboard file: ${storyboard_file}")
  536. endif()
  537. target_sources(${dest_target} PRIVATE "${storyboard_file}")
  538. set_property(TARGET ${dest_target} APPEND PROPERTY RESOURCE "${storyboard_file}")
  539. endif()
  540. endif()
  541. set_target_properties(${dest_target} PROPERTIES
  542. XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME
  543. "$<TARGET_PROPERTY:${source_target},JUCE_HARDENED_RUNTIME_ENABLED>"
  544. XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY
  545. "$<TARGET_PROPERTY:${source_target},JUCE_TARGETED_DEVICE_FAMILY>")
  546. if(juce_kind_string STREQUAL "AUv3 AppExtension")
  547. get_target_property(source_bundle_id ${source_target} JUCE_BUNDLE_ID)
  548. if(source_bundle_id MATCHES "\\.([^.]+)$")
  549. set_target_properties(${dest_target} PROPERTIES
  550. XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER
  551. "${source_bundle_id}.${CMAKE_MATCH_1}AUv3")
  552. else()
  553. message(FATAL_ERROR "Bundle ID should contain at least one `.`!")
  554. endif()
  555. else()
  556. set_target_properties(${dest_target} PROPERTIES
  557. XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER
  558. $<TARGET_PROPERTY:${source_target},JUCE_BUNDLE_ID>)
  559. endif()
  560. if(CMAKE_GENERATOR STREQUAL "Xcode")
  561. get_target_property(product_name ${source_target} JUCE_PRODUCT_NAME)
  562. set(install_path "$(LOCAL_APPS_DIR)")
  563. if(juce_kind_string STREQUAL "AUv3 AppExtension")
  564. set(install_path "${install_path}/${product_name}.app")
  565. if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
  566. set(install_path "${install_path}/PlugIns")
  567. else()
  568. set(install_path "${install_path}/Contents/PlugIns")
  569. endif()
  570. endif()
  571. set_target_properties(${dest_target} PROPERTIES
  572. XCODE_ATTRIBUTE_INSTALL_PATH "${install_path}"
  573. XCODE_ATTRIBUTE_SKIP_INSTALL "NO")
  574. endif()
  575. endfunction()
  576. function(_juce_add_resources_rc source_target dest_target)
  577. if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
  578. return()
  579. endif()
  580. get_target_property(juce_library_code ${source_target} JUCE_GENERATED_SOURCES_DIRECTORY)
  581. set(input_info_file "$<TARGET_PROPERTY:${source_target},JUCE_INFO_FILE>")
  582. get_target_property(generated_icon ${source_target} JUCE_ICON_FILE)
  583. set(dependency)
  584. if(generated_icon)
  585. set(dependency DEPENDS "${generated_icon}")
  586. endif()
  587. set(resource_rc_file "${juce_library_code}/resources.rc")
  588. add_custom_command(OUTPUT "${resource_rc_file}"
  589. COMMAND juce::juceaide rcfile "${input_info_file}" "${resource_rc_file}"
  590. ${dependency}
  591. VERBATIM)
  592. target_sources(${dest_target} PRIVATE "${resource_rc_file}")
  593. endfunction()
  594. function(_juce_configure_app_bundle source_target dest_target)
  595. set_target_properties(${dest_target} PROPERTIES
  596. JUCE_TARGET_KIND_STRING "App"
  597. MACOSX_BUNDLE TRUE
  598. WIN32_EXECUTABLE TRUE)
  599. _juce_add_resources_rc(${source_target} ${dest_target})
  600. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  601. set(nib_path "${JUCE_CMAKE_UTILS_DIR}/RecentFilesMenuTemplate.nib")
  602. target_sources("${dest_target}" PRIVATE "${nib_path}")
  603. set_source_files_properties("${nib_path}" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
  604. endif()
  605. endfunction()
  606. # ==================================================================================================
  607. function(_juce_create_windows_package source_target dest_target extension default_icon x32folder x64folder)
  608. if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
  609. return()
  610. endif()
  611. get_target_property(products_folder ${dest_target} LIBRARY_OUTPUT_DIRECTORY)
  612. set(product_name $<TARGET_PROPERTY:${source_target},JUCE_PRODUCT_NAME>)
  613. set(output_folder "${products_folder}/${product_name}.${extension}")
  614. set(is_x64 $<EQUAL:${CMAKE_SIZEOF_VOID_P},8>)
  615. set(arch_string $<IF:${is_x64},${x64folder},${x32folder}>)
  616. set_target_properties(${dest_target}
  617. PROPERTIES
  618. PDB_OUTPUT_DIRECTORY "${products_folder}"
  619. LIBRARY_OUTPUT_DIRECTORY "${output_folder}/Contents/${arch_string}")
  620. get_target_property(icon_file ${source_target} JUCE_ICON_FILE)
  621. if(NOT icon_file)
  622. set(icon_file "${default_icon}")
  623. endif()
  624. if(icon_file)
  625. set(desktop_ini "${output_folder}/desktop.ini")
  626. set(plugin_ico "${output_folder}/Plugin.ico")
  627. file(GENERATE OUTPUT "${desktop_ini}"
  628. CONTENT
  629. "[.ShellClassInfo]\nIconResource=Plugin.ico,0\nIconFile=Plugin.ico\nIconIndex=0\n")
  630. add_custom_command(TARGET ${dest_target} POST_BUILD
  631. COMMAND "${CMAKE_COMMAND}" -E copy "${icon_file}" "${plugin_ico}"
  632. COMMAND attrib +s "${desktop_ini}"
  633. COMMAND attrib +s "${output_folder}"
  634. DEPENDS "${icon_file}" "${desktop_ini}"
  635. VERBATIM)
  636. endif()
  637. endfunction()
  638. # ==================================================================================================
  639. function(_juce_add_unity_plugin_prefix_if_necessary name out_var)
  640. string(TOLOWER "${name}" lower)
  641. if(NOT lower MATCHES "^audioplugin")
  642. set(${out_var} "audioplugin_${name}" PARENT_SCOPE)
  643. else()
  644. set(${out_var} "${name}" PARENT_SCOPE)
  645. endif()
  646. endfunction()
  647. function(_juce_add_unity_script_file shared_target out_var)
  648. set(script_in "${JUCE_CMAKE_UTILS_DIR}/UnityPluginGUIScript.cs.in")
  649. get_target_property(plugin_name ${shared_target} JUCE_PLUGIN_NAME)
  650. get_target_property(plugin_vendor ${shared_target} JUCE_COMPANY_NAME)
  651. get_target_property(plugin_description ${shared_target} JUCE_DESCRIPTION)
  652. string(REGEX REPLACE " +" "_" plugin_class_name "${plugin_name}")
  653. get_target_property(juce_library_code ${shared_target} JUCE_GENERATED_SOURCES_DIRECTORY)
  654. _juce_add_unity_plugin_prefix_if_necessary("${plugin_name}" script_prefix)
  655. set(script_out "${juce_library_code}/${script_prefix}_UnityScript.cs")
  656. configure_file(${script_in} ${script_out})
  657. set(${out_var} "${script_out}" PARENT_SCOPE)
  658. endfunction()
  659. # ==================================================================================================
  660. function(_juce_copy_dir target from to)
  661. # This is a shim to make CMake copy a whole directory, rather than just
  662. # the contents of a directory
  663. add_custom_command(TARGET ${target} POST_BUILD
  664. COMMAND "${CMAKE_COMMAND}"
  665. "-Dsrc=${from}"
  666. "-Ddest=${to}"
  667. "-P" "${JUCE_CMAKE_UTILS_DIR}/copyDir.cmake"
  668. VERBATIM)
  669. endfunction()
  670. function(_juce_set_copy_properties shared_code target from to_property)
  671. get_target_property(destination "${shared_code}" "${to_property}")
  672. if(destination)
  673. set_target_properties("${target}" PROPERTIES JUCE_PLUGIN_COPY_DIR "${destination}")
  674. endif()
  675. set_target_properties("${target}" PROPERTIES JUCE_PLUGIN_ARTEFACT_FILE "${from}")
  676. endfunction()
  677. function(juce_enable_copy_plugin_step shared_code_target)
  678. get_target_property(active_targets "${shared_code_target}" JUCE_ACTIVE_PLUGIN_TARGETS)
  679. foreach(target IN LISTS active_targets)
  680. get_target_property(source "${target}" JUCE_PLUGIN_ARTEFACT_FILE)
  681. if(source)
  682. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  683. add_custom_command(TARGET ${target} POST_BUILD
  684. COMMAND "${CMAKE_COMMAND}"
  685. "-Dsrc=${source}"
  686. "-P" "${JUCE_CMAKE_UTILS_DIR}/checkBundleSigning.cmake"
  687. VERBATIM)
  688. endif()
  689. get_target_property(dest "${target}" JUCE_PLUGIN_COPY_DIR)
  690. if(dest)
  691. _juce_copy_dir("${target}" "${source}" "$<GENEX_EVAL:${dest}>")
  692. else()
  693. message(WARNING "Target '${target}' requested copy but no destination is set")
  694. endif()
  695. endif()
  696. endforeach()
  697. endfunction()
  698. # ==================================================================================================
  699. function(_juce_set_plugin_target_properties shared_code_target kind)
  700. set(target_name ${shared_code_target}_${kind})
  701. set_target_properties(${target_name} PROPERTIES
  702. ARCHIVE_OUTPUT_DIRECTORY "$<GENEX_EVAL:$<TARGET_PROPERTY:${shared_code_target},ARCHIVE_OUTPUT_DIRECTORY>>/${kind}"
  703. LIBRARY_OUTPUT_DIRECTORY "$<GENEX_EVAL:$<TARGET_PROPERTY:${shared_code_target},LIBRARY_OUTPUT_DIRECTORY>>/${kind}"
  704. RUNTIME_OUTPUT_DIRECTORY "$<GENEX_EVAL:$<TARGET_PROPERTY:${shared_code_target},RUNTIME_OUTPUT_DIRECTORY>>/${kind}")
  705. get_target_property(products_folder ${target_name} LIBRARY_OUTPUT_DIRECTORY)
  706. set(product_name $<TARGET_PROPERTY:${shared_code_target},JUCE_PRODUCT_NAME>)
  707. if(kind STREQUAL "VST3")
  708. set_target_properties(${target_name} PROPERTIES
  709. BUNDLE_EXTENSION vst3
  710. PREFIX ""
  711. SUFFIX .vst3
  712. BUNDLE TRUE
  713. XCODE_ATTRIBUTE_WRAPPER_EXTENSION vst3
  714. XCODE_ATTRIBUTE_LIBRARY_STYLE Bundle
  715. XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE YES)
  716. _juce_create_windows_package(${shared_code_target} ${target_name} vst3 "" x86-win x86_64-win)
  717. set(output_path "${products_folder}/${product_name}.vst3")
  718. if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD"))
  719. set_target_properties(${target_name} PROPERTIES
  720. SUFFIX .so
  721. LIBRARY_OUTPUT_DIRECTORY "${output_path}/Contents/${JUCE_TARGET_ARCHITECTURE}-linux")
  722. endif()
  723. _juce_set_copy_properties(${shared_code_target} ${target_name} "${output_path}" JUCE_VST3_COPY_DIR)
  724. elseif(kind STREQUAL "VST")
  725. set_target_properties(${target_name} PROPERTIES
  726. BUNDLE_EXTENSION vst
  727. BUNDLE TRUE
  728. XCODE_ATTRIBUTE_WRAPPER_EXTENSION vst
  729. XCODE_ATTRIBUTE_LIBRARY_STYLE Bundle
  730. XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE YES)
  731. set(output_path "$<TARGET_FILE:${target_name}>")
  732. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  733. set(output_path "$<TARGET_BUNDLE_DIR:${target_name}>")
  734. endif()
  735. _juce_set_copy_properties(${shared_code_target} ${target_name} "${output_path}" JUCE_VST_COPY_DIR)
  736. elseif(kind STREQUAL "AU")
  737. set_target_properties(${target_name} PROPERTIES
  738. BUNDLE_EXTENSION component
  739. XCODE_ATTRIBUTE_WRAPPER_EXTENSION component
  740. BUNDLE TRUE
  741. XCODE_ATTRIBUTE_LIBRARY_STYLE Bundle
  742. XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE YES)
  743. set(output_path "$<TARGET_BUNDLE_DIR:${target_name}>")
  744. _juce_set_copy_properties(${shared_code_target} ${target_name} "${output_path}" JUCE_AU_COPY_DIR)
  745. elseif(kind STREQUAL "AUv3")
  746. set_target_properties(${target_name} PROPERTIES
  747. XCODE_PRODUCT_TYPE "com.apple.product-type.app-extension"
  748. BUNDLE_EXTENSION appex
  749. XCODE_ATTRIBUTE_WRAPPER_EXTENSION appex
  750. XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE YES)
  751. elseif(kind STREQUAL "AAX")
  752. set_target_properties(${target_name} PROPERTIES
  753. BUNDLE_EXTENSION aaxplugin
  754. PREFIX ""
  755. SUFFIX .aaxplugin
  756. XCODE_ATTRIBUTE_WRAPPER_EXTENSION aaxplugin
  757. BUNDLE TRUE
  758. XCODE_ATTRIBUTE_LIBRARY_STYLE Bundle
  759. XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE YES)
  760. get_target_property(default_icon juce_aax_sdk INTERFACE_JUCE_AAX_DEFAULT_ICON)
  761. _juce_create_windows_package(${shared_code_target} ${target_name} aaxplugin "${default_icon}" Win32 x64)
  762. set(output_path "${products_folder}/${product_name}.aaxplugin")
  763. _juce_set_copy_properties(${shared_code_target} ${target_name} "${output_path}" JUCE_AAX_COPY_DIR)
  764. elseif(kind STREQUAL "Unity")
  765. set_target_properties(${target_name} PROPERTIES
  766. BUNDLE_EXTENSION bundle
  767. XCODE_ATTRIBUTE_WRAPPER_EXTENSION bundle
  768. BUNDLE TRUE
  769. XCODE_ATTRIBUTE_LIBRARY_STYLE Bundle
  770. XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE YES)
  771. _juce_add_unity_script_file(${shared_code_target} script_file)
  772. target_sources(${target_name} PRIVATE "${script_file}")
  773. set_source_files_properties("${script_file}" PROPERTIES
  774. GENERATED TRUE
  775. MACOSX_PACKAGE_LOCATION Resources)
  776. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  777. set(output_path "$<TARGET_BUNDLE_DIR:${target_name}>")
  778. _juce_set_copy_properties(${shared_code_target} ${target_name} "${output_path}" JUCE_UNITY_COPY_DIR)
  779. else()
  780. # On windows and linux, the gui script needs to be copied next to the unity output
  781. add_custom_command(TARGET ${target_name} POST_BUILD
  782. COMMAND "${CMAKE_COMMAND}" -E copy "${script_file}" "${products_folder}"
  783. DEPENDS "${script_file}"
  784. VERBATIM)
  785. _juce_set_copy_properties(${shared_code_target}
  786. ${target_name}
  787. "$<TARGET_FILE:${target_name}>"
  788. JUCE_UNITY_COPY_DIR)
  789. _juce_set_copy_properties(${shared_code_target}
  790. ${target_name}
  791. "${script_file}"
  792. JUCE_UNITY_COPY_DIR)
  793. endif()
  794. elseif(kind STREQUAL "LV2")
  795. set_target_properties(${target_name} PROPERTIES BUNDLE FALSE)
  796. get_target_property(JUCE_LV2URI "${shared_code_target}" JUCE_LV2URI)
  797. if(NOT JUCE_LV2URI MATCHES "https?://.*")
  798. message(WARNING
  799. "LV2URI should be well-formed with an 'http' prefix. "
  800. "Check the LV2URI argument to juce_add_plugin.")
  801. endif()
  802. set(source_header "${JUCE_CMAKE_UTILS_DIR}/JuceLV2Defines.h.in")
  803. get_target_property(juce_library_code "${shared_code_target}" JUCE_GENERATED_SOURCES_DIRECTORY)
  804. configure_file("${source_header}" "${juce_library_code}/JuceLV2Defines.h")
  805. set(output_path "${products_folder}/${product_name}.lv2")
  806. set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${output_path}")
  807. add_custom_command(TARGET ${target_name} POST_BUILD
  808. COMMAND juce::juce_lv2_helper "$<TARGET_FILE:${target_name}>"
  809. VERBATIM)
  810. _juce_set_copy_properties(${shared_code_target} ${target_name} "${output_path}" JUCE_LV2_COPY_DIR)
  811. endif()
  812. endfunction()
  813. # Place plugin wrapper targets alongside the shared code target in IDEs
  814. function(_juce_set_plugin_folder_property shared_target wrapper_target)
  815. get_target_property(folder_to_use "${shared_target}" FOLDER)
  816. if(folder_to_use STREQUAL "folder_to_use-NOTFOUND")
  817. set_target_properties("${shared_target}" PROPERTIES FOLDER "${shared_target}")
  818. elseif(NOT folder_to_use MATCHES ".*${shared_target}$")
  819. set_target_properties("${shared_target}" PROPERTIES FOLDER "${folder_to_use}/${shared_target}")
  820. endif()
  821. get_target_property(folder_to_use "${shared_target}" FOLDER)
  822. set_target_properties("${wrapper_target}" PROPERTIES FOLDER "${folder_to_use}")
  823. endfunction()
  824. # Convert the cmake plugin kind ids to strings understood by ProjectType::Target::typeFromName
  825. function(_juce_get_plugin_kind_name kind out_var)
  826. if(kind STREQUAL "AU")
  827. set(${out_var} "AU" PARENT_SCOPE)
  828. elseif(kind STREQUAL "AUv3")
  829. set(${out_var} "AUv3 AppExtension" PARENT_SCOPE)
  830. elseif(kind STREQUAL "AAX")
  831. set(${out_var} "AAX" PARENT_SCOPE)
  832. elseif(kind STREQUAL "LV2")
  833. set(${out_var} "LV2" PARENT_SCOPE)
  834. elseif(kind STREQUAL "Standalone")
  835. set(${out_var} "Standalone Plugin" PARENT_SCOPE)
  836. elseif(kind STREQUAL "Unity")
  837. set(${out_var} "Unity Plugin" PARENT_SCOPE)
  838. elseif(kind STREQUAL "VST")
  839. set(${out_var} "VST" PARENT_SCOPE)
  840. elseif(kind STREQUAL "VST3")
  841. set(${out_var} "VST3" PARENT_SCOPE)
  842. endif()
  843. endfunction()
  844. function(_juce_link_plugin_wrapper shared_code_target kind)
  845. set(target_name ${shared_code_target}_${kind})
  846. if(CMAKE_SYSTEM_NAME STREQUAL "Android")
  847. add_library(${target_name} SHARED)
  848. elseif((kind STREQUAL "Standalone") OR (kind STREQUAL "AUv3"))
  849. add_executable(${target_name} WIN32 MACOSX_BUNDLE)
  850. else()
  851. add_library(${target_name} MODULE)
  852. endif()
  853. if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD"))
  854. target_link_options(${target_name} PRIVATE "-Wl,--no-undefined")
  855. endif()
  856. # We re-export the shared code's private include dirs, because the wrapper targets need to
  857. # see the module headers. We don't just link publicly, because that would introduce
  858. # conflicting macro definitions.
  859. target_include_directories(${target_name} PRIVATE
  860. $<TARGET_PROPERTY:${shared_code_target},INCLUDE_DIRECTORIES>)
  861. target_link_libraries(${target_name} PRIVATE
  862. ${shared_code_target}
  863. juce::juce_audio_plugin_client_${kind})
  864. _juce_set_output_name(${target_name} $<TARGET_PROPERTY:${shared_code_target},JUCE_PRODUCT_NAME>)
  865. _juce_set_plugin_folder_property("${shared_code_target}" "${target_name}")
  866. _juce_get_plugin_kind_name(${kind} juce_kind_string)
  867. set_target_properties(${target_name} PROPERTIES
  868. XCODE_ATTRIBUTE_CLANG_LINK_OBJC_RUNTIME NO
  869. XCODE_ATTRIBUTE_COMBINE_HIDPI_IMAGES YES
  870. POSITION_INDEPENDENT_CODE TRUE
  871. VISIBILITY_INLINES_HIDDEN TRUE
  872. C_VISIBILITY_PRESET hidden
  873. CXX_VISIBILITY_PRESET hidden
  874. JUCE_TARGET_KIND_STRING "${juce_kind_string}")
  875. # Under the Xcode generator, POST_BUILD commands (including the plugin copy step) run before
  876. # signing, but M1 macs will only load signed binaries. Setting "adhoc_codesign" forces the
  877. # linker to sign bundles, so that they can be loaded even if they are copied before the "real"
  878. # signing step. See issue 21854 on the CMake Gitlab repo.
  879. if("${CMAKE_GENERATOR};${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Xcode;Darwin;arm64")
  880. target_link_options(${target_name} PRIVATE LINKER:-adhoc_codesign)
  881. endif()
  882. add_dependencies(${shared_code_target}_All ${target_name})
  883. if(NOT kind STREQUAL "LV2")
  884. _juce_configure_bundle(${shared_code_target} ${target_name})
  885. endif()
  886. _juce_set_plugin_target_properties(${shared_code_target} ${kind})
  887. endfunction()
  888. # ==================================================================================================
  889. function(_juce_get_vst3_category_string target out_var)
  890. get_target_property(vst3_categories ${target} JUCE_VST3_CATEGORIES)
  891. if((NOT Fx IN_LIST vst3_categories) AND (NOT Instrument IN_LIST vst3_categories))
  892. get_target_property(is_synth ${target} JUCE_IS_SYNTH)
  893. if(is_synth)
  894. set(first_type Instrument)
  895. else()
  896. set(first_type Fx)
  897. endif()
  898. list(INSERT vst3_categories 0 ${first_type})
  899. else()
  900. if(Instrument IN_LIST vst3_categories)
  901. list(REMOVE_ITEM vst3_categories Instrument)
  902. list(INSERT vst3_categories 0 Instrument)
  903. endif()
  904. if(Fx IN_LIST vst3_categories)
  905. list(REMOVE_ITEM vst3_categories Fx)
  906. list(INSERT vst3_categories 0 Fx)
  907. endif()
  908. endif()
  909. string(REGEX REPLACE ";" "|" result "${vst3_categories}")
  910. set(${out_var} ${result} PARENT_SCOPE)
  911. endfunction()
  912. function(_juce_configure_plugin_targets target)
  913. _juce_set_output_name(${target} $<TARGET_PROPERTY:${target},JUCE_PRODUCT_NAME>_SharedCode)
  914. target_link_libraries(${target} PRIVATE juce::juce_audio_plugin_client_utils)
  915. get_target_property(enabled_formats ${target} JUCE_FORMATS)
  916. set(active_formats)
  917. _juce_get_platform_plugin_kinds(plugin_kinds)
  918. foreach(kind IN LISTS plugin_kinds)
  919. if(kind IN_LIST enabled_formats)
  920. list(APPEND active_formats "${kind}")
  921. endif()
  922. endforeach()
  923. if((VST IN_LIST active_formats) AND (NOT TARGET juce_vst2_sdk))
  924. message(FATAL_ERROR "Use juce_set_vst2_sdk_path to set up the VST sdk before adding VST targets")
  925. elseif((AAX IN_LIST active_formats) AND (NOT TARGET juce_aax_sdk))
  926. message(FATAL_ERROR "Use juce_set_aax_sdk_path to set up the AAX sdk before adding AAX targets")
  927. endif()
  928. _juce_add_standard_defs(${target})
  929. _juce_add_plugin_definitions(${target} PRIVATE ${active_formats})
  930. # The plugin wrappers need to know what other modules are available, especially
  931. # juce_audio_utils and juce_gui_basics. We achieve this by searching for
  932. # JUCE_MODULE_AVAILABLE_ private compile definitions, and reexporting them in
  933. # the interface compile definitions.
  934. _juce_get_module_definitions(${target} ON enabled_modules)
  935. target_compile_definitions(${target} INTERFACE ${enabled_modules})
  936. target_compile_definitions(${target} PRIVATE JUCE_SHARED_CODE=1)
  937. get_target_property(project_version_string ${target} JUCE_VERSION)
  938. _juce_version_code(${project_version_string} project_version_hex)
  939. get_target_property(project_manufacturer_code ${target} JUCE_PLUGIN_MANUFACTURER_CODE)
  940. get_target_property(project_plugin_code ${target} JUCE_PLUGIN_CODE)
  941. get_target_property(use_legacy_compatibility_plugin_code ${target} JUCE_USE_LEGACY_COMPATIBILITY_PLUGIN_CODE)
  942. if(use_legacy_compatibility_plugin_code)
  943. set(project_manufacturer_code "proj")
  944. endif()
  945. _juce_to_char_literal(${project_manufacturer_code} project_manufacturer_code "plugin manufacturer")
  946. _juce_to_char_literal(${project_plugin_code} project_plugin_code "plugin")
  947. _juce_get_vst3_category_string(${target} vst3_category_string)
  948. target_compile_definitions(${target} PUBLIC
  949. JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone
  950. JucePlugin_IsSynth=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_IS_SYNTH>>
  951. JucePlugin_ManufacturerCode=0x${project_manufacturer_code}
  952. JucePlugin_Manufacturer="$<TARGET_PROPERTY:${target},JUCE_COMPANY_NAME>"
  953. JucePlugin_ManufacturerWebsite="$<TARGET_PROPERTY:${target},JUCE_COMPANY_WEBSITE>"
  954. JucePlugin_ManufacturerEmail="$<TARGET_PROPERTY:${target},JUCE_COMPANY_EMAIL>"
  955. JucePlugin_PluginCode=0x${project_plugin_code}
  956. JucePlugin_ProducesMidiOutput=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_NEEDS_MIDI_OUTPUT>>
  957. JucePlugin_IsMidiEffect=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_IS_MIDI_EFFECT>>
  958. JucePlugin_WantsMidiInput=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_NEEDS_MIDI_INPUT>>
  959. JucePlugin_EditorRequiresKeyboardFocus=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_EDITOR_WANTS_KEYBOARD_FOCUS>>
  960. JucePlugin_Name="$<TARGET_PROPERTY:${target},JUCE_PLUGIN_NAME>"
  961. JucePlugin_Desc="$<TARGET_PROPERTY:${target},JUCE_DESCRIPTION>"
  962. JucePlugin_Version=${project_version_string}
  963. JucePlugin_VersionString="${project_version_string}"
  964. JucePlugin_VersionCode=${project_version_hex}
  965. JucePlugin_VSTUniqueID=JucePlugin_PluginCode
  966. JucePlugin_VSTCategory=$<TARGET_PROPERTY:${target},JUCE_VST2_CATEGORY>
  967. JucePlugin_Vst3Category="${vst3_category_string}"
  968. JucePlugin_AUMainType=$<TARGET_PROPERTY:${target},JUCE_AU_MAIN_TYPE_CODE>
  969. JucePlugin_AUSubType=JucePlugin_PluginCode
  970. JucePlugin_AUExportPrefix=$<TARGET_PROPERTY:${target},JUCE_AU_EXPORT_PREFIX>
  971. JucePlugin_AUExportPrefixQuoted="$<TARGET_PROPERTY:${target},JUCE_AU_EXPORT_PREFIX>"
  972. JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode
  973. JucePlugin_CFBundleIdentifier=$<TARGET_PROPERTY:${target},JUCE_BUNDLE_ID>
  974. JucePlugin_AAXIdentifier=$<TARGET_PROPERTY:${target},JUCE_AAX_IDENTIFIER>
  975. JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode
  976. JucePlugin_AAXProductId=JucePlugin_PluginCode
  977. JucePlugin_AAXCategory=$<TARGET_PROPERTY:${target},JUCE_AAX_CATEGORY>
  978. JucePlugin_AAXDisableBypass=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_DISABLE_AAX_BYPASS>>
  979. JucePlugin_AAXDisableMultiMono=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_DISABLE_AAX_MULTI_MONO>>
  980. JucePlugin_VSTNumMidiInputs=$<TARGET_PROPERTY:${target},JUCE_VST_NUM_MIDI_INS>
  981. JucePlugin_VSTNumMidiOutputs=$<TARGET_PROPERTY:${target},JUCE_VST_NUM_MIDI_OUTS>
  982. JucePlugin_Enable_ARA=$<BOOL:$<TARGET_PROPERTY:${target},JUCE_IS_ARA_EFFECT>>
  983. JucePlugin_ARAFactoryID=$<TARGET_PROPERTY:${target},JUCE_ARA_FACTORY_ID>
  984. JucePlugin_ARADocumentArchiveID=$<TARGET_PROPERTY:${target},JUCE_ARA_DOCUMENT_ARCHIVE_ID>
  985. JucePlugin_ARACompatibleArchiveIDs=$<TARGET_PROPERTY:${target},JUCE_ARA_COMPATIBLE_ARCHIVE_IDS>
  986. JucePlugin_ARAContentTypes=$<TARGET_PROPERTY:${target},JUCE_ARA_ANALYSIS_TYPES>
  987. JucePlugin_ARATransformationFlags=$<TARGET_PROPERTY:${target},JUCE_ARA_TRANSFORMATION_FLAGS>)
  988. set_target_properties(${target} PROPERTIES
  989. POSITION_INDEPENDENT_CODE TRUE
  990. INTERFACE_POSITION_INDEPENDENT_CODE TRUE
  991. VISIBILITY_INLINES_HIDDEN TRUE
  992. C_VISIBILITY_PRESET hidden
  993. CXX_VISIBILITY_PRESET hidden)
  994. # A convenience target for building all plugin variations at once
  995. add_custom_target(${target}_All)
  996. _juce_set_plugin_folder_property("${target}" "${target}_All")
  997. foreach(kind IN LISTS active_formats)
  998. _juce_link_plugin_wrapper(${target} ${kind})
  999. if(TARGET ${target}_${kind})
  1000. list(APPEND active_plugin_targets ${target}_${kind})
  1001. endif()
  1002. endforeach()
  1003. set_target_properties(${target} PROPERTIES JUCE_ACTIVE_PLUGIN_TARGETS "${active_plugin_targets}")
  1004. if(TARGET ${target}_Standalone)
  1005. _juce_configure_app_bundle(${target} ${target}_Standalone)
  1006. endif()
  1007. if(TARGET ${target}_AU)
  1008. _juce_add_au_resource_fork(${target} ${target}_AU)
  1009. endif()
  1010. if(TARGET ${target}_AAX)
  1011. target_link_libraries(${target}_AAX PRIVATE juce_aax_sdk)
  1012. endif()
  1013. if((TARGET ${target}_AUv3) AND (TARGET ${target}_Standalone))
  1014. add_dependencies(${target}_Standalone ${target}_AUv3)
  1015. # Copy the AUv3 into the Standalone app bundle
  1016. _juce_copy_dir(${target}_Standalone
  1017. "$<TARGET_BUNDLE_DIR:${target}_AUv3>"
  1018. "$<TARGET_BUNDLE_CONTENT_DIR:${target}_Standalone>/PlugIns")
  1019. endif()
  1020. get_target_property(wants_copy "${target}" JUCE_COPY_PLUGIN_AFTER_BUILD)
  1021. if(wants_copy)
  1022. juce_enable_copy_plugin_step("${target}")
  1023. endif()
  1024. endfunction()
  1025. # ==================================================================================================
  1026. function(_juce_set_generic_property_if_not_set target property)
  1027. list(LENGTH ARGN num_extra_args)
  1028. if(num_extra_args EQUAL 0)
  1029. return()
  1030. endif()
  1031. set(existing_property)
  1032. get_target_property(existing_property ${target} ${property})
  1033. if(existing_property STREQUAL "existing_property-NOTFOUND")
  1034. set_target_properties(${target} PROPERTIES ${property} "${ARGN}")
  1035. endif()
  1036. endfunction()
  1037. function(_juce_set_property_if_not_set target property)
  1038. _juce_set_generic_property_if_not_set(${target} JUCE_${property} ${ARGN})
  1039. endfunction()
  1040. function(_juce_make_valid_4cc out_var)
  1041. string(RANDOM LENGTH 1 ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZ" head)
  1042. string(RANDOM LENGTH 3 ALPHABET "abcdefghijklmnopqrstuvwxyz" tail)
  1043. set(${out_var} "${head}${tail}" PARENT_SCOPE)
  1044. endfunction()
  1045. # This function adds some default properties that plugin targets expect to be
  1046. # set, in order to generate the correct compile definitions.
  1047. function(_juce_set_fallback_properties target)
  1048. _juce_set_property_if_not_set(${target} PRODUCT_NAME ${target})
  1049. get_target_property(output_name ${target} JUCE_PRODUCT_NAME)
  1050. _juce_set_property_if_not_set(${target} DESCRIPTION "${output_name}")
  1051. _juce_set_property_if_not_set(${target} PLUGIN_NAME "${output_name}")
  1052. get_target_property(real_company_name ${target} JUCE_COMPANY_NAME)
  1053. _juce_set_property_if_not_set(${target} BUNDLE_ID "com.${real_company_name}.${target}")
  1054. _juce_set_property_if_not_set(${target} VERSION ${PROJECT_VERSION})
  1055. get_target_property(final_version ${target} JUCE_VERSION)
  1056. if(NOT final_version)
  1057. message(FATAL_ERROR "Target ${target} must have its VERSION argument set, or must be part of a project with a PROJECT_VERSION")
  1058. endif()
  1059. _juce_set_property_if_not_set(${target} BUILD_VERSION "${final_version}")
  1060. get_target_property(custom_xcassets ${target} JUCE_CUSTOM_XCASSETS_FOLDER)
  1061. set(needs_storyboard TRUE)
  1062. if(custom_xcassets)
  1063. set(needs_storyboard FALSE)
  1064. endif()
  1065. set_target_properties(${target} PROPERTIES JUCE_SHOULD_ADD_STORYBOARD ${needs_storyboard})
  1066. _juce_set_property_if_not_set(${target} IPHONE_SCREEN_ORIENTATIONS
  1067. UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft
  1068. UIInterfaceOrientationLandscapeRight)
  1069. _juce_set_property_if_not_set(${target} IPAD_SCREEN_ORIENTATIONS
  1070. UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft
  1071. UIInterfaceOrientationLandscapeRight)
  1072. _juce_set_property_if_not_set(${target}
  1073. LAUNCH_STORYBOARD_FILE "${JUCE_CMAKE_UTILS_DIR}/LaunchScreen.storyboard")
  1074. _juce_set_property_if_not_set(${target} PLUGIN_MANUFACTURER_CODE "Manu")
  1075. # The plugin code will change on each run, unless you specify one manually!
  1076. _juce_make_valid_4cc(random_code)
  1077. _juce_set_property_if_not_set(${target} PLUGIN_CODE ${random_code})
  1078. _juce_set_property_if_not_set(${target} IS_SYNTH FALSE)
  1079. _juce_set_property_if_not_set(${target} NEEDS_MIDI_INPUT FALSE)
  1080. _juce_set_property_if_not_set(${target} NEEDS_MIDI_OUTPUT FALSE)
  1081. _juce_set_property_if_not_set(${target} IS_MIDI_EFFECT FALSE)
  1082. _juce_set_property_if_not_set(${target} EDITOR_WANTS_KEYBOARD_FOCUS FALSE)
  1083. _juce_set_property_if_not_set(${target} DISABLE_AAX_BYPASS FALSE)
  1084. _juce_set_property_if_not_set(${target} DISABLE_AAX_MULTI_MONO FALSE)
  1085. _juce_set_property_if_not_set(${target} PLUGINHOST_AU FALSE)
  1086. get_target_property(bundle_id ${target} JUCE_BUNDLE_ID)
  1087. _juce_set_property_if_not_set(${target} AAX_IDENTIFIER ${bundle_id})
  1088. _juce_set_property_if_not_set(${target} VST_NUM_MIDI_INS 16)
  1089. _juce_set_property_if_not_set(${target} VST_NUM_MIDI_OUTS 16)
  1090. _juce_set_property_if_not_set(${target} AU_SANDBOX_SAFE FALSE)
  1091. _juce_set_property_if_not_set(${target} SUPPRESS_AU_PLIST_RESOURCE_USAGE FALSE)
  1092. _juce_set_property_if_not_set(${target} HARDENED_RUNTIME_ENABLED NO)
  1093. _juce_set_property_if_not_set(${target} APP_SANDBOX_ENABLED NO)
  1094. _juce_set_property_if_not_set(${target} APP_SANDBOX_INHERIT NO)
  1095. get_target_property(is_synth ${target} JUCE_IS_SYNTH)
  1096. # VST3_CATEGORIES
  1097. if(is_synth)
  1098. _juce_set_property_if_not_set(${target} VST3_CATEGORIES Instrument Synth)
  1099. else()
  1100. _juce_set_property_if_not_set(${target} VST3_CATEGORIES Fx)
  1101. endif()
  1102. # VST2_CATEGORY
  1103. if(is_synth)
  1104. _juce_set_property_if_not_set(${target} VST2_CATEGORY kPlugCategSynth)
  1105. else()
  1106. _juce_set_property_if_not_set(${target} VST2_CATEGORY kPlugCategEffect)
  1107. endif()
  1108. get_target_property(is_midi_effect ${target} JUCE_IS_MIDI_EFFECT)
  1109. get_target_property(needs_midi_input ${target} JUCE_NEEDS_MIDI_INPUT)
  1110. # AU MAIN TYPE
  1111. if(is_midi_effect)
  1112. _juce_set_property_if_not_set(${target} AU_MAIN_TYPE kAudioUnitType_MIDIProcessor)
  1113. elseif(is_synth)
  1114. _juce_set_property_if_not_set(${target} AU_MAIN_TYPE kAudioUnitType_MusicDevice)
  1115. elseif(needs_midi_input)
  1116. _juce_set_property_if_not_set(${target} AU_MAIN_TYPE kAudioUnitType_MusicEffect)
  1117. else()
  1118. _juce_set_property_if_not_set(${target} AU_MAIN_TYPE kAudioUnitType_Effect)
  1119. endif()
  1120. _juce_set_property_if_not_set(${target} TARGETED_DEVICE_FAMILY "1,2")
  1121. set(au_category_codes
  1122. 'aufx'
  1123. 'aufc'
  1124. 'augn'
  1125. 'aumi'
  1126. 'aumx'
  1127. 'aumu'
  1128. 'aumf'
  1129. 'auol'
  1130. 'auou'
  1131. 'aupn')
  1132. set(au_category_strings
  1133. kAudioUnitType_Effect
  1134. kAudioUnitType_FormatConverter
  1135. kAudioUnitType_Generator
  1136. kAudioUnitType_MIDIProcessor
  1137. kAudioUnitType_Mixer
  1138. kAudioUnitType_MusicDevice
  1139. kAudioUnitType_MusicEffect
  1140. kAudioUnitType_OfflineEffect
  1141. kAudioUnitType_Output
  1142. kAudioUnitType_Panner)
  1143. # AU export prefix
  1144. string(MAKE_C_IDENTIFIER ${output_name} au_prefix)
  1145. set(au_prefix "${au_prefix}AU")
  1146. _juce_set_property_if_not_set(${target} AU_EXPORT_PREFIX ${au_prefix})
  1147. # Find appropriate AU category code
  1148. get_target_property(actual_au_category ${target} JUCE_AU_MAIN_TYPE)
  1149. list(FIND au_category_strings ${actual_au_category} au_index)
  1150. if(au_index GREATER_EQUAL 0)
  1151. list(GET au_category_codes ${au_index} au_code_representation)
  1152. set_target_properties(${target} PROPERTIES JUCE_AU_MAIN_TYPE_CODE ${au_code_representation})
  1153. endif()
  1154. # AAX category
  1155. # The order of these strings is important, as the index of each string
  1156. # will be used to set an appropriate bit in the category bitfield.
  1157. set(aax_category_strings
  1158. ePlugInCategory_None
  1159. ePlugInCategory_EQ
  1160. ePlugInCategory_Dynamics
  1161. ePlugInCategory_PitchShift
  1162. ePlugInCategory_Reverb
  1163. ePlugInCategory_Delay
  1164. ePlugInCategory_Modulation
  1165. ePlugInCategory_Harmonic
  1166. ePlugInCategory_NoiseReduction
  1167. ePlugInCategory_Dither
  1168. ePlugInCategory_SoundField
  1169. ePlugInCategory_HWGenerators
  1170. ePlugInCategory_SWGenerators
  1171. ePlugInCategory_WrappedPlugin
  1172. ePlugInCategory_Effect)
  1173. if(is_synth)
  1174. set(default_aax_category ePlugInCategory_SWGenerators)
  1175. else()
  1176. set(default_aax_category ePlugInCategory_None)
  1177. endif()
  1178. _juce_set_property_if_not_set(${target} AAX_CATEGORY ${default_aax_category})
  1179. # Replace AAX category string with its integral representation
  1180. get_target_property(actual_aax_category ${target} JUCE_AAX_CATEGORY)
  1181. set(aax_category_int "")
  1182. foreach(category_string IN LISTS actual_aax_category)
  1183. list(FIND aax_category_strings ${category_string} aax_index)
  1184. if(aax_index GREATER_EQUAL 0)
  1185. if(aax_index EQUAL 0)
  1186. set(aax_category_bit 0)
  1187. else()
  1188. set(aax_category_bit "1 << (${aax_index} - 1)")
  1189. endif()
  1190. if(aax_category_int STREQUAL "")
  1191. set(aax_category_int 0)
  1192. endif()
  1193. math(EXPR aax_category_int "${aax_category_int} | (${aax_category_bit})")
  1194. endif()
  1195. endforeach()
  1196. if(NOT aax_category_int STREQUAL "")
  1197. set_target_properties(${target} PROPERTIES JUCE_AAX_CATEGORY ${aax_category_int})
  1198. endif()
  1199. # Ensure this matches the Projucer implementation
  1200. get_target_property(company_website ${target} JUCE_COMPANY_WEBSITE)
  1201. get_target_property(plugin_name ${target} JUCE_PLUGIN_NAME)
  1202. string(MAKE_C_IDENTIFIER "${plugin_name}" plugin_name_sanitised)
  1203. _juce_set_property_if_not_set(${target} LV2URI "${company_website}/plugins/${plugin_name_sanitised}")
  1204. # ARA configuration
  1205. # Analysis types
  1206. set(ara_analysis_type_strings
  1207. kARAContentTypeNotes
  1208. kARAContentTypeTempoEntries
  1209. kARAContentTypeBarSignatures
  1210. kARAContentTypeStaticTuning
  1211. kARAContentTypeKeySignatures
  1212. kARAContentTypeSheetChords)
  1213. get_target_property(actual_ara_analysis_types ${target} JUCE_ARA_ANALYSIS_TYPES)
  1214. set(ara_analysis_types_int "")
  1215. foreach(category_string IN LISTS actual_ara_analysis_types)
  1216. list(FIND ara_analysis_type_strings ${category_string} ara_index)
  1217. if(ara_index GREATER_EQUAL 0)
  1218. set(ara_analysis_types_bit "1 << ${ara_index}")
  1219. if(ara_analysis_types_int STREQUAL "")
  1220. set(ara_analysis_types_int 0)
  1221. endif()
  1222. math(EXPR ara_analysis_types_int "${ara_analysis_types_int} | (${ara_analysis_types_bit})")
  1223. endif()
  1224. endforeach()
  1225. if(NOT ara_analysis_types_int STREQUAL "")
  1226. set_target_properties(${target} PROPERTIES JUCE_ARA_ANALYSIS_TYPES ${ara_analysis_types_int})
  1227. endif()
  1228. _juce_set_property_if_not_set(${target} ARA_ANALYSIS_TYPES 0)
  1229. # Transformation flags
  1230. set(ara_transformation_flags_strings
  1231. kARAPlaybackTransformationNoChanges
  1232. kARAPlaybackTransformationTimestretch
  1233. kARAPlaybackTransformationTimestretchReflectingTempo
  1234. kARAPlaybackTransformationContentBasedFadeAtTail
  1235. kARAPlaybackTransformationContentBasedFadeAtHead)
  1236. set(default_ara_transformation_flags kARAPlaybackTransformationNoChanges)
  1237. _juce_set_property_if_not_set(${target} ARA_TRANSFORMATION_FLAGS ${default_ara_transformation_flags})
  1238. get_target_property(actual_ara_transformation_flags ${target} JUCE_ARA_TRANSFORMATION_FLAGS)
  1239. set(ara_transformation_flags_int "")
  1240. foreach(transformation_string IN LISTS actual_ara_transformation_flags)
  1241. list(FIND ara_transformation_flags_strings ${transformation_string} ara_transformation_index)
  1242. if(ara_transformation_index GREATER_EQUAL 0)
  1243. if(ara_transformation_index EQUAL 0)
  1244. set(ara_transformation_bit 0)
  1245. else()
  1246. set(ara_transformation_bit "1 << (${ara_transformation_index} - 1)")
  1247. endif()
  1248. if(ara_transformation_flags_int STREQUAL "")
  1249. set(ara_transformation_flags_int 0)
  1250. endif()
  1251. math(EXPR ara_transformation_flags_int "${ara_transformation_flags_int} | (${ara_transformation_bit})")
  1252. endif()
  1253. endforeach()
  1254. if(NOT ara_transformation_flags_int STREQUAL "")
  1255. set_target_properties(${target} PROPERTIES JUCE_ARA_TRANSFORMATION_FLAGS ${ara_transformation_flags_int})
  1256. endif()
  1257. _juce_set_property_if_not_set(${target} IS_ARA_EFFECT FALSE)
  1258. get_target_property(final_bundle_id ${target} JUCE_BUNDLE_ID)
  1259. _juce_set_property_if_not_set(${target} ARA_FACTORY_ID "\"${final_bundle_id}.arafactory.${final_version}\"")
  1260. _juce_set_property_if_not_set(${target} ARA_DOCUMENT_ARCHIVE_ID "\"${final_bundle_id}.aradocumentarchive.1\"")
  1261. _juce_set_property_if_not_set(${target} ARA_COMPATIBLE_ARCHIVE_IDS "\"\"")
  1262. endfunction()
  1263. # ==================================================================================================
  1264. function(_juce_initialise_target target)
  1265. set(one_value_args
  1266. VERSION
  1267. BUILD_VERSION
  1268. PRODUCT_NAME
  1269. PLIST_TO_MERGE
  1270. BUNDLE_ID
  1271. MICROPHONE_PERMISSION_ENABLED
  1272. MICROPHONE_PERMISSION_TEXT
  1273. CAMERA_PERMISSION_ENABLED
  1274. CAMERA_PERMISSION_TEXT
  1275. SEND_APPLE_EVENTS_PERMISSION_ENABLED
  1276. SEND_APPLE_EVENTS_PERMISSION_TEXT
  1277. BLUETOOTH_PERMISSION_ENABLED
  1278. BLUETOOTH_PERMISSION_TEXT
  1279. FILE_SHARING_ENABLED # iOS only
  1280. DOCUMENT_BROWSER_ENABLED # iOS only
  1281. LAUNCH_STORYBOARD_FILE # iOS only
  1282. APP_GROUPS_ENABLED # iOS only
  1283. ICLOUD_PERMISSIONS_ENABLED # iOS only
  1284. STATUS_BAR_HIDDEN # iOS only
  1285. BACKGROUND_AUDIO_ENABLED # iOS only
  1286. BACKGROUND_BLE_ENABLED # iOS only
  1287. CUSTOM_XCASSETS_FOLDER # iOS only
  1288. TARGETED_DEVICE_FAMILY # iOS only
  1289. REQUIRES_FULL_SCREEN # iOS only
  1290. ICON_BIG
  1291. ICON_SMALL
  1292. COMPANY_COPYRIGHT
  1293. COMPANY_NAME
  1294. COMPANY_WEBSITE
  1295. COMPANY_EMAIL
  1296. NEEDS_CURL # Set this true if you want to link curl on Linux
  1297. NEEDS_WEB_BROWSER # Set this true if you want to link webkit on Linux
  1298. NEEDS_STORE_KIT # Set this true if you want in-app-purchases on Mac
  1299. PUSH_NOTIFICATIONS_ENABLED
  1300. NETWORK_MULTICAST_ENABLED
  1301. HARDENED_RUNTIME_ENABLED
  1302. APP_SANDBOX_ENABLED
  1303. APP_SANDBOX_INHERIT
  1304. PLUGIN_NAME
  1305. PLUGIN_MANUFACTURER_CODE
  1306. PLUGIN_CODE
  1307. DESCRIPTION
  1308. IS_SYNTH
  1309. NEEDS_MIDI_INPUT
  1310. NEEDS_MIDI_OUTPUT
  1311. IS_MIDI_EFFECT
  1312. EDITOR_WANTS_KEYBOARD_FOCUS
  1313. DISABLE_AAX_BYPASS
  1314. DISABLE_AAX_MULTI_MONO
  1315. AAX_IDENTIFIER
  1316. VST_NUM_MIDI_INS
  1317. VST_NUM_MIDI_OUTS
  1318. VST2_CATEGORY
  1319. AU_MAIN_TYPE
  1320. AU_EXPORT_PREFIX
  1321. AU_SANDBOX_SAFE
  1322. SUPPRESS_AU_PLIST_RESOURCE_USAGE
  1323. PLUGINHOST_AU # Set this true if you want to host AU plugins
  1324. USE_LEGACY_COMPATIBILITY_PLUGIN_CODE
  1325. LV2URI
  1326. IS_ARA_EFFECT
  1327. ARA_FACTORY_ID
  1328. ARA_DOCUMENT_ARCHIVE_ID
  1329. VST_COPY_DIR
  1330. VST3_COPY_DIR
  1331. AAX_COPY_DIR
  1332. AU_COPY_DIR
  1333. UNITY_COPY_DIR
  1334. COPY_PLUGIN_AFTER_BUILD)
  1335. set(multi_value_args
  1336. FORMATS
  1337. VST3_CATEGORIES
  1338. HARDENED_RUNTIME_OPTIONS
  1339. APP_SANDBOX_OPTIONS
  1340. APP_SANDBOX_FILE_ACCESS_HOME_RO
  1341. APP_SANDBOX_FILE_ACCESS_HOME_RW
  1342. APP_SANDBOX_FILE_ACCESS_ABS_RO
  1343. APP_SANDBOX_FILE_ACCESS_ABS_RW
  1344. DOCUMENT_EXTENSIONS
  1345. AAX_CATEGORY
  1346. IPHONE_SCREEN_ORIENTATIONS # iOS only
  1347. IPAD_SCREEN_ORIENTATIONS # iOS only
  1348. APP_GROUP_IDS # iOS only
  1349. ARA_COMPATIBLE_ARCHIVE_IDS
  1350. ARA_ANALYSIS_TYPES
  1351. ARA_TRANSFORMATION_FLAGS)
  1352. cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN})
  1353. set(base_folder "${CMAKE_CURRENT_BINARY_DIR}/${target}_artefacts")
  1354. set(products_folder "${base_folder}/$<CONFIG>")
  1355. set(juce_library_code "${base_folder}/JuceLibraryCode")
  1356. set_target_properties(${target} PROPERTIES JUCE_GENERATED_SOURCES_DIRECTORY "${juce_library_code}")
  1357. set_target_properties(${target} PROPERTIES
  1358. ARCHIVE_OUTPUT_DIRECTORY "${products_folder}"
  1359. LIBRARY_OUTPUT_DIRECTORY "${products_folder}"
  1360. RUNTIME_OUTPUT_DIRECTORY "${products_folder}")
  1361. if(JUCE_ARG_ICON_BIG)
  1362. _juce_make_absolute_and_check(JUCE_ARG_ICON_BIG)
  1363. endif()
  1364. if(JUCE_ARG_ICON_SMALL)
  1365. _juce_make_absolute_and_check(JUCE_ARG_ICON_SMALL)
  1366. endif()
  1367. set(inherited_properties
  1368. COMPANY_NAME
  1369. COMPANY_WEBSITE
  1370. COMPANY_EMAIL
  1371. COMPANY_COPYRIGHT
  1372. VST_COPY_DIR
  1373. VST3_COPY_DIR
  1374. AU_COPY_DIR
  1375. AAX_COPY_DIR
  1376. UNITY_COPY_DIR
  1377. COPY_PLUGIN_AFTER_BUILD)
  1378. # Overwrite any properties that might be inherited
  1379. foreach(prop_string IN LISTS inherited_properties)
  1380. if(NOT ${JUCE_ARG_${prop_string}} STREQUAL "")
  1381. set_target_properties(${target} PROPERTIES JUCE_${prop_string} "${JUCE_ARG_${prop_string}}")
  1382. endif()
  1383. endforeach()
  1384. # Add each of the function arguments as target properties, so that it's easier to
  1385. # extract them in other functions
  1386. foreach(arg_string IN LISTS one_value_args multi_value_args)
  1387. _juce_set_property_if_not_set(${target} ${arg_string} "${JUCE_ARG_${arg_string}}")
  1388. endforeach()
  1389. _juce_set_fallback_properties(${target})
  1390. target_include_directories(${target} PRIVATE
  1391. $<TARGET_PROPERTY:${target},JUCE_GENERATED_SOURCES_DIRECTORY>)
  1392. target_link_libraries(${target} PUBLIC $<$<TARGET_EXISTS:juce_vst2_sdk>:juce_vst2_sdk>)
  1393. get_target_property(is_pluginhost_au ${target} JUCE_PLUGINHOST_AU)
  1394. if(is_pluginhost_au)
  1395. target_compile_definitions(${target} PUBLIC JUCE_PLUGINHOST_AU=1)
  1396. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
  1397. _juce_link_frameworks("${target}" PRIVATE CoreAudioKit)
  1398. endif()
  1399. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  1400. _juce_link_frameworks("${target}" PRIVATE AudioUnit)
  1401. endif()
  1402. endif()
  1403. _juce_write_generate_time_info(${target})
  1404. _juce_link_optional_libraries(${target})
  1405. _juce_fixup_module_source_groups()
  1406. endfunction()
  1407. # ==================================================================================================
  1408. function(juce_add_console_app target)
  1409. add_executable(${target})
  1410. target_compile_definitions(${target} PRIVATE JUCE_STANDALONE_APPLICATION=1)
  1411. if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  1412. target_compile_definitions(${target} PRIVATE _CONSOLE=1)
  1413. endif()
  1414. _juce_initialise_target(${target} ${ARGN})
  1415. endfunction()
  1416. function(juce_add_gui_app target)
  1417. if(CMAKE_SYSTEM_NAME STREQUAL "Android")
  1418. add_library(${target} SHARED)
  1419. else()
  1420. add_executable(${target})
  1421. endif()
  1422. target_compile_definitions(${target} PRIVATE JUCE_STANDALONE_APPLICATION=1)
  1423. _juce_initialise_target(${target} ${ARGN})
  1424. _juce_set_output_name(${target} $<TARGET_PROPERTY:${target},JUCE_PRODUCT_NAME>)
  1425. set_target_properties(${target} PROPERTIES JUCE_TARGET_KIND_STRING "App")
  1426. _juce_configure_bundle(${target} ${target})
  1427. _juce_configure_app_bundle(${target} ${target})
  1428. endfunction()
  1429. function(juce_add_plugin target)
  1430. add_library(${target} STATIC)
  1431. set_target_properties(${target} PROPERTIES JUCE_IS_PLUGIN TRUE)
  1432. _juce_initialise_target(${target} ${ARGN})
  1433. _juce_configure_plugin_targets(${target})
  1434. endfunction()
  1435. # ==================================================================================================
  1436. function(_juce_target_args_from_plugin_characteristics out_var)
  1437. set(pairs
  1438. "pluginIsSynth\;IS_SYNTH"
  1439. "pluginWantsMidiIn\;NEEDS_MIDI_INPUT"
  1440. "pluginProducesMidiOut\;NEEDS_MIDI_OUTPUT"
  1441. "pluginIsMidiEffectPlugin\;IS_MIDI_EFFECT"
  1442. "pluginEditorRequiresKeys\;EDITOR_WANTS_KEYBOARD_FOCUS")
  1443. set(result)
  1444. foreach(pair IN LISTS pairs)
  1445. list(GET pair 0 old_key)
  1446. if("${old_key}" IN_LIST ARGN)
  1447. list(GET pair 1 new_key)
  1448. list(APPEND result ${new_key} TRUE)
  1449. endif()
  1450. endforeach()
  1451. set(${out_var} ${result} PARENT_SCOPE)
  1452. endfunction()
  1453. # ==================================================================================================
  1454. function(_juce_get_pip_targets pip out_var)
  1455. set(test_targets "${pip}")
  1456. _juce_get_all_plugin_kinds(plugin_kinds)
  1457. foreach(plugin_kind IN LISTS plugin_kinds)
  1458. list(APPEND test_targets "${JUCE_PIP_NAME}_${plugin_kind}")
  1459. endforeach()
  1460. set(${out_var} ${test_targets} PARENT_SCOPE)
  1461. endfunction()
  1462. function(juce_add_pip header)
  1463. _juce_make_absolute(header)
  1464. _juce_extract_metadata_block(JUCE_PIP_METADATA "${header}" metadata_dict)
  1465. _juce_get_metadata("${metadata_dict}" name JUCE_PIP_NAME)
  1466. if(NOT JUCE_PIP_NAME)
  1467. message(FATAL_ERROR "Error in '${header}': PIP headers must declare a `name` field")
  1468. endif()
  1469. string(MAKE_C_IDENTIFIER "${JUCE_PIP_NAME}" pip_name_sanitised)
  1470. if(NOT JUCE_PIP_NAME STREQUAL pip_name_sanitised)
  1471. message(FATAL_ERROR "Error in '${header}': PIP `name` value '${JUCE_PIP_NAME}' must be a valid C identifier")
  1472. endif()
  1473. if(TARGET "${JUCE_PIP_NAME}")
  1474. # We already added a target with this name, let's try using the filename instead
  1475. get_filename_component(JUCE_PIP_NAME "${header}" NAME_WE)
  1476. endif()
  1477. if(TARGET "${JUCE_PIP_NAME}")
  1478. message(FATAL_ERROR "Error in '${header}': Could not create a unique target name for PIP ${header}")
  1479. endif()
  1480. _juce_get_metadata("${metadata_dict}" type pip_kind)
  1481. if(NOT pip_kind)
  1482. message(FATAL_ERROR "Error in '${header}': PIP headers must declare a `type` field")
  1483. endif()
  1484. _juce_get_metadata("${metadata_dict}" pluginCharacteristics pip_charateristics)
  1485. _juce_target_args_from_plugin_characteristics(extra_target_args ${pip_charateristics})
  1486. list(APPEND extra_target_args
  1487. NEEDS_CURL TRUE
  1488. NEEDS_WEB_BROWSER TRUE)
  1489. _juce_get_metadata("${metadata_dict}" moduleFlags pip_moduleflags)
  1490. if("JUCE_IN_APP_PURCHASES=1" IN_LIST pip_moduleflags)
  1491. list(APPEND extra_target_args
  1492. BUNDLE_ID "com.rmsl.juceInAppPurchaseSample"
  1493. NEEDS_STORE_KIT TRUE)
  1494. endif()
  1495. if("JUCE_PLUGINHOST_AU=1" IN_LIST pip_moduleflags)
  1496. list(APPEND extra_target_args PLUGINHOST_AU TRUE)
  1497. endif()
  1498. if(pip_kind STREQUAL "AudioProcessor")
  1499. _juce_get_metadata("${metadata_dict}" documentControllerClass JUCE_PIP_DOCUMENTCONTROLLER_CLASS)
  1500. if(JUCE_PIP_DOCUMENTCONTROLLER_CLASS)
  1501. if(NOT TARGET juce_ara_sdk)
  1502. message(WARNING
  1503. "${header} specifies a documentControllerClass, but the ARA SDK could not be located. "
  1504. "Use juce_set_ara_sdk_path to specify the ARA SDK location. "
  1505. "This PIP will not be configured.")
  1506. endif()
  1507. set(source_main "${JUCE_CMAKE_UTILS_DIR}/PIPAudioProcessorWithARA.cpp.in")
  1508. juce_add_plugin(${JUCE_PIP_NAME}
  1509. FORMATS AU VST3
  1510. IS_ARA_EFFECT TRUE)
  1511. else()
  1512. set(source_main "${JUCE_CMAKE_UTILS_DIR}/PIPAudioProcessor.cpp.in")
  1513. # We add AAX/VST2 targets too, if the user has set up those SDKs
  1514. set(extra_formats)
  1515. if(TARGET juce_aax_sdk)
  1516. list(APPEND extra_formats AAX)
  1517. endif()
  1518. if(TARGET juce_vst2_sdk)
  1519. list(APPEND extra_formats VST)
  1520. endif()
  1521. # Standalone plugins might want to access the mic
  1522. list(APPEND extra_target_args MICROPHONE_PERMISSION_ENABLED TRUE)
  1523. juce_add_plugin(${JUCE_PIP_NAME}
  1524. FORMATS AU AUv3 LV2 Standalone Unity VST3 ${extra_formats}
  1525. ${extra_target_args})
  1526. endif()
  1527. elseif(pip_kind STREQUAL "Component")
  1528. set(source_main "${JUCE_CMAKE_UTILS_DIR}/PIPComponent.cpp.in")
  1529. juce_add_gui_app(${JUCE_PIP_NAME} ${extra_target_args})
  1530. elseif(pip_kind STREQUAL "Console")
  1531. set(source_main "${JUCE_CMAKE_UTILS_DIR}/PIPConsole.cpp.in")
  1532. juce_add_console_app(${JUCE_PIP_NAME} ${extra_target_args})
  1533. else()
  1534. message(FATAL_ERROR "Error in '${header}': PIP kind must be either AudioProcessor, Component, or Console")
  1535. endif()
  1536. if(NOT ARGV1 STREQUAL "")
  1537. set("${ARGV1}" "${JUCE_PIP_NAME}" PARENT_SCOPE)
  1538. endif()
  1539. # Generate Main.cpp
  1540. _juce_get_metadata("${metadata_dict}" mainClass JUCE_PIP_MAIN_CLASS)
  1541. get_target_property(juce_library_code ${JUCE_PIP_NAME} JUCE_GENERATED_SOURCES_DIRECTORY)
  1542. set(pip_main "${juce_library_code}/Main.cpp")
  1543. set(JUCE_PIP_HEADER "${header}")
  1544. configure_file(${source_main} ${pip_main})
  1545. target_sources(${JUCE_PIP_NAME} PRIVATE ${pip_main})
  1546. _juce_get_metadata("${metadata_dict}" dependencies pip_dependencies)
  1547. juce_generate_juce_header(${JUCE_PIP_NAME})
  1548. foreach(module IN LISTS pip_dependencies)
  1549. if(module STREQUAL "")
  1550. continue()
  1551. endif()
  1552. set(discovered_module)
  1553. if(TARGET "${module}")
  1554. set(discovered_module "${module}")
  1555. else()
  1556. message(FATAL_ERROR "Error in '${header}': No such module: ${module}")
  1557. endif()
  1558. target_link_libraries(${JUCE_PIP_NAME} PRIVATE ${discovered_module})
  1559. endforeach()
  1560. target_compile_definitions(${JUCE_PIP_NAME}
  1561. PRIVATE ${pip_moduleflags}
  1562. PUBLIC
  1563. JUCE_VST3_CAN_REPLACE_VST2=0)
  1564. _juce_get_pip_targets(${JUCE_PIP_NAME} pip_targets)
  1565. # This keeps the PIPs slightly better organised in the JUCE megaproject
  1566. if((DEFINED JUCE_SOURCE_DIR) AND (header MATCHES "^${JUCE_SOURCE_DIR}"))
  1567. file(RELATIVE_PATH folder "${JUCE_SOURCE_DIR}" "${header}")
  1568. get_filename_component(folder_parent "${folder}" DIRECTORY)
  1569. foreach(target_name IN ITEMS ${pip_targets} ${JUCE_PIP_NAME}_All)
  1570. if(TARGET "${target_name}")
  1571. set_target_properties("${target_name}" PROPERTIES
  1572. FOLDER "${folder_parent}/${JUCE_PIP_NAME}")
  1573. endif()
  1574. endforeach()
  1575. endif()
  1576. # We're building JUCE itself
  1577. if(DEFINED JUCE_SOURCE_DIR)
  1578. # PIPs need to know about the resources folder
  1579. target_compile_definitions(${JUCE_PIP_NAME} PRIVATE
  1580. PIP_JUCE_EXAMPLES_DIRECTORY_STRING="${JUCE_SOURCE_DIR}/examples")
  1581. get_filename_component(pip_parent_path "${header}" DIRECTORY)
  1582. target_include_directories(${JUCE_PIP_NAME} PRIVATE "${pip_parent_path}")
  1583. if((CMAKE_SYSTEM_NAME STREQUAL "iOS") AND (header MATCHES "^${JUCE_SOURCE_DIR}"))
  1584. foreach(target_name IN LISTS pip_targets)
  1585. if(TARGET "${target_name}")
  1586. juce_add_bundle_resources_directory("${target_name}" "${JUCE_SOURCE_DIR}/examples/Assets")
  1587. endif()
  1588. endforeach()
  1589. endif()
  1590. endif()
  1591. endfunction()
  1592. # ==================================================================================================
  1593. function(juce_set_aax_sdk_path path)
  1594. if(TARGET juce_aax_sdk)
  1595. message(FATAL_ERROR "juce_set_aax_sdk_path should only be called once")
  1596. endif()
  1597. _juce_make_absolute(path)
  1598. if((NOT EXISTS "${path}")
  1599. OR (NOT EXISTS "${path}/Interfaces")
  1600. OR (NOT EXISTS "${path}/Interfaces/ACF"))
  1601. message(FATAL_ERROR "Could not find AAX SDK at the specified path: ${path}")
  1602. endif()
  1603. if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  1604. add_library(juce_aax_sdk STATIC IMPORTED GLOBAL)
  1605. set_target_properties(juce_aax_sdk PROPERTIES
  1606. IMPORTED_LOCATION_DEBUG "${path}/Libs/Debug/libAAXLibrary_libcpp.a"
  1607. IMPORTED_LOCATION "${path}/Libs/Release/libAAXLibrary_libcpp.a")
  1608. elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  1609. add_library(juce_aax_sdk INTERFACE IMPORTED GLOBAL)
  1610. else()
  1611. return()
  1612. endif()
  1613. target_include_directories(juce_aax_sdk INTERFACE
  1614. "${path}"
  1615. "${path}/Interfaces"
  1616. "${path}/Interfaces/ACF")
  1617. target_compile_definitions(juce_aax_sdk INTERFACE JucePlugin_AAXLibs_path="${path}/Libs")
  1618. set_target_properties(juce_aax_sdk PROPERTIES INTERFACE_JUCE_AAX_DEFAULT_ICON "${path}/Utilities/PlugIn.ico")
  1619. endfunction()
  1620. function(juce_set_vst2_sdk_path path)
  1621. if(TARGET juce_vst2_sdk)
  1622. message(FATAL_ERROR "juce_set_vst2_sdk_path should only be called once")
  1623. endif()
  1624. _juce_make_absolute(path)
  1625. if(NOT EXISTS "${path}")
  1626. message(FATAL_ERROR "Could not find VST2 SDK at the specified path: ${path}")
  1627. endif()
  1628. add_library(juce_vst2_sdk INTERFACE IMPORTED GLOBAL)
  1629. # This is a bit of a hack, but we really need the VST2 paths to always follow the VST3 paths.
  1630. target_include_directories(juce_vst2_sdk INTERFACE
  1631. $<TARGET_PROPERTY:juce::juce_vst3_headers,INTERFACE_INCLUDE_DIRECTORIES>
  1632. "${path}")
  1633. endfunction()
  1634. function(juce_set_vst3_sdk_path path)
  1635. if(TARGET juce_vst3_sdk)
  1636. message(FATAL_ERROR "juce_set_vst3_sdk_path should only be called once")
  1637. endif()
  1638. _juce_make_absolute(path)
  1639. if(NOT EXISTS "${path}")
  1640. message(FATAL_ERROR "Could not find VST3 SDK at the specified path: ${path}")
  1641. endif()
  1642. add_library(juce_vst3_sdk INTERFACE IMPORTED GLOBAL)
  1643. target_include_directories(juce_vst3_sdk INTERFACE "${path}")
  1644. endfunction()
  1645. function(juce_set_ara_sdk_path path)
  1646. if(TARGET juce_ara_sdk)
  1647. message(FATAL_ERROR "juce_set_ara_sdk_path should only be called once")
  1648. endif()
  1649. _juce_make_absolute(path)
  1650. if(NOT EXISTS "${path}")
  1651. message(FATAL_ERROR "Could not find ARA SDK at the specified path: ${path}")
  1652. endif()
  1653. add_library(juce_ara_sdk INTERFACE IMPORTED GLOBAL)
  1654. target_include_directories(juce_ara_sdk INTERFACE "${path}")
  1655. endfunction()
  1656. # ==================================================================================================
  1657. function(juce_disable_default_flags)
  1658. set(langs C CXX)
  1659. set(modes DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
  1660. foreach(lang IN LISTS langs)
  1661. foreach(mode IN LISTS modes)
  1662. list(FILTER CMAKE_${lang}_FLAGS_${mode} INCLUDE REGEX "[/-]M[TD]d?")
  1663. set(CMAKE_${lang}_FLAGS_${mode} "${CMAKE_${lang}_FLAGS_${mode}}" PARENT_SCOPE)
  1664. endforeach()
  1665. endforeach()
  1666. endfunction()