diff --git a/CMakeLists.txt b/CMakeLists.txt index ed66a23005..958a9c131c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,14 +29,40 @@ endif() project(JUCE VERSION 6.0.8 LANGUAGES C CXX) +include(CMakeDependentOption) + set_property(GLOBAL PROPERTY USE_FOLDERS YES) set(JUCE_MODULES_DIR "${JUCE_SOURCE_DIR}/modules" CACHE INTERNAL "The path to JUCE modules") -include(extras/Build/CMake/JUCEUtils.cmake) +# This option will disable most of the JUCE helper functions and tools. This option exists to +# facilitate existing CMake builds which handle things like bundle creation, icons, plists, and +# binary data independently of JUCE. This option is not recommended - use at your own risk! -juce_disable_default_flags() +option(JUCE_MODULES_ONLY "Only configure the JUCE modules" OFF) + +include(extras/Build/CMake/JUCEModuleSupport.cmake) + +# This option controls whether dummy targets are added to the build, where these targets contain all +# of the source files for each JUCE module. If you're planning to use an IDE and want to be able to +# browse all of JUCE's source files, this may be useful. However, it will increase the size of +# generated IDE projects and might slow down configuration a bit. If you enable this, you should +# probably also add `set_property(GLOBAL PROPERTY USE_FOLDERS YES)` to your top level CMakeLists, +# otherwise the module sources will be added directly to the top level of the project, instead of in +# a nice 'Modules' subfolder. + +cmake_dependent_option(JUCE_ENABLE_MODULE_SOURCE_GROUPS + "Show all module sources in IDE projects" OFF + "JUCE_MODULES_ONLY" OFF) + +add_subdirectory(modules) + +if(JUCE_MODULES_ONLY) + return() +endif() + +include(extras/Build/CMake/JUCEUtils.cmake) set_directory_properties(PROPERTIES JUCE_COMPANY_NAME "JUCE" @@ -50,17 +76,8 @@ set_property(GLOBAL PROPERTY JUCE_COPY_PLUGIN_AFTER_BUILD ${JUCE_COPY_PLUGIN_AFT set(CMAKE_CXX_EXTENSIONS FALSE) -# This option controls whether dummy targets are added to the build, where these targets contain all -# of the source files for each JUCE module. If you're planning to use an IDE and want to be able to -# browse all of JUCE's source files, this may be useful. However, it will increase the size of -# generated IDE projects and might slow down configuration a bit. If you enable this, you should -# probably also add `set_property(GLOBAL PROPERTY USE_FOLDERS YES)` to your top level CMakeLists, -# otherwise the module sources will be added directly to the top level of the project, instead of in -# a nice 'Modules' subfolder. +juce_disable_default_flags() -option(JUCE_ENABLE_MODULE_SOURCE_GROUPS "Show all module sources in IDE projects" OFF) - -add_subdirectory(modules) add_subdirectory(extras/Build) # If you want to build the JUCE examples with VST2/AAX support, you'll need to make the VST2/AAX diff --git a/extras/Build/CMake/JUCECheckAtomic.cmake b/extras/Build/CMake/JUCECheckAtomic.cmake index 4ad7672042..e53f952708 100644 --- a/extras/Build/CMake/JUCECheckAtomic.cmake +++ b/extras/Build/CMake/JUCECheckAtomic.cmake @@ -81,3 +81,6 @@ function(_juce_create_atomic_target target_name) file(REMOVE "${test_file_name}") file(REMOVE_RECURSE "${test_bindir}") endfunction() + +_juce_create_atomic_target(juce_atomic_wrapper) + diff --git a/extras/Build/CMake/JUCEModuleSupport.cmake b/extras/Build/CMake/JUCEModuleSupport.cmake new file mode 100644 index 0000000000..1e09461eb6 --- /dev/null +++ b/extras/Build/CMake/JUCEModuleSupport.cmake @@ -0,0 +1,532 @@ +# ============================================================================== +# +# This file is part of the JUCE library. +# Copyright (c) 2020 - Raw Material Software Limited +# +# JUCE is an open source library subject to commercial or open-source +# licensing. +# +# By using JUCE, you agree to the terms of both the JUCE 6 End-User License +# Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). +# +# End User License Agreement: www.juce.com/juce-6-licence +# Privacy Policy: www.juce.com/juce-privacy-policy +# +# Or: You may also use this code under the terms of the GPL v3 (see +# www.gnu.org/licenses). +# +# JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER +# EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE +# DISCLAIMED. +# +# ============================================================================== + +# ================================================================================================== +# JUCE Modules Support Helper Functions +# +# In this file, functions intended for use by end-users have the prefix `juce_`. +# Functions beginning with an underscore should be considered private and susceptible to +# change, so don't call them directly. +# +# See the readme at `docs/CMake API.md` for more information about CMake usage, +# including documentation of the public functions in this file. +# ================================================================================================== + +include_guard(GLOBAL) +cmake_minimum_required(VERSION 3.12) + +# ================================================================================================== + +function(_juce_add_interface_library target) + add_library(${target} INTERFACE) + target_sources(${target} INTERFACE ${ARGN}) +endfunction() + +# ================================================================================================== + +set(JUCE_CMAKE_UTILS_DIR ${CMAKE_CURRENT_LIST_DIR} + CACHE INTERNAL "The path to the folder holding this file and other resources") + +include("${JUCE_CMAKE_UTILS_DIR}/JUCEHelperTargets.cmake") +include("${JUCE_CMAKE_UTILS_DIR}/JUCECheckAtomic.cmake") + +# ================================================================================================== + +function(_juce_add_standard_defs juce_target) + target_compile_definitions(${juce_target} INTERFACE + JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 + $,DEBUG=1 _DEBUG=1,NDEBUG=1 _NDEBUG=1> + $<$:JUCE_ANDROID=1>) +endfunction() + +# ================================================================================================== + +macro(_juce_make_absolute path) + if(NOT IS_ABSOLUTE "${${path}}") + get_filename_component("${path}" "${${path}}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}") + endif() +endmacro() + +macro(_juce_make_absolute_and_check path) + _juce_make_absolute("${path}") + + if(NOT EXISTS "${${path}}") + message(FATAL_ERROR "No file at path ${${path}}") + endif() +endmacro() + +# ================================================================================================== + +# This creates an imported interface library with a random name, and then adds +# the fields from a JUCE module header to the target as INTERFACE_ properties. +# We can extract properties later using `_juce_get_metadata`. +# This way, the interface library ends up behaving a bit like a dictionary, +# and we don't have to parse the module header from scratch every time we +# want to find a specific key. +function(_juce_extract_metadata_block delim_str file_with_block out_dict) + string(RANDOM LENGTH 16 random_string) + set(target_name "${random_string}_dict") + set(${out_dict} "${target_name}" PARENT_SCOPE) + add_library(${target_name} INTERFACE IMPORTED) + + if(NOT EXISTS ${file_with_block}) + message(FATAL_ERROR "Unable to find file ${file_with_block}") + endif() + + file(STRINGS ${file_with_block} module_header_contents) + + set(last_written_key) + set(append NO) + + foreach(line IN LISTS module_header_contents) + if(NOT append) + if(line MATCHES " *BEGIN_${delim_str} *") + set(append YES) + endif() + + continue() + endif() + + if(append AND (line MATCHES " *END_${delim_str} *")) + break() + endif() + + if(line MATCHES "^ *([a-zA-Z]+):") + set(last_written_key "${CMAKE_MATCH_1}") + endif() + + string(REGEX REPLACE "^ *${last_written_key}: *" "" line "${line}") + string(REGEX REPLACE "[ ,]+" ";" line "${line}") + + set_property(TARGET ${target_name} APPEND PROPERTY + "INTERFACE_JUCE_${last_written_key}" "${line}") + endforeach() +endfunction() + +# Fetches properties attached to a metadata target. +function(_juce_get_metadata target key out_var) + get_target_property(content "${target}" "INTERFACE_JUCE_${key}") + + if(NOT "${content}" STREQUAL "content-NOTFOUND") + set(${out_var} "${content}" PARENT_SCOPE) + endif() +endfunction() + +# ================================================================================================== + +function(_juce_should_build_module_source filename output_var) + get_filename_component(trimmed_name "${filename}" NAME_WE) + + set(result TRUE) + + set(pairs + "OSX\;Darwin" + "Windows\;Windows" + "Linux\;Linux" + "Android\;Android" + "iOS\;iOS") + + foreach(pair IN LISTS pairs) + list(GET pair 0 suffix) + list(GET pair 1 system_name) + + if((trimmed_name MATCHES "_${suffix}$") AND NOT (CMAKE_SYSTEM_NAME STREQUAL "${system_name}")) + set(result FALSE) + endif() + endforeach() + + set("${output_var}" "${result}" PARENT_SCOPE) +endfunction() + +function(_juce_module_sources module_path output_path built_sources other_sources) + get_filename_component(module_parent_path ${module_path} DIRECTORY) + get_filename_component(module_glob ${module_path} NAME) + + file(GLOB_RECURSE all_module_files + CONFIGURE_DEPENDS LIST_DIRECTORIES FALSE + RELATIVE "${module_parent_path}" + "${module_path}/*") + + set(base_path "${module_glob}/${module_glob}") + + set(module_cpp ${all_module_files}) + list(FILTER module_cpp INCLUDE REGEX "^${base_path}[^/]*\\.(c|cc|cpp|cxx|s|asm)$") + + if(APPLE) + set(module_mm ${all_module_files}) + list(FILTER module_mm INCLUDE REGEX "^${base_path}[^/]*\\.mm$") + + if(module_mm) + set(module_mm_replaced ${module_mm}) + list(TRANSFORM module_mm_replaced REPLACE "\\.mm$" ".cpp") + list(REMOVE_ITEM module_cpp ${module_mm_replaced}) + endif() + + set(module_apple_files ${all_module_files}) + list(FILTER module_apple_files INCLUDE REGEX "${base_path}[^/]*\\.(m|mm|metal|r|swift)$") + list(APPEND module_cpp ${module_apple_files}) + endif() + + set(headers ${all_module_files}) + + set(module_files_to_build) + + foreach(filename IN LISTS module_cpp) + _juce_should_build_module_source("${filename}" should_build_file) + + if(should_build_file) + list(APPEND module_files_to_build "${filename}") + endif() + endforeach() + + if(NOT "${module_files_to_build}" STREQUAL "") + list(REMOVE_ITEM headers ${module_files_to_build}) + endif() + + foreach(source_list IN ITEMS module_files_to_build headers) + list(TRANSFORM ${source_list} PREPEND "${output_path}/") + endforeach() + + set(${built_sources} ${module_files_to_build} PARENT_SCOPE) + set(${other_sources} ${headers} PARENT_SCOPE) +endfunction() + +# ================================================================================================== + +function(_juce_get_all_plugin_kinds out) + set(${out} AU AUv3 AAX Standalone Unity VST VST3 PARENT_SCOPE) +endfunction() + +function(_juce_get_platform_plugin_kinds out) + set(result Standalone) + + if(APPLE AND (CMAKE_GENERATOR STREQUAL "Xcode")) + list(APPEND result AUv3) + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + list(APPEND result AU) + endif() + + if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + list(APPEND result AAX Unity VST VST3) + endif() + + set(${out} ${result} PARENT_SCOPE) +endfunction() + +function(_juce_add_plugin_definitions target visibility) + _juce_get_all_plugin_kinds(options) + cmake_parse_arguments(JUCE_ARG "${options}" "" "" ${ARGN}) + + foreach(opt IN LISTS options) + set(flag_value 0) + + if(JUCE_ARG_${opt}) + set(flag_value 1) + endif() + + target_compile_definitions(${target} ${visibility} "JucePlugin_Build_${opt}=${flag_value}") + endforeach() +endfunction() + +# ================================================================================================== + +# Takes a target, a link visibility, and a variable-length list of framework +# names. On macOS, finds the requested frameworks using `find_library` and +# links them. On iOS, links directly with `-framework Name`. +function(_juce_link_frameworks target visibility) + foreach(framework IN LISTS ARGN) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + find_library("juce_found_${framework}" "${framework}" REQUIRED) + target_link_libraries("${target}" "${visibility}" "${juce_found_${framework}}") + elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") + # CoreServices is only available on iOS 12+, we must link it weakly on earlier platforms + if((framework STREQUAL "CoreServices") AND (CMAKE_OSX_DEPLOYMENT_TARGET LESS 12.0)) + set(framework_flags "-weak_framework ${framework}") + else() + set(framework_flags "-framework ${framework}") + endif() + + target_link_libraries("${target}" "${visibility}" "${framework_flags}") + endif() + endforeach() +endfunction() + +# ================================================================================================== + +function(_juce_add_plugin_wrapper_target format path out_path) + _juce_module_sources("${path}" "${out_path}" out_var headers) + list(FILTER out_var EXCLUDE REGEX "/juce_audio_plugin_client_utils.cpp$") + set(target_name juce_audio_plugin_client_${format}) + + _juce_add_interface_library("${target_name}" ${out_var}) + _juce_add_plugin_definitions("${target_name}" INTERFACE ${format}) + _juce_add_standard_defs("${target_name}") + + target_compile_features("${target_name}" INTERFACE cxx_std_14) + add_library("juce::${target_name}" ALIAS "${target_name}") + + if(format STREQUAL "AUv3") + _juce_link_frameworks("${target_name}" INTERFACE AVFoundation) + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + _juce_link_frameworks("${target_name}" INTERFACE AudioUnit) + endif() + elseif(format STREQUAL "AU") + _juce_link_frameworks("${target_name}" INTERFACE AudioUnit CoreAudioKit) + endif() +endfunction() + +# ================================================================================================== + +function(_juce_link_libs_from_metadata module_name dict key) + _juce_get_metadata("${dict}" "${key}" libs) + + if(libs) + target_link_libraries(${module_name} INTERFACE ${libs}) + endif() +endfunction() + +# ================================================================================================== + +function(_juce_create_pkgconfig_target name) + if(TARGET juce::pkgconfig_${name}) + return() + endif() + + find_package(PkgConfig REQUIRED) + pkg_check_modules(${name} ${ARGN}) + + add_library(pkgconfig_${name} INTERFACE) + add_library(juce::pkgconfig_${name} ALIAS pkgconfig_${name}) + install(TARGETS pkgconfig_${name} EXPORT JUCE) + + set(pairs + "INCLUDE_DIRECTORIES\;INCLUDE_DIRS" + "LINK_LIBRARIES\;LINK_LIBRARIES" + "LINK_OPTIONS\;LDFLAGS_OTHER" + "COMPILE_OPTIONS\;CFLAGS_OTHER") + + foreach(pair IN LISTS pairs) + list(GET pair 0 key) + list(GET pair 1 value) + + if(${name}_${value}) + set_target_properties(pkgconfig_${name} PROPERTIES INTERFACE_${key} "${${name}_${value}}") + endif() + endforeach() +endfunction() + +# ================================================================================================== + +function(juce_add_module module_path) + set(one_value_args INSTALL_PATH ALIAS_NAMESPACE) + cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "" ${ARGN}) + + _juce_make_absolute(module_path) + + get_filename_component(module_name ${module_path} NAME) + get_filename_component(module_parent_path ${module_path} DIRECTORY) + + set(module_header_name "${module_name}.h") + + if(NOT EXISTS "${module_path}/${module_header_name}") + set(module_header_name "${module_header_name}pp") + endif() + + if(NOT EXISTS "${module_path}/${module_header_name}") + message(FATAL_ERROR "Could not locate module header for module '${module_path}'") + endif() + + set(base_path "${module_parent_path}") + + _juce_module_sources("${module_path}" "${base_path}" globbed_sources headers) + + if(${module_name} STREQUAL "juce_audio_plugin_client") + _juce_get_platform_plugin_kinds(plugin_kinds) + + foreach(kind IN LISTS plugin_kinds) + _juce_add_plugin_wrapper_target(${kind} "${module_path}" "${base_path}") + endforeach() + + set(utils_source + "${base_path}/${module_name}/juce_audio_plugin_client_utils.cpp") + add_library(juce_audio_plugin_client_utils INTERFACE) + target_sources(juce_audio_plugin_client_utils INTERFACE "${utils_source}") + + if(JUCE_ARG_ALIAS_NAMESPACE) + add_library(${JUCE_ARG_ALIAS_NAMESPACE}::juce_audio_plugin_client_utils + ALIAS juce_audio_plugin_client_utils) + endif() + + file(GLOB_RECURSE all_module_files + CONFIGURE_DEPENDS LIST_DIRECTORIES FALSE + RELATIVE "${module_parent_path}" + "${module_path}/*") + else() + list(APPEND all_module_sources ${globbed_sources}) + endif() + + _juce_add_interface_library(${module_name} ${all_module_sources}) + + set_property(GLOBAL APPEND PROPERTY _juce_module_names ${module_name}) + + set_target_properties(${module_name} PROPERTIES + INTERFACE_JUCE_MODULE_SOURCES "${globbed_sources}" + INTERFACE_JUCE_MODULE_HEADERS "${headers}" + INTERFACE_JUCE_MODULE_PATH "${base_path}") + + if(JUCE_ENABLE_MODULE_SOURCE_GROUPS) + target_sources(${module_name} INTERFACE ${headers}) + endif() + + if(${module_name} STREQUAL "juce_core") + _juce_add_standard_defs(${module_name}) + + target_link_libraries(juce_core INTERFACE juce::juce_atomic_wrapper) + + if(CMAKE_SYSTEM_NAME MATCHES ".*BSD") + target_link_libraries(juce_core INTERFACE execinfo) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") + target_sources(juce_core INTERFACE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c") + target_include_directories(juce_core INTERFACE "${ANDROID_NDK}/sources/android/cpufeatures") + target_link_libraries(juce_core INTERFACE android log) + endif() + endif() + + if(${module_name} STREQUAL "juce_audio_processors") + add_library(juce_vst3_headers INTERFACE) + + target_compile_definitions(juce_vst3_headers INTERFACE "$<$:JUCE_CUSTOM_VST3_SDK=1>") + + target_include_directories(juce_vst3_headers INTERFACE + "$<$:$>" + "$<$>:${base_path}/juce_audio_processors/format_types/VST3_SDK>") + + target_link_libraries(juce_audio_processors INTERFACE juce_vst3_headers) + + if(JUCE_ARG_ALIAS_NAMESPACE) + add_library(${JUCE_ARG_ALIAS_NAMESPACE}::juce_vst3_headers ALIAS juce_vst3_headers) + endif() + endif() + + target_include_directories(${module_name} INTERFACE ${base_path}) + + target_compile_definitions(${module_name} INTERFACE JUCE_MODULE_AVAILABLE_${module_name}=1) + + if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) + target_compile_definitions(${module_name} INTERFACE LINUX=1) + endif() + + _juce_extract_metadata_block(JUCE_MODULE_DECLARATION "${module_path}/${module_header_name}" metadata_dict) + + _juce_get_metadata("${metadata_dict}" minimumCppStandard module_cpp_standard) + + if(module_cpp_standard) + target_compile_features(${module_name} INTERFACE cxx_std_${module_cpp_standard}) + else() + target_compile_features(${module_name} INTERFACE cxx_std_11) + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + _juce_get_metadata("${metadata_dict}" OSXFrameworks module_osxframeworks) + + foreach(module_framework IN LISTS module_osxframeworks) + if(module_framework STREQUAL "") + continue() + endif() + + _juce_link_frameworks("${module_name}" INTERFACE "${module_framework}") + endforeach() + + _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" OSXLibs) + elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") + _juce_get_metadata("${metadata_dict}" iOSFrameworks module_iosframeworks) + + foreach(module_framework IN LISTS module_iosframeworks) + if(module_framework STREQUAL "") + continue() + endif() + + _juce_link_frameworks("${module_name}" INTERFACE "${module_framework}") + endforeach() + + _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" iOSLibs) + elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) + _juce_get_metadata("${metadata_dict}" linuxPackages module_linuxpackages) + + if(module_linuxpackages) + _juce_create_pkgconfig_target(${module_name}_LINUX_DEPS ${module_linuxpackages}) + target_link_libraries(${module_name} INTERFACE juce::pkgconfig_${module_name}_LINUX_DEPS) + endif() + + _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" linuxLibs) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) + if(module_name STREQUAL "juce_gui_basics") + target_compile_options(${module_name} INTERFACE /bigobj) + endif() + + _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" windowsLibs) + elseif(MSYS OR MINGW) + if(module_name STREQUAL "juce_gui_basics") + target_compile_options(${module_name} INTERFACE "-Wa,-mbig-obj") + endif() + + _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" mingwLibs) + endif() + endif() + + _juce_get_metadata("${metadata_dict}" dependencies module_dependencies) + target_link_libraries(${module_name} INTERFACE ${module_dependencies}) + + _juce_get_metadata("${metadata_dict}" searchpaths module_searchpaths) + + if(NOT module_searchpaths STREQUAL "") + foreach(module_searchpath IN LISTS module_searchpaths) + target_include_directories(${module_name} + INTERFACE "${module_path}/${module_searchpath}") + endforeach() + endif() + + if(JUCE_ARG_INSTALL_PATH) + install(DIRECTORY "${module_path}" DESTINATION "${JUCE_ARG_INSTALL_PATH}") + endif() + + if(JUCE_ARG_ALIAS_NAMESPACE) + add_library(${JUCE_ARG_ALIAS_NAMESPACE}::${module_name} ALIAS ${module_name}) + endif() +endfunction() + +function(juce_add_modules) + set(one_value_args INSTALL_PATH ALIAS_NAMESPACE) + cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "" ${ARGN}) + + foreach(path IN LISTS JUCE_ARG_UNPARSED_ARGUMENTS) + juce_add_module(${path} + INSTALL_PATH "${JUCE_ARG_INSTALL_PATH}" + ALIAS_NAMESPACE "${JUCE_ARG_ALIAS_NAMESPACE}") + endforeach() +endfunction() + diff --git a/extras/Build/CMake/JUCEUtils.cmake b/extras/Build/CMake/JUCEUtils.cmake index 2e4628096d..78c31120f4 100644 --- a/extras/Build/CMake/JUCEUtils.cmake +++ b/extras/Build/CMake/JUCEUtils.cmake @@ -22,7 +22,7 @@ # ============================================================================== # ================================================================================================== -# JUCE/CMake Compatibility Module +# JUCE Target Support Helper Functions # # In this file, functions intended for use by end-users have the prefix `juce_`. # Functions beginning with an underscore should be considered private and susceptible to @@ -82,51 +82,6 @@ set_property(GLOBAL PROPERTY JUCE_COPY_PLUGIN_AFTER_BUILD FALSE) # ================================================================================================== -function(_juce_add_interface_library target) - add_library(${target} INTERFACE) - target_sources(${target} INTERFACE ${ARGN}) -endfunction() - -# ================================================================================================== - -function(_juce_create_pkgconfig_target name) - if(TARGET juce::pkgconfig_${name}) - return() - endif() - - find_package(PkgConfig REQUIRED) - pkg_check_modules(${name} ${ARGN}) - - add_library(pkgconfig_${name} INTERFACE) - add_library(juce::pkgconfig_${name} ALIAS pkgconfig_${name}) - install(TARGETS pkgconfig_${name} EXPORT JUCE) - - set(pairs - "INCLUDE_DIRECTORIES\;INCLUDE_DIRS" - "LINK_LIBRARIES\;LINK_LIBRARIES" - "LINK_OPTIONS\;LDFLAGS_OTHER" - "COMPILE_OPTIONS\;CFLAGS_OTHER") - - foreach(pair IN LISTS pairs) - list(GET pair 0 key) - list(GET pair 1 value) - - if(${name}_${value}) - set_target_properties(pkgconfig_${name} PROPERTIES INTERFACE_${key} "${${name}_${value}}") - endif() - endforeach() -endfunction() - -# ================================================================================================== - -set(JUCE_CMAKE_UTILS_DIR ${CMAKE_CURRENT_LIST_DIR} - CACHE INTERNAL "The path to the folder holding this file and other resources") - -include("${JUCE_CMAKE_UTILS_DIR}/JUCEHelperTargets.cmake") -include("${JUCE_CMAKE_UTILS_DIR}/JUCECheckAtomic.cmake") - -_juce_create_atomic_target(juce_atomic_wrapper) - # Tries to discover the target platform architecture, which is necessary for # naming VST3 bundle folders correctly. function(_juce_find_linux_target_architecture result) @@ -187,31 +142,6 @@ _juce_set_default_properties() # ================================================================================================== -function(_juce_add_standard_defs juce_target) - target_compile_definitions(${juce_target} INTERFACE - JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 - $,DEBUG=1 _DEBUG=1,NDEBUG=1 _NDEBUG=1> - $<$:JUCE_ANDROID=1>) -endfunction() - -# ================================================================================================== - -macro(_juce_make_absolute path) - if(NOT IS_ABSOLUTE "${${path}}") - get_filename_component("${path}" "${${path}}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}") - endif() -endmacro() - -macro(_juce_make_absolute_and_check path) - _juce_make_absolute("${path}") - - if(NOT EXISTS "${${path}}") - message(FATAL_ERROR "No file at path ${${path}}") - endif() -endmacro() - -# ================================================================================================== - function(juce_add_bundle_resources_directory target folder) _juce_make_absolute(folder) @@ -233,181 +163,6 @@ endfunction() # ================================================================================================== -# This creates an imported interface library with a random name, and then adds -# the fields from a JUCE module header to the target as INTERFACE_ properties. -# We can extract properties later using `_juce_get_metadata`. -# This way, the interface library ends up behaving a bit like a dictionary, -# and we don't have to parse the module header from scratch every time we -# want to find a specific key. -function(_juce_extract_metadata_block delim_str file_with_block out_dict) - string(RANDOM LENGTH 16 random_string) - set(target_name "${random_string}_dict") - set(${out_dict} "${target_name}" PARENT_SCOPE) - add_library(${target_name} INTERFACE IMPORTED) - - if(NOT EXISTS ${file_with_block}) - message(FATAL_ERROR "Unable to find file ${file_with_block}") - endif() - - file(STRINGS ${file_with_block} module_header_contents) - - set(last_written_key) - set(append NO) - - foreach(line IN LISTS module_header_contents) - if(NOT append) - if(line MATCHES " *BEGIN_${delim_str} *") - set(append YES) - endif() - - continue() - endif() - - if(append AND (line MATCHES " *END_${delim_str} *")) - break() - endif() - - if(line MATCHES "^ *([a-zA-Z]+):") - set(last_written_key "${CMAKE_MATCH_1}") - endif() - - string(REGEX REPLACE "^ *${last_written_key}: *" "" line "${line}") - string(REGEX REPLACE "[ ,]+" ";" line "${line}") - - set_property(TARGET ${target_name} APPEND PROPERTY - "INTERFACE_JUCE_${last_written_key}" "${line}") - endforeach() -endfunction() - -# Fetches properties attached to a metadata target. -function(_juce_get_metadata target key out_var) - get_target_property(content "${target}" "INTERFACE_JUCE_${key}") - - if(NOT "${content}" STREQUAL "content-NOTFOUND") - set(${out_var} "${content}" PARENT_SCOPE) - endif() -endfunction() - -# ================================================================================================== - -function(_juce_should_build_module_source filename output_var) - get_filename_component(trimmed_name "${filename}" NAME_WE) - - set(result TRUE) - - set(pairs - "OSX\;Darwin" - "Windows\;Windows" - "Linux\;Linux" - "Android\;Android" - "iOS\;iOS") - - foreach(pair IN LISTS pairs) - list(GET pair 0 suffix) - list(GET pair 1 system_name) - - if((trimmed_name MATCHES "_${suffix}$") AND NOT (CMAKE_SYSTEM_NAME STREQUAL "${system_name}")) - set(result FALSE) - endif() - endforeach() - - set("${output_var}" "${result}" PARENT_SCOPE) -endfunction() - -function(_juce_module_sources module_path output_path built_sources other_sources) - get_filename_component(module_parent_path ${module_path} DIRECTORY) - get_filename_component(module_glob ${module_path} NAME) - - file(GLOB_RECURSE all_module_files - CONFIGURE_DEPENDS LIST_DIRECTORIES FALSE - RELATIVE "${module_parent_path}" - "${module_path}/*") - - set(base_path "${module_glob}/${module_glob}") - - set(module_cpp ${all_module_files}) - list(FILTER module_cpp INCLUDE REGEX "^${base_path}[^/]*\\.(c|cc|cpp|cxx|s|asm)$") - - if(APPLE) - set(module_mm ${all_module_files}) - list(FILTER module_mm INCLUDE REGEX "^${base_path}[^/]*\\.mm$") - - if(module_mm) - set(module_mm_replaced ${module_mm}) - list(TRANSFORM module_mm_replaced REPLACE "\\.mm$" ".cpp") - list(REMOVE_ITEM module_cpp ${module_mm_replaced}) - endif() - - set(module_apple_files ${all_module_files}) - list(FILTER module_apple_files INCLUDE REGEX "${base_path}[^/]*\\.(m|mm|metal|r|swift)$") - list(APPEND module_cpp ${module_apple_files}) - endif() - - set(headers ${all_module_files}) - - set(module_files_to_build) - - foreach(filename IN LISTS module_cpp) - _juce_should_build_module_source("${filename}" should_build_file) - - if(should_build_file) - list(APPEND module_files_to_build "${filename}") - endif() - endforeach() - - if(NOT "${module_files_to_build}" STREQUAL "") - list(REMOVE_ITEM headers ${module_files_to_build}) - endif() - - foreach(source_list IN ITEMS module_files_to_build headers) - list(TRANSFORM ${source_list} PREPEND "${output_path}/") - endforeach() - - set(${built_sources} ${module_files_to_build} PARENT_SCOPE) - set(${other_sources} ${headers} PARENT_SCOPE) -endfunction() - -# ================================================================================================== - -function(_juce_get_all_plugin_kinds out) - set(${out} AU AUv3 AAX Standalone Unity VST VST3 PARENT_SCOPE) -endfunction() - -function(_juce_get_platform_plugin_kinds out) - set(result Standalone) - - if(APPLE AND (CMAKE_GENERATOR STREQUAL "Xcode")) - list(APPEND result AUv3) - endif() - - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - list(APPEND result AU) - endif() - - if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android") - list(APPEND result AAX Unity VST VST3) - endif() - - set(${out} ${result} PARENT_SCOPE) -endfunction() - -function(_juce_add_plugin_definitions target visibility) - _juce_get_all_plugin_kinds(options) - cmake_parse_arguments(JUCE_ARG "${options}" "" "" ${ARGN}) - - foreach(opt IN LISTS options) - set(flag_value 0) - - if(JUCE_ARG_${opt}) - set(flag_value 1) - endif() - - target_compile_definitions(${target} ${visibility} "JucePlugin_Build_${opt}=${flag_value}") - endforeach() -endfunction() - -# ================================================================================================== - function(_juce_add_au_resource_fork shared_code_target au_target) if(NOT JUCE_XCRUN) return() @@ -469,256 +224,6 @@ endfunction() # ================================================================================================== -# Takes a target, a link visibility, and a variable-length list of framework -# names. On macOS, finds the requested frameworks using `find_library` and -# links them. On iOS, links directly with `-framework Name`. -function(_juce_link_frameworks target visibility) - foreach(framework IN LISTS ARGN) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - find_library("juce_found_${framework}" "${framework}" REQUIRED) - target_link_libraries("${target}" "${visibility}" "${juce_found_${framework}}") - elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") - # CoreServices is only available on iOS 12+, we must link it weakly on earlier platforms - if((framework STREQUAL "CoreServices") AND (CMAKE_OSX_DEPLOYMENT_TARGET LESS 12.0)) - set(framework_flags "-weak_framework ${framework}") - else() - set(framework_flags "-framework ${framework}") - endif() - - target_link_libraries("${target}" "${visibility}" "${framework_flags}") - endif() - endforeach() -endfunction() - -# ================================================================================================== - -function(_juce_add_plugin_wrapper_target format path out_path) - _juce_module_sources("${path}" "${out_path}" out_var headers) - list(FILTER out_var EXCLUDE REGEX "/juce_audio_plugin_client_utils.cpp$") - set(target_name juce_audio_plugin_client_${format}) - - _juce_add_interface_library("${target_name}" ${out_var}) - _juce_add_plugin_definitions("${target_name}" INTERFACE ${format}) - _juce_add_standard_defs("${target_name}") - - target_compile_features("${target_name}" INTERFACE cxx_std_14) - add_library("juce::${target_name}" ALIAS "${target_name}") - - if(format STREQUAL "AUv3") - _juce_link_frameworks("${target_name}" INTERFACE AVFoundation) - - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - _juce_link_frameworks("${target_name}" INTERFACE AudioUnit) - endif() - elseif(format STREQUAL "AU") - _juce_link_frameworks("${target_name}" INTERFACE AudioUnit CoreAudioKit) - endif() -endfunction() - -# ================================================================================================== - -function(_juce_link_libs_from_metadata module_name dict key) - _juce_get_metadata("${dict}" "${key}" libs) - - if(libs) - target_link_libraries(${module_name} INTERFACE ${libs}) - endif() -endfunction() - -# ================================================================================================== - -function(juce_add_module module_path) - set(one_value_args INSTALL_PATH ALIAS_NAMESPACE) - cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "" ${ARGN}) - - _juce_make_absolute(module_path) - - get_filename_component(module_name ${module_path} NAME) - get_filename_component(module_parent_path ${module_path} DIRECTORY) - - set(module_header_name "${module_name}.h") - - if(NOT EXISTS "${module_path}/${module_header_name}") - set(module_header_name "${module_header_name}pp") - endif() - - if(NOT EXISTS "${module_path}/${module_header_name}") - message(FATAL_ERROR "Could not locate module header for module '${module_path}'") - endif() - - set(base_path "${module_parent_path}") - - _juce_module_sources("${module_path}" "${base_path}" globbed_sources headers) - - if(${module_name} STREQUAL "juce_audio_plugin_client") - _juce_get_platform_plugin_kinds(plugin_kinds) - - foreach(kind IN LISTS plugin_kinds) - _juce_add_plugin_wrapper_target(${kind} "${module_path}" "${base_path}") - endforeach() - - set(utils_source - "${base_path}/${module_name}/juce_audio_plugin_client_utils.cpp") - add_library(juce_audio_plugin_client_utils INTERFACE) - target_sources(juce_audio_plugin_client_utils INTERFACE "${utils_source}") - - if(JUCE_ARG_ALIAS_NAMESPACE) - add_library(${JUCE_ARG_ALIAS_NAMESPACE}::juce_audio_plugin_client_utils - ALIAS juce_audio_plugin_client_utils) - endif() - - file(GLOB_RECURSE all_module_files - CONFIGURE_DEPENDS LIST_DIRECTORIES FALSE - RELATIVE "${module_parent_path}" - "${module_path}/*") - else() - list(APPEND all_module_sources ${globbed_sources}) - endif() - - _juce_add_interface_library(${module_name} ${all_module_sources}) - - set_property(GLOBAL APPEND PROPERTY _juce_module_names ${module_name}) - - set_target_properties(${module_name} PROPERTIES - INTERFACE_JUCE_MODULE_SOURCES "${globbed_sources}" - INTERFACE_JUCE_MODULE_HEADERS "${headers}" - INTERFACE_JUCE_MODULE_PATH "${base_path}") - - if(JUCE_ENABLE_MODULE_SOURCE_GROUPS) - target_sources(${module_name} INTERFACE ${headers}) - endif() - - if(${module_name} STREQUAL "juce_core") - _juce_add_standard_defs(${module_name}) - - target_link_libraries(juce_core INTERFACE juce::juce_atomic_wrapper) - - if(CMAKE_SYSTEM_NAME MATCHES ".*BSD") - target_link_libraries(juce_core INTERFACE execinfo) - elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") - target_sources(juce_core INTERFACE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c") - target_include_directories(juce_core INTERFACE "${ANDROID_NDK}/sources/android/cpufeatures") - target_link_libraries(juce_core INTERFACE android log) - endif() - endif() - - if(${module_name} STREQUAL "juce_audio_processors") - add_library(juce_vst3_headers INTERFACE) - - target_compile_definitions(juce_vst3_headers INTERFACE "$<$:JUCE_CUSTOM_VST3_SDK=1>") - - target_include_directories(juce_vst3_headers INTERFACE - "$<$:$>" - "$<$>:${base_path}/juce_audio_processors/format_types/VST3_SDK>") - - target_link_libraries(juce_audio_processors INTERFACE juce_vst3_headers) - - if(JUCE_ARG_ALIAS_NAMESPACE) - add_library(${JUCE_ARG_ALIAS_NAMESPACE}::juce_vst3_headers ALIAS juce_vst3_headers) - endif() - endif() - - target_include_directories(${module_name} INTERFACE ${base_path}) - - target_compile_definitions(${module_name} INTERFACE JUCE_MODULE_AVAILABLE_${module_name}=1) - - if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) - target_compile_definitions(${module_name} INTERFACE LINUX=1) - endif() - - _juce_extract_metadata_block(JUCE_MODULE_DECLARATION "${module_path}/${module_header_name}" metadata_dict) - - _juce_get_metadata("${metadata_dict}" minimumCppStandard module_cpp_standard) - - if(module_cpp_standard) - target_compile_features(${module_name} INTERFACE cxx_std_${module_cpp_standard}) - else() - target_compile_features(${module_name} INTERFACE cxx_std_11) - endif() - - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - _juce_get_metadata("${metadata_dict}" OSXFrameworks module_osxframeworks) - - foreach(module_framework IN LISTS module_osxframeworks) - if(module_framework STREQUAL "") - continue() - endif() - - _juce_link_frameworks("${module_name}" INTERFACE "${module_framework}") - endforeach() - - _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" OSXLibs) - elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") - _juce_get_metadata("${metadata_dict}" iOSFrameworks module_iosframeworks) - - foreach(module_framework IN LISTS module_iosframeworks) - if(module_framework STREQUAL "") - continue() - endif() - - _juce_link_frameworks("${module_name}" INTERFACE "${module_framework}") - endforeach() - - _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" iOSLibs) - elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) - _juce_get_metadata("${metadata_dict}" linuxPackages module_linuxpackages) - - if(module_linuxpackages) - _juce_create_pkgconfig_target(${module_name}_LINUX_DEPS ${module_linuxpackages}) - target_link_libraries(${module_name} INTERFACE juce::pkgconfig_${module_name}_LINUX_DEPS) - endif() - - _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" linuxLibs) - elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) - if(module_name STREQUAL "juce_gui_basics") - target_compile_options(${module_name} INTERFACE /bigobj) - endif() - - _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" windowsLibs) - elseif(MSYS OR MINGW) - if(module_name STREQUAL "juce_gui_basics") - target_compile_options(${module_name} INTERFACE "-Wa,-mbig-obj") - endif() - - _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" mingwLibs) - endif() - endif() - - _juce_get_metadata("${metadata_dict}" dependencies module_dependencies) - target_link_libraries(${module_name} INTERFACE ${module_dependencies}) - - _juce_get_metadata("${metadata_dict}" searchpaths module_searchpaths) - - if(NOT module_searchpaths STREQUAL "") - foreach(module_searchpath IN LISTS module_searchpaths) - target_include_directories(${module_name} - INTERFACE "${module_path}/${module_searchpath}") - endforeach() - endif() - - if(JUCE_ARG_INSTALL_PATH) - install(DIRECTORY "${module_path}" DESTINATION "${JUCE_ARG_INSTALL_PATH}") - endif() - - if(JUCE_ARG_ALIAS_NAMESPACE) - add_library(${JUCE_ARG_ALIAS_NAMESPACE}::${module_name} ALIAS ${module_name}) - endif() -endfunction() - -function(juce_add_modules) - set(one_value_args INSTALL_PATH ALIAS_NAMESPACE) - cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "" ${ARGN}) - - foreach(path IN LISTS JUCE_ARG_UNPARSED_ARGUMENTS) - juce_add_module(${path} - INSTALL_PATH "${JUCE_ARG_INSTALL_PATH}" - ALIAS_NAMESPACE "${JUCE_ARG_ALIAS_NAMESPACE}") - endforeach() -endfunction() - -# ================================================================================================== - # Ideally, we'd check the preprocessor defs on the target to see whether # JUCE_USE_CURL, JUCE_WEB_BROWSER, or JUCE_IN_APP_PURCHASES have been explicitly turned off, # and then link libraries as appropriate.