# This script provides helper functions for FindModules # Parse and set variables from VERSION dependency file # On return: # MODULENAME_ARCHIVE will be set to parent scope # MODULENAME_VER will be set to parent scope (eg FFMPEG_VER, DAV1D_VER) # MODULENAME_BASE_URL will be set to parent scope if exists in VERSION file (eg FFMPEG_BASE_URL) # MODULENAME_HASH will be set if either SHA256 or SHA512 exists in VERSION file # MODULENAME_BYPRODUCT will be set to parent scope function(get_versionfile_data) # Dependency path set(MODULE_PATH "${PROJECTSOURCE}/tools/depends/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_LOCATION}") if(NOT EXISTS "${MODULE_PATH}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_VERSION}-VERSION") MESSAGE(FATAL_ERROR "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_VERSION}-VERSION does not exist at ${MODULE_PATH}.") else() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE "${MODULE_PATH}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_VERSION}-VERSION") endif() file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LNAME REGEX "^[ \t]*LIBNAME=") file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_VER REGEX "^[ \t]*VERSION=") file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE REGEX "^[ \t]*ARCHIVE=") file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL REGEX "^[ \t]*BASE_URL=") file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL REGEX "^[ \t]*FULL_URL=") if(WIN32 OR WINDOWS_STORE) file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT REGEX "^[ \t]*BYPRODUCT_WIN=") else() file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT REGEX "^[ \t]*BYPRODUCT=") endif() # Tarball Hash file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH_SHA256 REGEX "^[ \t]*SHA256=") file(STRINGS ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FILE} ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH_SHA512 REGEX "^[ \t]*SHA512=") string(REGEX REPLACE ".*LIBNAME=([^ \t]*).*" "\\1" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LNAME "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LNAME}") string(REGEX REPLACE ".*VERSION=([^ \t]*).*" "\\1" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_VER "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_VER}") string(REGEX REPLACE ".*ARCHIVE=([^ \t]*).*" "\\1" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE}") string(REGEX REPLACE ".*BASE_URL=([^ \t]*).*" "\\1" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL}") string(REGEX REPLACE ".*FULL_URL=([^ \t]*).*" "\\1" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL}") if(WIN32 OR WINDOWS_STORE) string(REGEX REPLACE ".*BYPRODUCT_WIN=([^ \t]*).*" "\\1" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}") else() string(REGEX REPLACE ".*BYPRODUCT=([^ \t]*).*" "\\1" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}") endif() string(REGEX REPLACE "\\$\\(LIBNAME\\)" "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LNAME}" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE}") string(REGEX REPLACE "\\$\\(VERSION\\)" "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_VER}" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE}") set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE} PARENT_SCOPE) # FULL_URL substitutes the following VERSION, BASE_URL # FULL_URL syntax: FULL_URL=$(BASE_URL)/archive/$(VERSION).tar.gz string(REGEX REPLACE "\\$\\(BASE_URL\\)" "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL}" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL}") string(REGEX REPLACE "\\$\\(VERSION\\)" "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_VER}" ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL}") set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL} PARENT_SCOPE) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_VER ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_VER} PARENT_SCOPE) if (${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL} PARENT_SCOPE) else() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL "${KODI_MIRROR}/build-deps/sources" PARENT_SCOPE) endif() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT} PARENT_SCOPE) # allow user to override the download URL hash with a local tarball hash # needed for offline build envs if (NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH) if (${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH_SHA256) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH_SHA256} PARENT_SCOPE) elseif(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH_SHA512) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH_SHA512} PARENT_SCOPE) endif() endif() endfunction() # Parse and set Version from VERSION dependency file # Used for retrieving version numbers for dependency libs to allow setting # a required version for find_package call # On return: # LIB_MODULENAME_VER will be set to parent scope (eg LIB_FMT_VER) function(get_libversion_data module libtype) # Dependency path set(LIB_MODULE_PATH "${CMAKE_SOURCE_DIR}/tools/depends/${libtype}/${module}") string(TOUPPER ${module} MOD_UPPER) if(NOT EXISTS "${LIB_MODULE_PATH}/${MOD_UPPER}-VERSION") MESSAGE(FATAL_ERROR "${MOD_UPPER}-VERSION does not exist at ${LIB_MODULE_PATH}.") else() set(${MOD_UPPER}_FILE "${LIB_MODULE_PATH}/${MOD_UPPER}-VERSION") endif() file(STRINGS ${${MOD_UPPER}_FILE} ${MOD_UPPER}_VER REGEX "^[ \t]*VERSION=") string(REGEX REPLACE ".*VERSION=([^ \t]*).*" "\\1" ${MOD_UPPER}_VER "${${MOD_UPPER}_VER}") set(LIB_${MOD_UPPER}_VER ${${MOD_UPPER}_VER} PARENT_SCOPE) endfunction() # Function to loop through list of patch files (full path) # Sets to a PATCH_COMMAND variable and set to parent scope (caller) # Used to test windows line endings and set appropriate patch commands function(generate_patchcommand _patchlist) # find the path to the patch executable find_package(Patch MODULE REQUIRED ${SEARCH_QUIET}) # Loop through patches and add to PATCH_COMMAND # for windows, check CRLF/LF state set(_count 0) foreach(patch ${_patchlist}) if(WIN32 OR WINDOWS_STORE) PATCH_LF_CHECK(${patch}) endif() if(${_count} EQUAL "0") set(_patch_command ${PATCH_EXECUTABLE} -p1 -i ${patch}) else() list(APPEND _patch_command COMMAND ${PATCH_EXECUTABLE} -p1 -i ${patch}) endif() math(EXPR _count "${_count}+1") endforeach() set(PATCH_COMMAND ${_patch_command} PARENT_SCOPE) unset(_count) unset(_patch_command) endfunction() # Macro to factor out the repetitive URL setup macro(SETUP_BUILD_VARS) string(TOUPPER ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC} ${CMAKE_FIND_PACKAGE_NAME}_MODULE) if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_LOCATION) string(TOUPPER ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_LOCATION} _MODULE_UPPER) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_VERSION ${_MODULE_UPPER}) unset(_MODULE_UPPER) else() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_LOCATION ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_MODULE_VERSION ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}) endif() if(NOT DEFINED ${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME) set(${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}) endif() if(NOT DEFINED ${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME_PC) set(${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME_PC ${${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME}) endif() # Fall through to target build module dir if not explicitly set if(NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE "target") endif() if(NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME build-${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}) endif() # Location for build type, native or target if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE STREQUAL "target") set(DEP_LOCATION "${DEPENDS_PATH}") else() set(DEP_LOCATION "${NATIVEPREFIX}") endif() # PROJECTSOURCE used in native toolchain to provide core project sourcedir # to externalproject_add targets that have a different CMAKE_SOURCE_DIR (eg jsonschema/texturepacker in-tree) if(NOT PROJECTSOURCE) set(PROJECTSOURCE ${CMAKE_SOURCE_DIR}) endif() if(NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_DISABLE_VERSION) # populate variables of data from VERSION file for MODULE get_versionfile_data() endif() if(VERBOSE) message(STATUS "MODULE: ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}") message(STATUS "${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE: ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE}") message(STATUS "DEP_LOCATION: ${DEP_LOCATION}") message(STATUS "PROJECTSOURCE: ${PROJECTSOURCE}") endif() endmacro() macro(CLEAR_BUILD_VARS) # unset all generic variables to insure clean state between macro calls # Potentially an issue with scope when a macro is used inside a dep that uses a macro unset(PROJECTSOURCE) unset(INSTALL_DIR) unset(CMAKE_ARGS) unset(PATCH_COMMAND) unset(CONFIGURE_COMMAND) unset(BUILD_COMMAND) unset(INSTALL_COMMAND) unset(BUILD_IN_SOURCE) unset(BUILD_BYPRODUCTS) unset(WIN_DISABLE_PROJECT_FLAGS) # unset all module specific variables to insure clean state between macro calls # potentially an issue when a native and a target of the same module exists unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIST_SEPARATOR) unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR) unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR_PLATFORM) unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INSTALL_PREFIX) unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_TOOLCHAIN_FILE) unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE) endmacro() # Macro to create externalproject_add target # # Common usage # # CMAKE_ARGS: cmake(required) # PATCH_COMMAND: ALL(optional) # CONFIGURE_COMMAND: autoconf(required), meson(required) # BUILD_COMMAND: autoconf(required), meson(required), cmake(optional) # INSTALL_COMMAND: autoconf(required), meson(required), cmake(optional) # BUILD_IN_SOURCE: ALL(optional) # BUILD_BYPRODUCTS: ALL(optional) # # Windows Specific # WIN_DISABLE_PROJECT_FLAGS - Set to not use core compiler flags for externalproject_add target # This removes CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS # from the externalproject_add target. Primarily used for HOST build # tools that may have different arch/build requirements to the core app # target (eg flatc) # macro(BUILD_DEP_TARGET) include(ExternalProject) # allow user to override the download URL with a local tarball # needed for offline build envs if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL) get_filename_component(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL}" ABSOLUTE) elseif(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_FULL_URL}") else() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BASE_URL}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE}) endif() if(VERBOSE) message(STATUS "${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL: ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL}") endif() # Remove cmake warning when Xcode generator used with "New" build system if(CMAKE_GENERATOR STREQUAL Xcode) # Policy CMP0114 is not set to NEW. In order to support the Xcode "new build # system", this project must be updated to set policy CMP0114 to NEW. if(CMAKE_XCODE_BUILD_SYSTEM STREQUAL 12) cmake_policy(SET CMP0114 NEW) else() cmake_policy(SET CMP0114 OLD) endif() endif() if(CMAKE_ARGS) set(CMAKE_ARGS CMAKE_ARGS ${CMAKE_ARGS} -DPROJECTSOURCE=${PROJECTSOURCE} "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}") # We dont have a toolchain for windows, so manually add all the cmake # build arguments we may want # We can disable adding them with WIN_DISABLE_PROJECT_FLAGS. This is potentially required # for host build tools (eg flatc) that may be a different arch to the core app if(WIN32 OR WINDOWS_STORE) if(NOT (DEFINED WIN_DISABLE_PROJECT_FLAGS OR ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE STREQUAL "native")) list(APPEND CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} $<$:${CMAKE_C_FLAGS_DEBUG}> $<$:${CMAKE_C_FLAGS_RELEASE}> ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_C_FLAGS}" "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} $<$:${CMAKE_CXX_FLAGS_DEBUG}> $<$:${CMAKE_CXX_FLAGS_RELEASE}> ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_CXX_FLAGS}" "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS} $<$:${CMAKE_EXE_LINKER_FLAGS_DEBUG}> $<$:${CMAKE_EXE_LINKER_FLAGS_RELEASE}> ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_EXE_LINKER_FLAGS}") endif() endif() if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INSTALL_LIBDIR) list(APPEND CMAKE_ARGS -DCMAKE_INSTALL_LIBDIR=${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INSTALL_LIBDIR}) else() list(APPEND CMAKE_ARGS -DCMAKE_INSTALL_LIBDIR=lib) endif() if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INSTALL_PREFIX) list(APPEND CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INSTALL_PREFIX}) else() list(APPEND CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DEP_LOCATION}) endif() if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_TOOLCHAIN_FILE) list(APPEND CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_TOOLCHAIN_FILE}) elseif(CMAKE_TOOLCHAIN_FILE) list(APPEND CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) endif() # Set build type for dep build. # if MODULE has set a manual build type, use it, otherwise use project build type if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_TYPE) list(APPEND CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_TYPE}") # Build_type is forced, so unset the opposite _LIBRARY_ to only give # select_library_configurations one library name to choose from if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_TYPE STREQUAL "Release") unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG) else() unset(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE) endif() else() # single config generator (ie Make, Ninja) if(CMAKE_BUILD_TYPE) list(APPEND CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") else() # Multi-config generators (eg VS, Xcode, Ninja Multi-Config) will not have CMAKE_BUILD_TYPE # Use config genex to generate the types # Potential issue if Build type isnt supported by lib project # eg lib supports Debug/Release, however users selects RelWithDebInfo in project list(APPEND CMAKE_ARGS "-DCMAKE_BUILD_TYPE=$") endif() endif() # Xcode - Default sub projects to makefile builds. More consistent # Windows - Default to same generator version used in parent if(CMAKE_GENERATOR STREQUAL Xcode) if(NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR CMAKE_GENERATOR "Unix Makefiles") endif() elseif(MSVC) # Only apply SYSTEM variables for target build libs if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE STREQUAL "target") if(DEFINED CMAKE_SYSTEM_VERSION) list(APPEND CMAKE_ARGS -DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}) endif() if(DEFINED CMAKE_SYSTEM_NAME) list(APPEND CMAKE_ARGS -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}) endif() endif() if(NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR CMAKE_GENERATOR "${CMAKE_GENERATOR}") endif() if(NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR_PLATFORM) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR_PLATFORM CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM}) endif() endif() endif() if(PATCH_COMMAND) set(PATCH_COMMAND PATCH_COMMAND ${PATCH_COMMAND}) endif() if(CONFIGURE_COMMAND) # DEP_BUILDENV is potentially populated in a toolchain file. We dont want to use it # for host tool builds, so make sure to check _LIB_TYPE if(NOT CMAKE_ARGS AND (DEP_BUILDENV AND NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE STREQUAL "native")) # DEP_BUILDENV only used for non cmake externalproject_add builds # iterate through CONFIGURE_COMMAND looking for multiple COMMAND, we need to # add DEP_BUILDENV for each distinct COMMAND set(tmp_config_command ${DEP_BUILDENV}) foreach(item ${CONFIGURE_COMMAND}) list(APPEND tmp_config_command ${item}) if(item STREQUAL "COMMAND") list(APPEND tmp_config_command ${DEP_BUILDENV}) endif() endforeach() set(CONFIGURE_COMMAND CONFIGURE_COMMAND ${tmp_config_command}) unset(tmp_config_command) else() set(CONFIGURE_COMMAND CONFIGURE_COMMAND ${CONFIGURE_COMMAND}) endif() endif() if(BUILD_COMMAND) # DEP_BUILDENV is potentially populated in a toolchain file. We dont want to use it # for host tool builds, so make sure to check _LIB_TYPE if(NOT CMAKE_ARGS AND (DEP_BUILDENV AND NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_LIB_TYPE STREQUAL "native")) # DEP_BUILDENV only used for non cmake externalproject_add builds # iterate through BUILD_COMMAND looking for multiple COMMAND, we need to # add DEP_BUILDENV for each distinct COMMAND set(tmp_build_command ${DEP_BUILDENV}) foreach(item ${BUILD_COMMAND}) list(APPEND tmp_build_command ${item}) if(item STREQUAL "COMMAND") list(APPEND tmp_build_command ${DEP_BUILDENV}) endif() endforeach() set(BUILD_COMMAND BUILD_COMMAND ${tmp_build_command}) unset(tmp_build_command) else() set(BUILD_COMMAND BUILD_COMMAND ${BUILD_COMMAND}) endif() endif() if(INSTALL_COMMAND) set(INSTALL_COMMAND INSTALL_COMMAND ${INSTALL_COMMAND}) endif() if(BUILD_IN_SOURCE) set(BUILD_IN_SOURCE BUILD_IN_SOURCE ${BUILD_IN_SOURCE}) endif() # Change extension of BYPRODUCT # eg, Macos uses dylib for shared libs, but all other unix platforms use .so if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT_EXTENSION) string(REGEX REPLACE "\\.[^.]*$" "" _LIBNAME ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT "${_LIBNAME}.${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT_EXTENSION}") unset(_LIBNAME) endif() # Defines if the build byproduct is a shared lib # This sets up extension changes, and output paths. Both can be overridden by the # caller if required. # Unix platforms default to .so extension if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SHARED_LIB) if(WIN32 OR WINDOWS_STORE) if(NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_POSTFIX) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_POSTFIX dll) endif() if(NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH bin) endif() if(NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_PATH) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_PATH lib) endif() else() if(NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_POSTFIX) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_POSTFIX so) endif() if(NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH lib) endif() endif() else() if(NOT DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH lib) endif() endif() # Set Library names. if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_DEBUG_POSTFIX) set(_POSTFIX ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_DEBUG_POSTFIX}) string(REGEX REPLACE "\\.[^.]*$" "" _LIBNAME ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}) string(REGEX REPLACE "^.*\\." "" _LIBEXT ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}) if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SHARED_LIB) # Windows shared libs have both a .lib and a .dll artifact. # IMPLIB_ is windows only for our use cases if(WIN32 OR WINDOWS_STORE) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_DEBUG ${DEP_LOCATION}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_PATH}/${_LIBNAME}${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_DEBUG_POSTFIX}.${_LIBEXT}) endif() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG ${DEP_LOCATION}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH}/${_LIBNAME}${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_DEBUG_POSTFIX}.${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_POSTFIX}) else() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG ${DEP_LOCATION}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH}/${_LIBNAME}${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_DEBUG_POSTFIX}.${_LIBEXT}) endif() endif() # set _LIBRARY_RELEASE for use of select_library_configurations # any modules that dont use select_library_configurations, we set _LIBRARY # No harm in having either set for both potential paths if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SHARED_LIB) string(REGEX REPLACE "\\.[^.]*$" "" _LIBNAME ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}) string(REGEX REPLACE "^.*\\." "" _LIBEXT ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}) if(WIN32 OR WINDOWS_STORE) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_RELEASE ${DEP_LOCATION}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_PATH}/${_LIBNAME}.${_LIBEXT}) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_RELEASE}) endif() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE ${DEP_LOCATION}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH}/${_LIBNAME}.${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_POSTFIX}) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE}) elseif(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INTERFACE_LIB) # Dont create LIBRARY variables for interface libs. We consider these header only for now else() set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE ${DEP_LOCATION}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LOCATION_PATH}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BYPRODUCT}) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE}) endif() if(NOT ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INCLUDE_DIR) set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INCLUDE_DIR ${DEP_LOCATION}/include) endif() if(BUILD_BYPRODUCTS) set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS ${BUILD_BYPRODUCTS}) else() if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20") set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "$,${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG},${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE}>") else() if(DEFINED CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE STREQUAL "Release" AND DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG) set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG}") else() set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY}") endif() else() message(FATAL_ERROR "MultiConfig Generator usage requires CMake >= 3.20.0 - Generator Expressions in BYPRODUCT option") endif() endif() else() set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY}") endif() endif() if(NOT INSTALL_DIR) set(INSTALL_DIR ${DEP_LOCATION}) endif() # Allow a target to supply in-tree source location. eg TexturePacker, JsonSchemaBuilder if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SOURCE_DIR) set(BUILD_DOWNLOAD_STEPS SOURCE_DIR "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SOURCE_DIR}") else() set(BUILD_DOWNLOAD_STEPS URL ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_URL} URL_HASH ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_HASH} DOWNLOAD_DIR ${TARBALL_DIR} DOWNLOAD_NAME ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_ARCHIVE}) endif() externalproject_add(${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME} ${BUILD_DOWNLOAD_STEPS} PREFIX ${CORE_BUILD_DIR}/${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME} INSTALL_DIR ${INSTALL_DIR} ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIST_SEPARATOR} ${CMAKE_ARGS} ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR} ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_GENERATOR_PLATFORM} ${PATCH_COMMAND} ${CONFIGURE_COMMAND} ${BUILD_COMMAND} ${INSTALL_COMMAND} ${BUILD_BYPRODUCTS} ${BUILD_IN_SOURCE}) set_target_properties(${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME} PROPERTIES FOLDER "External Projects") CLEAR_BUILD_VARS() # Set both _FOUND and _FOUND as we have some legacy macros/functions that # rely on _FOUND, but cmake has new policies that are heading towards _FOUND set(${${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME}_FOUND 1) string(TOUPPER "${${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME}" _search_upper) set(${_search_upper}_FOUND ON CACHE BOOL "${_search_upper}_FOUND" FORCE) unset(_search_upper) endmacro() # Macro to test format of line endings of a patch # Windows Specific macro(PATCH_LF_CHECK patch) if(CMAKE_HOST_WIN32) # On Windows "patch.exe" can only handle CR-LF line-endings. # Our patches have LF-only line endings - except when they # have been checked out as part of a dependency hosted on Git # and core.autocrlf=true. file(READ ${ARGV0} patch_content_hex HEX) # Force handle LF-only line endings if(NOT patch_content_hex MATCHES "0d0a") if (NOT "--binary" IN_LIST PATCH_EXECUTABLE) list(APPEND PATCH_EXECUTABLE --binary) endif() else() if ("--binary" IN_LIST PATCH_EXECUTABLE) list(REMOVE_ITEM PATCH_EXECUTABLE --binary) endif() endif() endif() unset(patch_content_hex) endmacro() # Function to check a list of libraries to force the calling library to be # rebuilt if one of its dependencies needs to be built. # # ToDo: all dep_list libs are considered REQUIRED for find_package call # Should we handle optional dependencies? # # caller: Parent lib # dep_list: List of libraries to be checked for LIB_BUILD property # # Return: Set ${caller}_FORCE_BUILD variable to alert caller lib to force a rebuild # # ToDo: We break early on detection of first lib in dep_list requiring a build # We may want to run all find_package calls regardless for dependency inception function(check_dependency_build caller dep_list) foreach(_dep ${dep_list}) find_package(${_dep} REQUIRED ${SEARCH_QUIET}) if(TARGET LIBRARY::${_dep}) # Test if LIB_BUILD property is set on LIBRARY::${_dep} TARGET indicating # if it requires to be build (version update, or even just missing) get_target_property(${caller}_DEP_BUILD LIBRARY::${_dep} LIB_BUILD) if(${caller}_DEP_BUILD) # A dependency is to be rebuilt, set this lib to be built, no need to check any # other libs in DEPLIST set(${caller}_FORCE_BUILD ON PARENT_SCOPE) if(VERBOSE) message(WARNING "${caller} alerted to rebuild required by ${_dep}") endif() break() endif() endif() endforeach() endfunction() macro(SETUP_FIND_SPECS) # Setup Find version specs if requested by caller if(${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION) if(${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_EXACT) set(CONFIG_${CMAKE_FIND_PACKAGE_NAME}_FIND_SPEC "${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_COMPLETE} EXACT") set(PC_${CMAKE_FIND_PACKAGE_NAME}_FIND_SPEC "=${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_COMPLETE}") else() set(CONFIG_${CMAKE_FIND_PACKAGE_NAME}_FIND_SPEC "${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_COMPLETE}") set(PC_${CMAKE_FIND_PACKAGE_NAME}_FIND_SPEC ">=${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_COMPLETE}") endif() endif() endmacro() # Macro to generate a TARGET based on information created by a BUILD_DEP_TARGET call # # Populates the following INTERFACE options for a target if they exist for ${CMAKE_FIND_PACKAGE_NAME}_MODULE # INTERFACE_INCLUDE_DIRECTORIES # INTERFACE_LINK_LIBRARIES # IMPORTED_LOCATION_RELEASE # IMPORTED_IMPLIB_RELEASE # IMPORTED_LOCATION_DEBUG # IMPORTED_IMPLIB_DEBUG # # Input: # ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SHARED_LIB (BOOL) - Library created as SHARED # ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INTERFACE_LIB (BOOL) - Library created as INTERFACE # Default: STATIC - Library created as INTERFACE # # ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_TYPE # Default: ${APP_NAME_LC} # Option: LIBRARY # macro(SETUP_BUILD_TARGET) if(DEFINED ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_TYPE) set(LIB_SCOPE ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_TYPE}) else() set(LIB_SCOPE ${APP_NAME_LC}) endif() if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SHARED_LIB) add_library(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} SHARED IMPORTED) elseif(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INTERFACE_LIB) add_library(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} INTERFACE IMPORTED) else() add_library(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} STATIC IMPORTED) endif() if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INCLUDE_DIR) set_target_properties(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_INCLUDE_DIR}") endif() if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LINK_LIBRARIES) set_target_properties(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} PROPERTIES INTERFACE_LINK_LIBRARIES "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LINK_LIBRARIES}") endif() if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE) set_target_properties(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} PROPERTIES IMPORTED_CONFIGURATIONS RELEASE IMPORTED_LOCATION_RELEASE "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_RELEASE}") if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SHARED_LIB AND (WIN32 OR WINDOWS_STORE)) set_target_properties(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} PROPERTIES IMPORTED_IMPLIB_RELEASE "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_RELEASE}") endif() endif() if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG) set_target_properties(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} PROPERTIES IMPORTED_LOCATION_DEBUG "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_LIBRARY_DEBUG}") set_property(TARGET ${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_SHARED_LIB AND (WIN32 OR WINDOWS_STORE)) set_target_properties(${LIB_SCOPE}::${CMAKE_FIND_PACKAGE_NAME} PROPERTIES IMPORTED_IMPLIB_DEBUG "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_IMPLIB_DEBUG}") endif() endif() endmacro() # Macro to add INTERFACE_COMPILE_DEFINITIONS to a TARGET # if ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_COMPILE_DEFINITIONS is defined # # We use this to add HAVE_ defines to any TARGET type we use (pkgconfig, cmake or build) # macro(ADD_TARGET_COMPILE_DEFINITION) if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_COMPILE_DEFINITIONS) get_target_property(_ALIASTARGET ${APP_NAME_LC}::${CMAKE_FIND_PACKAGE_NAME} ALIASED_TARGET) if(_ALIASTARGET) set(LIB_TARGET ${_ALIASTARGET}) else() set(LIB_TARGET ${APP_NAME_LC}::${CMAKE_FIND_PACKAGE_NAME}) endif() set_property(TARGET ${LIB_TARGET} APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS "${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_COMPILE_DEFINITIONS}") endif() endmacro() # Add internal build target when a Multi Config Generator is used # We cant add a dependency based off a generator expression for targeted build types, # https://gitlab.kitware.com/cmake/cmake/-/issues/19467 # therefore if the find heuristics only find the library, we add the internal build # target to the project to allow user to manually trigger for any build type they need # in case only a specific build type is actually available (eg Release found, Debug Required) # This is mainly targeted for windows who required different runtime libs for different # types, and they arent compatible macro(ADD_MULTICONFIG_BUILDMACRO) if(_multiconfig_generator) if(NOT TARGET ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME}) cmake_language(EVAL CODE " buildmacro${CMAKE_FIND_PACKAGE_NAME}() ") set_target_properties(${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE) endif() add_dependencies(build_internal_depends ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_BUILD_NAME}) endif() endmacro() macro(SEARCH_EXISTING_PACKAGES) find_package(${${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME} ${CONFIG_${CMAKE_FIND_PACKAGE_NAME}_FIND_SPEC} CONFIG ${SEARCH_QUIET} HINTS ${DEPENDS_PATH}/share/cmake ${DEPENDS_PATH}/lib/cmake ${${CORE_SYSTEM_NAME}_SEARCH_CONFIG}) # fallback to pkgconfig to cover all bases if(NOT ${${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME}_FOUND) find_package(PkgConfig ${SEARCH_QUIET}) if(PKG_CONFIG_FOUND) pkg_check_modules(${${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME} ${${CMAKE_FIND_PACKAGE_NAME}_SEARCH_NAME_PC}${PC_${CMAKE_FIND_PACKAGE_NAME}_FIND_SPEC} ${SEARCH_QUIET} IMPORTED_TARGET) endif() endif() endmacro() # Custom property that we can track to allow us to notify to dependency find modules # that a dependency of that find module is being built, and therefore that higher level # dependency should also be built regardless of success in lib searches define_property(TARGET PROPERTY LIB_BUILD BRIEF_DOCS "This target will be compiling the library" FULL_DOCS "This target will be compiling the library") # Functions to generate meson cross files for a platform macro(generate_mesoncrossfile) create_mesonbinaries() file(WRITE ${DEPENDS_PATH}/share/${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}-cross-file.meson "${meson_binaries_string}\n") create_mesonhostmachine() file(APPEND ${DEPENDS_PATH}/share/${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}-cross-file.meson "${meson_host_machine_string}\n") create_mesonproperties() file(APPEND ${DEPENDS_PATH}/share/${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}-cross-file.meson "${meson_properties_string}\n") create_mesonbuiltin() file(APPEND ${DEPENDS_PATH}/share/${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}-cross-file.meson "${meson_builtin_string}\n") endmacro() # Creates the [binaries] block of a meson cross file # sets meson_binaries_string to PARENT_SCOPE # Format for binaries is # Additional module specific binaries can be supplied by setting # ${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_BINARIES with suitable pairs function(create_mesonbinaries) set(binariespairs "c" "CMAKE_C_COMPILER" "cpp" "CMAKE_CXX_COMPILER" "ar" "CMAKE_AR" "cmake" "CMAKE_COMMAND") if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_BINARIES) list(APPEND binariespairs ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE_LC}_BINARIES}) endif() if(NOT "${CMAKE_STRIP}" STREQUAL "") list(APPEND binariespairs "strip" "CMAKE_STRIP") endif() if(PKG_CONFIG_EXECUTABLE) list(APPEND binariespairs "pkg-config" "PKG_CONFIG_EXECUTABLE") endif() # Get/set loop limit (Size - 1) from size of binariespairs list list(LENGTH binariespairs options_length) math(EXPR options_length "${options_length} - 1") foreach(option_arg RANGE 0 ${options_length} 2) math(EXPR cmake_arg "${option_arg} + 1") # meson option name list(GET binariespairs ${option_arg} meson_label_name) # cmake source variable name list(GET binariespairs ${cmake_arg} cmake_binary_name) set(input "${${cmake_binary_name}}") string(STRIP "${input}" input) string(PREPEND input "${meson_label_name} = '") string(APPEND input "'") string(APPEND output_string "${input}\n") endforeach() # Easiest to just prepend header at the end of the full string creation string(PREPEND output_string "[binaries]\n") set(meson_binaries_string ${output_string} PARENT_SCOPE) endfunction() # Creates the [host_machine] block of a meson cross file # sets meson_host_machine_string to PARENT_SCOPE function(create_mesonhostmachine) # CMAKE_C_COMPILER_ARCHITECTURE_ID is only populated for MSVC prior to cmake 4.1 # cmake 4.1+ does populate for unix platforms if(CMAKE_C_COMPILER_ARCHITECTURE_ID) string(TOUPPER "${CMAKE_C_COMPILER_ARCHITECTURE_ID}" UPPER_C_ARCH) else() string(TOUPPER "${CPU}" UPPER_C_ARCH) endif() # Non-exhaustive list to map cmake CPU to meson cpu names # https://mesonbuild.com/Reference-tables.html#cpu-families if("${UPPER_C_ARCH}" MATCHES "ARM64" OR "${UPPER_C_ARCH}" MATCHES "AARCH64") set(meson_cpu_family aarch64) elseif("${UPPER_C_ARCH}" MATCHES "ARMV.") set(meson_cpu_family arm) elseif("${UPPER_C_ARCH}" STREQUAL "X64" OR "${UPPER_C_ARCH}" STREQUAL "X86_64") set(meson_cpu_family x86_64) elseif("${UPPER_C_ARCH}" STREQUAL "X86" OR "${UPPER_C_ARCH}" MATCHES "I.86") set(meson_cpu_family x86) endif() # Non-exhaustive list to map cmake to meson os names # https://mesonbuild.com/Reference-tables.html#operating-system-names if(CMAKE_SYSTEM_NAME MATCHES "Android") set(meson_sys_name android) elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(meson_sys_name darwin) elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") set(meson_sys_name freebsd) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(meson_sys_name linux) elseif(CMAKE_SYSTEM_NAME MATCHES "NetBSD") set(meson_sys_name netbsd) elseif(CMAKE_SYSTEM_NAME MATCHES Windows) set(meson_sys_name windows) endif() string(APPEND output_string "system = '${meson_sys_name}'\n") string(APPEND output_string "cpu_family = '${meson_cpu_family}'\n") # cpu is apparently unnecessary from a functional stand point, however the field # is still required. We have no easy way to populate, so for now just use an empty value string(APPEND output_string "cpu = ''\n") string(APPEND output_string "endian = 'little'\n") # Easiest to just prepend header at the end of the full string creation string(PREPEND output_string "[host_machine]\n") set(meson_host_machine_string ${output_string} PARENT_SCOPE) endfunction() # Creates the [properties] block of a meson cross file # sets meson_properties_string to PARENT_SCOPE function(create_mesonproperties) string(APPEND output_string "pkg_config_libdir = '${DEPENDS_PATH}/lib/pkgconfig'\n") # Easiest to just prepend header at the end of the full string creation string(PREPEND output_string "[properties]\n") set(meson_properties_string ${output_string} PARENT_SCOPE) endfunction() # Creates the [Built-in Options] block of a meson cross file # sets meson_builtin_string to PARENT_SCOPE function(create_mesonbuiltin) # Pair is of the format: # The cmake field is based on the name of the variable, but removing the CMAKE_ prefix # This allows us to also provide a module specific additional variable if additions are required # eg. CMAKE_C_FLAGS dav1d_C_FLAGS set(builtinpairs "c_args" "C_FLAGS" "c_link_args" "EXE_LINKER_FLAGS" "cpp_args" "CXX_FLAGS" "cpp_link_args" "EXE_LINKER_FLAGS") # Get/set loop limit (Size - 1) from size of builtinpairs list list(LENGTH builtinpairs options_length) math(EXPR options_length "${options_length} - 1") foreach(option_arg RANGE 0 ${options_length} 2) math(EXPR cmake_flag_arg "${option_arg} + 1") # meson option name list(GET builtinpairs ${option_arg} meson_label_name) # cmake source variable name list(GET builtinpairs ${cmake_flag_arg} cmake_flag_name) set(input "${CMAKE_${cmake_flag_name}} ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_${cmake_flag_name}}") string(STRIP "${input}" input) # builtinpairs cmake source variables are specifically single strings, and not lists string(REGEX REPLACE "[ ]+" "', '" tmp_string "${input}") string(PREPEND tmp_string "${meson_label_name} = ['") string(APPEND tmp_string "']") string(APPEND output_string "${tmp_string}\n") endforeach() # allow a module to override the default_library type. if(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_libType) string(APPEND output_string "default_library = '${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_libType}'\n") else() string(APPEND output_string "default_library = 'static'\n") endif() string(APPEND output_string "prefix = '${DEPENDS_PATH}'\n") string(APPEND output_string "libdir = 'lib'\n") string(APPEND output_string "bindir = 'bin'\n") string(APPEND output_string "includedir = 'include'\n") # Easiest to just prepend header at the end of the full string creation string(PREPEND output_string "[built-in options]\n") set(meson_builtin_string ${output_string} PARENT_SCOPE) endfunction() # Creates a variable and sets in parent scope - ${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_dev_env # Variable is purposely set with an ending COMMAND to allow the variable to be placed # in an externalproject_add build or configure step. # # eg. set(BUILD_COMMAND ${${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_dev_env} # Ninja::Ninja -C ./build) # function(create_module_dev_env) if(WIN32 OR WINDOWS_STORE) set(Vcvars_FIND_VCVARSALL TRUE) if(NOT VERBOSE_FIND) set(Vcvars_FIND_QUIETLY TRUE) endif() find_package(Vcvars REQUIRED) if(WINDOWS_STORE) set(vcstore store) endif() string(TOLOWER "${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}" _lower_hostarch) string(TOLOWER "${CMAKE_GENERATOR_PLATFORM}" _lower_targetarch) if("${_lower_hostarch}" STREQUAL "x64") set(_lower_hostarch amd64) endif() if("${_lower_targetarch}" STREQUAL "x64") set(_lower_targetarch amd64) endif() if("${_lower_hostarch}" STREQUAL "${_lower_targetarch}") set(vcarch ${_lower_hostarch}) else() set(vcarch ${_lower_hostarch}_${_lower_targetarch}) endif() set(cmd_wrapper "${Vcvars_BATCH_FILE}" ${vcarch} ${vcstore} ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}) # trailing COMMAND sets externalproject_add commands up, and is required set(${${CMAKE_FIND_PACKAGE_NAME}_MODULE}_dev_env ${cmd_wrapper} COMMAND PARENT_SCOPE) endif() endfunction()