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.

2303 lines
92KB

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