From d6acfd84fd6a90e68bb62650906bc5df56837565 Mon Sep 17 00:00:00 2001 From: Damien Nguyen Date: Mon, 21 Feb 2022 17:44:08 +0100 Subject: [PATCH] Introduce FindTemplate.cmake and update utils.cmake - Add FindTemplate.cmake, _find_utils_begin.cmake and _find_utils_end.cmake - Fix missing success messages when looking for packages - Replace message("XXX") with message(STATUS "XXX") - Fix issues with package names capitalization and FetchContent(...) - Add version check to account for libraries with versions like OpenSSL (X.Y.Za) - Renamed MS_PREFER_LOCAL_PKG to MS_PREFER_SYSTEM_PKGS - Renamed MS_{pkg}_PREFER_LOCAL to MS_{pkg}_PREFER_SYSTEM - Allow "alias of alias" in __create_target_aliases - Add support for specifying multiple packages using the MS_PREFER_SYSTEM_PKGS variable and a comma separated list - Add LIBS_CMAKE_NAMES to mindspore_add_pkg - Add to_cmake_path function - Update mindspore_add_pkg to allow for exact version match - Generate pseudo-CMake config files for non-CMake projects --- .cmake-format.yaml | 8 + cmake/modules/FindTemplate.cmake | 1497 +++++++++++++++++++++++++ cmake/modules/_find_utils_begin.cmake | 34 + cmake/modules/_find_utils_end.cmake | 29 + cmake/utils.cmake | 824 +++++++++++--- 5 files changed, 2211 insertions(+), 181 deletions(-) create mode 100644 cmake/modules/FindTemplate.cmake create mode 100644 cmake/modules/_find_utils_begin.cmake create mode 100644 cmake/modules/_find_utils_end.cmake diff --git a/.cmake-format.yaml b/.cmake-format.yaml index 680ef618f5a..47388ebf9a1 100644 --- a/.cmake-format.yaml +++ b/.cmake-format.yaml @@ -45,6 +45,12 @@ parse: mindspore_add_pkg: pargs: nargs: 1 + flags: + - FORCE_EXACT_VERSION + - CMAKE_PKG_NO_COMPONENTS + - GEN_CMAKE_CONFIG + - FORCE_CONFIG_SEARCH + - BUILD_OPTION_PASS_PREFIX kwargs: URL: 1 MD5: 1 @@ -58,8 +64,10 @@ parse: RELEASE: 1 LIB_PATH: 1 CUSTOM_CMAKE: 1 + NS_NAME: 1 CMAKE_OPTION: + LIBS: + + LIBS_CMAKE_NAMES: + PRE_CONFIGURE_COMMAND: + CONFIGURE_COMMAND: + BUILD_OPTION: + diff --git a/cmake/modules/FindTemplate.cmake b/cmake/modules/FindTemplate.cmake new file mode 100644 index 00000000000..a4b232a2fe7 --- /dev/null +++ b/cmake/modules/FindTemplate.cmake @@ -0,0 +1,1497 @@ +# ============================================================================== +# +# Copyright 2021 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============================================================================== +# Largely inspired by the FindBoost.cmake module: +# +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. +# ============================================================================== + +# cmake-lint: disable=C0103 + +# ~~~ +# Variables that may be defined: +# ${_pkg}_TARGET_DEFINITIONS - Compile definitions added to all targets +# ${_pkg}_NAMESPACE - Specify the namespace for manually found imported targets (defaults to ${_pkg}) +# NB: has no effects if the package is found using CMake config mode +# ${_pkg}_DEFINE_PREFIX - PREFIX for pre-processor defines (defaults to ${_pkg} in uppercase); mostly used to +# automatically determine the package's version +# ${_pkg}_${component}_TYPE - Type of component +# Can be one of: LIBRARY (default), EXECUTABLE +# ${_pkg}_${component}_TARGET_DEFINITIONS - Compile definitions added to a particular component (in uppercase) +# ${_pkg}_NO_CMAKE - No search for CMake packages +# ${_pkg}_NO_PKGCONFIG - No search for package using PkgConfig +# ${_pkg}_INCLUDE_FILE - Include file name to look for include directory +# ${_pkg}_INCLUDE_DIR_UP_INDEX - Number of sub-directory levels the include file is located into (defaults to 0) +# e.g. /usr/include/mylib/dir/mylib.h & 0 => inc_dir = /usr/include/mylib/dir) +# e.g. /usr/include/mylib/dir/mylib.h & 1 => inc_dir = /usr/include/mylib) +# ${_pkg}_INCLUDE_PATH_SUFFIXES +# ${_pkg}_DEFAULT_COMPONENTS - Default list of components +# ${_pkg}_${component}_NAMES or ${_pkg}_${component}_RELEASE_NAMES and/or ${_pkg}_${component}_DEBUG_NAMES +# ${_pkg}_${component}_DEPENDENCIES - List of dependencies between components of the package +# ${_pkg}_${component}_EXTERNAL_DEPENDENCIES - List of libraries/CMake targets +# ${_pkg}_${component}_HEADER_ONLY - TRUE/FALSE if component is header-only +# ${_pkg}_INC_SYSTEM_PATHS - List of system paths to consider when looking for header files +# ${_pkg}_LIB_SYSTEM_PATHS - List of system paths to consider when looking for libraries +# ${_pkg}_FIND_LIBRARY_SUFFIXES - List of library suffixes (in lieu of CMAKE_FIND_LIBRAY_SUFFIXES) +# Functions +# ${_pkg}_version_function function with signature: +# func(include_dir) +# -> need to assign in parent scope ${_pkg}_VERSION, ${_pkg}_VERSION_MAJOR, ${_pkg}_VERSION_MINOR, +# ${_pkg}_VERSION_PATCH +# ${_pkg}_include_dir_post_process function with signature: +# func(var include_dir) +# -> `var` is the name of the include dir variable and `include_dir` its original value +# ${_pkg}_update_library_search_dirs_with_prebuilt_paths function with signature: +# func(componentlibvar basedir) +# -> append to ${componentlibvar} pre-built paths based on ${basedir} +# ${_pgk}_windows_set_import_library_path with signature: +# func(target basename) or func(target basename config) where config is RELEASE, DEBUG, etc. +# -> typical call: ${_pkg}_windows_set_import_library_path(some_target IMPORTED_LOCATION) +# ${_pkg}_post_process function with signature: +# func(pkg) +# ~~~ + +# The FPHSA helper provides standard way of reporting final search results to the user including the version and +# component checks. +include(FindPackageHandleStandardArgs) + +# Save project's policies +cmake_policy(PUSH) +cmake_policy(SET CMP0057 NEW) # if IN_LIST +cmake_policy(SET CMP0102 NEW) # if mark_as_advanced(non_cache_var) + +# ============================================================================== +# FindPkg functions & macros +# + +# ~~~ +# Print debug text if ${_pkg}_DEBUG is set. Call example: +# _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "debug message") +# ~~~ +function(_debug_print file line text) + if(${_pkg}_DEBUG) + message(STATUS "[ ${file}:${line} ] ${text}") + endif() +endfunction() + +# ~~~ +# _debug_print_var(file line variable_name [ENVIRONMENT] [SOURCE "short explanation of origin of var value"]) +# +# ENVIRONMENT - look up environment variable instead of CMake variable +# +# Print variable name and its value if ${_pkg}_DEBUG is set. Call example: +# _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" ${_pkg}_ROOT) +# ~~~ +function(_debug_print_var file line name) + if(${_pkg}_DEBUG) + cmake_parse_arguments(_args "ENVIRONMENT" "SOURCE" "" ${ARGN}) + + unset(source) + if(_args_SOURCE) + set(source " (${_args_SOURCE})") + endif() + + if(_args_ENVIRONMENT) + if(DEFINED ENV{${name}}) + set(value "\"$ENV{${name}}\"") + else() + set(value "") + endif() + set(_name "ENV{${name}}") + else() + if(DEFINED "${name}") + set(value "\"${${name}}\"") + else() + set(value "") + endif() + set(_name "${name}") + endif() + + _debug_print("${file}" "${line}" "${_name} = ${value}${source}") + endif() +endfunction() + +# ###################################################################################################################### +# +# Check the existence of the libraries. +# +# ###################################################################################################################### +# This macro was taken directly from the FindQt4.cmake file that is included with the CMake distribution. This is NOT my +# work. All work was done by the original authors of the FindQt4.cmake file. Only minor modifications were made to +# remove references to Qt and make this file more generally applicable And ELSE/ENDIF pairs were removed for +# readability. +# ###################################################################################################################### +macro(_adjust_lib_vars basename) + if(${_pkg}_INCLUDE_DIR) + if(${_pkg}_${basename}_HEADER_ONLY) + string(TOUPPER ${basename} BASENAME) + set(${_pkg}_${BASENAME}_FOUND ON) + else() + if(${_pkg}_${basename}_LIBRARY_DEBUG AND ${_pkg}_${basename}_LIBRARY_RELEASE) + # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for single-config generators, set optimized and + # debug libraries + get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(_isMultiConfig OR CMAKE_BUILD_TYPE) + set(${_pkg}_${basename}_LIBRARY optimized ${${_pkg}_${basename}_LIBRARY_RELEASE} debug + ${${_pkg}_${basename}_LIBRARY_DEBUG}) + else() + # For single-config generators where CMAKE_BUILD_TYPE has no value, just use the release libraries + set(${_pkg}_${basename}_LIBRARY ${${_pkg}_${basename}_LIBRARY_RELEASE}) + endif() + # FIXME: This probably should be set for both cases + set(${_pkg}_${basename}_LIBRARIES optimized ${${_pkg}_${basename}_LIBRARY_RELEASE} debug + ${${_pkg}_${basename}_LIBRARY_DEBUG}) + endif() + + # if only the release version was found, set the debug variable also to the release version + if(${_pkg}_${basename}_LIBRARY_RELEASE AND NOT ${_pkg}_${basename}_LIBRARY_DEBUG) + set(${_pkg}_${basename}_LIBRARY_DEBUG ${${_pkg}_${basename}_LIBRARY_RELEASE}) + set(${_pkg}_${basename}_LIBRARY ${${_pkg}_${basename}_LIBRARY_RELEASE}) + set(${_pkg}_${basename}_LIBRARIES ${${_pkg}_${basename}_LIBRARY_RELEASE}) + endif() + + # if only the debug version was found, set the release variable also to the debug version + if(${_pkg}_${basename}_LIBRARY_DEBUG AND NOT ${_pkg}_${basename}_LIBRARY_RELEASE) + set(${_pkg}_${basename}_LIBRARY_RELEASE ${${_pkg}_${basename}_LIBRARY_DEBUG}) + set(${_pkg}_${basename}_LIBRARY ${${_pkg}_${basename}_LIBRARY_DEBUG}) + set(${_pkg}_${basename}_LIBRARIES ${${_pkg}_${basename}_LIBRARY_DEBUG}) + endif() + + # If the debug & release library ends up being the same, omit the keywords + if("${${_pkg}_${basename}_LIBRARY_RELEASE}" STREQUAL "${${_pkg}_${basename}_LIBRARY_DEBUG}") + set(${_pkg}_${basename}_LIBRARY ${${_pkg}_${basename}_LIBRARY_RELEASE}) + set(${_pkg}_${basename}_LIBRARIES ${${_pkg}_${basename}_LIBRARY_RELEASE}) + endif() + + if(${_pkg}_${basename}_LIBRARY) + set(${_pkg}_${basename}_FOUND ON) + endif() + endif() + endif() + + # Make variables changeable to the advanced user + mark_as_advanced(${_pkg}_${basename}_LIBRARY_RELEASE ${_pkg}_${basename}_LIBRARY_DEBUG) +endmacro() + +# ~~~ +# Detect changes in used variables. +# Compares the current variable value with the last one. +# In short form: +# v != v_LAST -> CHANGED = 1 +# v is defined, v_LAST not -> CHANGED = 1 +# v is not defined, but v_LAST is -> CHANGED = 1 +# otherwise -> CHANGED = 0 +# CHANGED is returned in variable named ${changed_var} +# ~~~ +macro(_change_detect changed_var) + set(${changed_var} 0) + foreach(var ${ARGN}) + if(DEFINED _${_pkg}_COMPONENTS_SEARCHED) + if(${var}) + if(_${var}_LAST) + string(COMPARE NOTEQUAL "${${var}}" "${_${var}_LAST}" _${var}_CHANGED) + else() + set(_${var}_CHANGED 1) + endif() + elseif(_${var}_LAST) + set(_${var}_CHANGED 1) + endif() + if(_${var}_CHANGED) + set(${changed_var} 1) + endif() + else() + set(_${var}_CHANGED 0) + endif() + endforeach() +endmacro() + +# +# Find the given library (var). Use 'build_type' to support different lib paths for RELEASE or DEBUG builds +# +macro(_find_library var build_type) + # cmake-lint: disable=C0103 + + find_library(${var} ${ARGN}) + + if(${var}) + # If this is the first library found then save ${_pkg}_LIBRARY_DIR_[RELEASE,DEBUG]. + if(NOT ${_pkg}_LIBRARY_DIR_${build_type}) + get_filename_component(_dir "${${var}}" PATH) + set(${_pkg}_LIBRARY_DIR_${build_type} + "${_dir}" + CACHE PATH "${_pkg} library directory ${build_type}" FORCE) + endif() + elseif(_${_pkg}_FIND_LIBRARY_HINTS_FOR_COMPONENT) + # Try component-specific hints but do not save ${_pkg}_LIBRARY_DIR_[RELEASE,DEBUG]. + find_library(${var} HINTS ${_${_pkg}_FIND_LIBRARY_HINTS_FOR_COMPONENT} ${ARGN}) + endif() + + # If ${_pkg}_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there. + if(${_pkg}_LIBRARY_DIR_${build_type}) + set(_${_pkg}_LIBRARY_SEARCH_DIRS_${build_type} ${${_pkg}_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH) + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_LIBRARY_DIR_${build_type}") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "_${_pkg}_LIBRARY_SEARCH_DIRS_${build_type}") + endif() +endmacro() + +# +# Find the given program (var). +# +macro(_find_program var) + # cmake-lint: disable=C0103 + + find_program(${var} ${ARGN}) + + if(${var}) + # If this is the first library found then save ${_pkg}_LIBRARY_DIR_[RELEASE,DEBUG]. + if(NOT ${_pkg}_EXECUTABLE_DIR) + get_filename_component(_dir "${${var}}" DIRECTORY) + set(${_pkg}_EXECUTABLE_DIR + "${_dir}" + CACHE PATH "${_pkg} executable directory" FORCE) + endif() + elseif(_${_pkg}_FIND_EXECUTABLE_HINTS_FOR_COMPONENT) + # Try component-specific hints but do not save ${_pkg}_EXECUTABLE_DIR. + find_program(${var} HINTS ${_${_pkg}_FIND_EXECUTABLE_HINTS_FOR_COMPONENT} ${ARGN}) + endif() + + # If ${_pkg}_EXECUTABLE_DIR is known then search only there. + if(${_pkg}_EXECUTABLE_DIR) + set(_${_pkg}_EXECUTABLE_SEARCH_DIRS ${${_pkg}_EXECUTABLE_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_EXECUTABLE_DIR") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_EXECUTABLE_SEARCH_DIRS") + endif() +endmacro() + +# ------------------------------------------------------------------------------ +# Determine if any missing dependencies require adding to the component list. +# +# Sets ${_pkg}_${COMPONENT}_DEPENDENCIES for each required component +# +# * componentvar - the component list variable name +# * extravar - the indirect dependency list variable name +# +function(_missing_dependencies componentvar extravar) + # * _${_pkg}_unprocessed_components - list of components requiring processing + # * _${_pkg}_processed_components - components already processed (or currently being processed) + # * _${_pkg}_new_components - new components discovered for future processing + + list(APPEND _${_pkg}_unprocessed_components ${${componentvar}}) + + while(_${_pkg}_unprocessed_components) + list(APPEND _${_pkg}_processed_components ${_${_pkg}_unprocessed_components}) + foreach(component ${_${_pkg}_unprocessed_components}) + string(TOUPPER ${component} uppercomponent) + # set(${_ret} ${${_pkg}_${component}_DEPENDENCIES} PARENT_SCOPE) + + foreach(componentdep ${${_pkg}_${component}_DEPENDENCIES}) + if(NOT ("${componentdep}" IN_LIST _${_pkg}_processed_components OR "${componentdep}" IN_LIST + _${_pkg}_new_components)) + list(APPEND _${_pkg}_new_components ${componentdep}) + endif() + endforeach() + endforeach() + set(_${_pkg}_unprocessed_components ${_${_pkg}_new_components}) + unset(_${_pkg}_new_components) + endwhile() + set(_${_pkg}_extra_components ${_${_pkg}_processed_components}) + if(_${_pkg}_extra_components AND ${componentvar}) + list(REMOVE_ITEM _${_pkg}_extra_components ${${componentvar}}) + endif() + set(${componentvar} + ${_${_pkg}_processed_components} + PARENT_SCOPE) + set(${extravar} + ${_${_pkg}_extra_components} + PARENT_SCOPE) +endfunction() + +# Update library search directories using some pre-built paths +function(_update_library_search_dirs_with_prebuilt_paths componentlibvar basedir) + if(COMMAND ${_pkg}_update_library_search_dirs_with_prebuilt_paths) + cmake_language(CALL ${_pkg}_update_library_search_dirs_with_prebuilt_paths ${componentlibvar} ${basedir}) + endif() + + set(${componentlibvar} + ${${componentlibvar}} + PARENT_SCOPE) +endfunction() + +# Update executable search directories using some pre-built paths +function(_update_exec_search_dirs_with_prebuilt_paths componentlibvar basedir) + if(COMMAND ${_pkg}_update_exec_search_dirs_with_prebuilt_paths) + cmake_language(CALL ${_pkg}_update_exec_search_dirs_with_prebuilt_paths ${componentlibvar} ${basedir}) + endif() + + set(${componentlibvar} + ${${componentlibvar}} + PARENT_SCOPE) +endfunction() + +# Set import library paths on Windows +function(_windows_set_import_library_path target basename) + if(COMMAND ${_pkg}_windows_set_import_library_path) + cmake_language(CALL ${_pkg}_windows_set_import_library_path ${target} ${basename}) + endif() +endfunction() + +function(_extract_version_from_lib_name pkg_name lib_path) + if(CMAKE_VERSION VERSION_LESS 3.19) + return() + endif() + + file(REAL_PATH "${lib_path}" lib_path) + + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET lib_path EXTENSION _ext) + else() + get_filename_component(_ext "${lib_path}" EXT) + endif() + + if(_ext MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(${pkg_name}_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(${pkg_name}_VERSION_MINOR ${CMAKE_MATCH_2}) + set(${pkg_name}_VERSION_PATCH ${CMAKE_MATCH_3}) + elseif(_ext MATCHES "([0-9]+)\\.([0-9]+)") + + set(${pkg_name}_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(${pkg_name}_VERSION_MINOR ${CMAKE_MATCH_2}) + set(${pkg_name}_VERSION_PATCH 0) + endif() + + if((NOT "${${pkg_name}_VERSION_MAJOR}" STREQUAL "") AND (NOT "${${pkg_name}_VERSION_MINOR}" STREQUAL "")) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Extracting version information from filename: ${lib_path}") + + set(${pkg_name}_VERSION_MAJOR + ${${pkg_name}_VERSION_MAJOR} + PARENT_SCOPE) + set(${pkg_name}_VERSION_MINOR + ${${pkg_name}_VERSION_MINOR} + PARENT_SCOPE) + set(${pkg_name}_VERSION_PATCH + ${${pkg_name}_VERSION_PATCH} + PARENT_SCOPE) + set(${pkg_name}_VERSION + ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3} + PARENT_SCOPE) + set(${pkg_name}_HAS_VERSION + TRUE + CACHE BOOL "If ${pkg_name} version was found" FORCE) + set(${pkg_name}_HAS_VERSION + TRUE + PARENT_SCOPE) + endif() +endfunction() + +# Initialize some component-related variables +macro(_init_component_vars components) + set(_${_pkg}_find_types) + foreach(_comp ${${components}}) + set(${_pkg}_FIND_REQUIRED_${_comp} ${${_pkg}_FIND_REQUIRED}) + if(NOT ${_pkg}_${_comp}_TYPE) + set(${_pkg}_${_comp}_TYPE "LIBRARY") + elseif((NOT "${${_pkg}_${_comp}_TYPE}" STREQUAL "LIBRARY") AND (NOT "${${_pkg}_${_comp}_TYPE}" STREQUAL "EXECUTABLE" + )) + message(FATAL_ERROR "Invalid value for ${_pkg}_${_comp}_TYPE: ${${_pkg}_${_comp}_TYPE}") + endif() + list(APPEND _${_pkg}_find_types ${${_pkg}_${_comp}_TYPE}) + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_FIND_REQUIRED_${_comp}") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_${_comp}_TYPE") + endforeach() +endmacro() + +# ============================================================================== +# Initialize some helper variables + +if("${${_pkg}_NAMESPACE}" STREQUAL "") + set(${_pkg}_NAMESPACE ${_pkg}) +endif() + +if("${${_pkg}_DEFINE_PREFIX}" STREQUAL "") + string(TOUPPER ${_pkg} ${_pkg}_DEFINE_PREFIX) +endif() + +# ============================================================================== +# Before we go searching, check whether a ${_pkg} cmake package is available, unless the user specifically asked NOT to +# search for one. +# +# If ${_pkg}_DIR is set, this behaves as any find_package call would. If not, it looks at ${_pkg}_ROOT and ${_pkg}ROOT +# to find ${_pkg}. +# +if(NOT ${_pkg}_NO_CMAKE) + # If ${_pkg}_DIR is not set, look for ${_pkg}ROOT and ${_pkg}_ROOT as alternatives, since these are more conventional + # for ${_pkg}. + if("$ENV{${_pkg}_DIR}" STREQUAL "") + if(NOT "$ENV{${_pkg}_ROOT}" STREQUAL "") + set(ENV{${_pkg}_DIR} $ENV{${_pkg}_ROOT}) + elseif(NOT "$ENV{${_pkg}ROOT}" STREQUAL "") + set(ENV{${_pkg}_DIR} $ENV{${_pkg}ROOT}) + endif() + endif() + + set(_${_pkg}_FIND_PACKAGE_ARGS "") + if(${_pkg}_NO_SYSTEM_PATHS) + list(APPEND _${_pkg}_FIND_PACKAGE_ARGS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + endif() + + # Additional components may be required via component dependencies. Add any missing components to the list. + _missing_dependencies(${_pkg}_FIND_COMPONENTS _${_pkg}_EXTRA_FIND_COMPONENTS) + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_EXTRA_FIND_COMPONENTS") + + # Do the same find_package call but look specifically for the CMake version. Note that args are passed in the + # ${_pkg}_FIND_xxxxx variables, so there is no need to delegate them to this find_package call. + if(NOT ${_pkg}_FOUND) + find_package(${_pkg} QUIET CONFIG ${_${_pkg}_FIND_PACKAGE_ARGS}) + endif() + if(DEFINED ${_pkg}_DIR) + mark_as_advanced(${_pkg}_DIR) + endif() + + # If we found a ${_pkg} cmake package, then we're done. Print out what we found. Otherwise let the rest of the module + # try to find it. + if(${_pkg}_FOUND) + if(COMMAND ${_pkg}_post_process) + cmake_language(CALL ${_pkg}_post_process ${_pkg}) + endif() + + # Convert component found variables to standard variables if required + if(${_pkg}_FIND_COMPONENTS) + foreach(_comp IN LISTS ${_pkg}_FIND_COMPONENTS) + if(DEFINED ${_pkg}_${_comp}_FOUND) + # Nothing to do + elseif(TARGET ${${_pkg}_NAMESPACE}::${_comp}) + set(${_pkg}_${_comp}_FOUND TRUE) + endif() + string(TOUPPER ${_comp} _uppercomp) + if(DEFINED ${_pkg}_${_uppercomp}_FOUND) + set(${_pkg}_${_comp}_FOUND ${${_pkg}_${_uppercomp}_FOUND}) + endif() + endforeach() + endif() + + find_package_handle_standard_args(${_pkg} HANDLE_COMPONENTS CONFIG_MODE) + + # Restore project's policies + cmake_policy(POP) + return() + endif() +endif() + +# ============================================================================== +# Default initialization of components to search for + +if(NOT ${_pkg}_FIND_COMPONENTS) + set(${_pkg}_FIND_COMPONENTS ${${_pkg}_DEFAULT_COMPONENTS}) +endif() + +_init_component_vars(${_pkg}_FIND_COMPONENTS) +if("EXECUTABLE" IN_LIST _${_pkg}_find_types) + set(${_pkg}_NO_PKGCONFIG ON) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Disabling PkgConfig search since searching for at least one executable") +endif() + +# ============================================================================== +# Before we go searching by hand, check whether we can find PkgConfig and look for the package that wayunless the user +# specifically asked NOT to for one. +# +if(NOT ${_pkg}_NO_PKGCONFIG) + find_package(PkgConfig QUIET) + if(PkgConfig_FOUND) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Trying to find package ${_pkg} using PkgConfig: ${PKG_CONFIG_EXECUTABLE}") + + if(${_pkg}_FIND_COMPONENTS) + set(_${_pkg}_pkgconfig_found) + set(_${_pkg}_pkgconfig_args) + if(${_pkg}_DEBUG) + set(_${_pkg}_indent "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] ") + else() + list(APPEND _${_pkg}_pkgconfig_args QUIET) + endif() + + foreach(_comp ${${_pkg}_FIND_COMPONENTS}) + if(TARGET ${${_pkg}_NAMESPACE}::${_comp}) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "CMake target ${_tgt_name} already exists, skipping...") + continue() + endif() + + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Looking for component: ${_comp}") + set(_prefix ${_pkg}_${_comp}) + + list(APPEND ${_prefix}_PKGCONFIG_NAMES ${${_pkg}_${_comp}_NAMES}) + foreach(_name ${${_pkg}_${_comp}_NAMES}) + list(APPEND ${_prefix}_PKGCONFIG_NAMES "lib${_name}") + endforeach() + list(REMOVE_DUPLICATES ${_pkg}_${_comp}_PKGCONFIG_NAMES) + + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_${_comp}_PKGCONFIG_NAMES") + + if(NOT ${_pkg}_${_comp}_PKGCONFIG_NAMES) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "No names for component ${_comp} of ${_pkg}, skipping PkgConfig search for it") + continue() + endif() + + list(APPEND CMAKE_MESSAGE_INDENT "${_${_pkg}_indent}") + pkg_search_module(${_prefix} ${_${_pkg}_pkgconfig_args} ${${_pkg}_${_comp}_PKGCONFIG_NAMES}) + list(POP_BACK CMAKE_MESSAGE_INDENT) + if(${_prefix}_FOUND) + list(APPEND _${_pkg}_pkgconfig_found ${_comp}) + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_prefix}_INCLUDE_DIR") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_prefix}_LINK_LIBRARIES") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_prefix}_LDFLAGS_OTHER") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_prefix}_CFLAGS_OTHER") + endif() + endforeach() + + unset(_${_pkg}_indent) + + # If we found a ${_pkg} PkgConfig package, then we're done. Print out what we found. Otherwise let the rest of the + # module try to find it. + if(_${_pkg}_pkgconfig_found) + set(${_pkg}_FOUND TRUE) + list(GET _${_pkg}_pkgconfig_found 0 _comp) + set(${_pkg}_VERSION ${${_pkg}_${_comp}_VERSION}) + if(${_pkg}_VERSION VERSION_GREATER 0) + set(${_pkg}_HAS_VERSION + TRUE + CACHE BOOL "If ${_pkg} version was found" FORCE) + else() + set(${_pkg}_HAS_VERSION + FALSE + CACHE BOOL "If ${_pkg} version was found" FORCE) + endif() + + # Create the inmported targets + foreach(_comp ${_${_pkg}_pkgconfig_found}) + set(_tgt_name ${${_pkg}_NAMESPACE}::${_comp}) + set(_prefix ${_pkg}_${_comp}) + + if(NOT TARGET ${_tgt_name}) + add_library(${_tgt_name} INTERFACE IMPORTED) + endif() + if(${_prefix}_INCLUDE_DIRS) + set_target_properties(${_tgt_name} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${${_prefix}_INCLUDE_DIRS}") + endif() + if(${_prefix}_LINK_LIBRARIES) + set_target_properties(${_tgt_name} PROPERTIES INTERFACE_LINK_LIBRARIES "${${_prefix}_LINK_LIBRARIES}") + endif() + if(${_prefix}_LDFLAGS_OTHER) + set_target_properties(${_tgt_name} PROPERTIES INTERFACE_LINK_OPTIONS "${${_prefix}_LDFLAGS_OTHER}") + endif() + if(${_prefix}_CFLAGS_OTHER) + set_target_properties(${_tgt_name} PROPERTIES INTERFACE_COMPILE_OPTIONS "${${_prefix}_CFLAGS_OTHER}") + endif() + endforeach() + + # NB: no adjustments with ${_pkg}_${_uppercomp}_DEPENDENCIES here since PkgConfig takes cares of this for us. + # This has the downside that the dependencies are included into one single CMake targets rather than using + # CMake's target dependency mechanisms. + + if(${_pkg}_${_comp}_EXTERNAL_DEPENDENCIES) + target_link_libraries(${${_pkg}_NAMESPACE}::${_comp} INTERFACE "${${_pkg}_${_comp}_EXTERNAL_DEPENDENCIES}") + endif() + + if(COMMAND ${_pkg}_post_process) + cmake_language(CALL ${_pkg}_post_process ${_pkg}) + endif() + + if(${_pkg}_HAS_VERSION) + find_package_handle_standard_args( + ${_pkg} + VERSION_VAR ${_pkg}_VERSION + HANDLE_COMPONENTS REASON_FAILURE_MESSAGE "PkgConfig search failed") + else() + find_package_handle_standard_args(${_pkg} HANDLE_COMPONENTS REASON_FAILURE_MESSAGE "PkgConfig search failed") + endif() + + # ====================================================================== + # Finalize + + # Report ${_pkg}_LIBRARIES + set(${_pkg}_LIBRARIES "") + foreach(_comp IN LISTS ${_pkg}_FIND_COMPONENTS) + if(${_pkg}_${_comp}_FOUND) + list(APPEND ${_pkg}_LIBRARIES ${${_prefix}_LINK_LIBRARIES}) + endif() + endforeach() + list(REMOVE_DUPLICATES ${_pkg}_LIBRARIES) + + # Configure display of cache entries in GUI. + foreach(var ${_pkg}ROOT ${_pkg}_ROOT ${_${_pkg}_VARS_INC} ${_${_pkg}_VARS_LIB}) + get_property( + _type + CACHE ${var} + PROPERTY TYPE) + if(_type) + set_property(CACHE ${var} PROPERTY ADVANCED 1) + if("x${_type}" STREQUAL "xUNINITIALIZED") + set_property(CACHE ${var} PROPERTY TYPE PATH) + endif() + endif() + endforeach() + + # Record last used values of input variables so we can detect on the next run if the user changed them. + foreach(var ${_${_pkg}_VARS_INC} ${_${_pkg}_VARS_LIB} ${_${_pkg}_VARS_DIR} ${_${_pkg}_VARS_NAME}) + if(DEFINED ${var}) + set(_${var}_LAST + "${${var}}" + CACHE INTERNAL "Last used ${var} value.") + else() + unset(_${var}_LAST CACHE) + endif() + endforeach() + + # Maintain a persistent list of components requested anywhere since the last flush. + set(_${_pkg}_COMPONENTS_SEARCHED "${_${_pkg}_COMPONENTS_SEARCHED}") + list(APPEND _${_pkg}_COMPONENTS_SEARCHED ${${_pkg}_FIND_COMPONENTS}) + list(REMOVE_DUPLICATES _${_pkg}_COMPONENTS_SEARCHED) + list(SORT _${_pkg}_COMPONENTS_SEARCHED) + set(_${_pkg}_COMPONENTS_SEARCHED + "${_${_pkg}_COMPONENTS_SEARCHED}" + CACHE INTERNAL "Components requested for this build tree.") + + # Restore project's policies + cmake_policy(POP) + return() + endif() + else() + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Skipping PkgConfig since no COMPONENTS have been specified (not yet supported)") + endif() + else() + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Skipping PkgConfig since no pkg-config excutable could not be found.") + endif() +endif() + +# ============================================================================== +# Start of main. +# ============================================================================== + +# cmake-lint: disable=C0103 + +# If the user sets ${_pkg}_LIBRARY_DIR, use it as the default for both configurations. +if(NOT ${_pkg}_LIBRARY_DIR_RELEASE AND ${_pkg}_LIBRARY_DIR) + set(${_pkg}_LIBRARY_DIR_RELEASE "${${_pkg}_LIBRARY_DIR}") +endif() +if(NOT ${_pkg}_LIBRARY_DIR_DEBUG AND ${_pkg}_LIBRARY_DIR) + set(${_pkg}_LIBRARY_DIR_DEBUG "${${_pkg}_LIBRARY_DIR}") +endif() + +if(NOT DEFINED ${_pkg}_FIND_RELEASE_ONLY) + set(${_pkg}_FIND_RELEASE_ONLY FALSE) +endif() +if(NOT DEFINED ${_pkg}_USE_DEBUG_LIBS AND NOT ${_pkg}_FIND_RELEASE_ONLY) + set(${_pkg}_USE_DEBUG_LIBS TRUE) +endif() +if(NOT DEFINED ${_pkg}_USE_RELEASE_LIBS) + set(${_pkg}_USE_RELEASE_LIBS TRUE) +endif() + +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_FIND_RELEASE_ONLY") +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_NO_SYSTEM_PATHS") + +# ------------------------------------------------------------------------------ + +# Collect environment variable inputs as hints. Do not consider changes. +foreach(var ${_pkg}ROOT ${_pkg}_ROOT ${_pkg}_INCLUDEDIR ${_pkg}_LIBRARYDIR ${_pkg}_EXECDIR) + set(_env $ENV{${var}}) + if(_env) + file(TO_CMAKE_PATH "${_env}" _ENV_${var}) + else() + set(_ENV_${var} "") + endif() +endforeach() +if(NOT _ENV_${_pkg}_ROOT AND _ENV_${_pkg}ROOT) + set(_ENV_${_pkg}_ROOT "${_ENV_${_pkg}ROOT}") +endif() + +# Collect inputs and cached results. Detect changes since the last run. +if(NOT ${_pkg}_ROOT AND ${_pkg}ROOT) + set(${_pkg}_ROOT "${${_pkg}ROOT}") +endif() +set(_${_pkg}_VARS_DIR ${_pkg}_ROOT ${_pkg}_NO_SYSTEM_PATHS) + +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_ROOT") +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_ROOT" ENVIRONMENT) +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_INCLUDEDIR") +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_INCLUDEDIR" ENVIRONMENT) +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_LIBRARYDIR") +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_LIBRARYDIR" ENVIRONMENT) +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_EXECDIR") +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_EXECDIR" ENVIRONMENT) + +# ============================================================================== +# Search for ${_pkg} include DIR + +set(_${_pkg}_PATH_SUFFIXES ${${_pkg}_INCLUDE_PATH_SUFFIXES}) +set(_${_pkg}_VARS_INC ${_pkg}_INCLUDEDIR ${_pkg}_INCLUDE_DIR) +_change_detect(_${_pkg}_CHANGE_INCDIR ${_${_pkg}_VARS_DIR} ${_${_pkg}_VARS_INC}) +# Clear ${_pkg}_INCLUDE_DIR if it did not change but other input affecting the location did. We will find a new one +# based on the new inputs. +if(_${_pkg}_CHANGE_INCDIR AND NOT _${_pkg}_INCLUDE_DIR_CHANGED) + unset(${_pkg}_INCLUDE_DIR CACHE) +endif() + +if(NOT ${_pkg}_INCLUDE_DIR) + set(_${_pkg}_INCLUDE_SEARCH_DIRS "") + if(${_pkg}_INCLUDEDIR) + list(APPEND _${_pkg}_INCLUDE_SEARCH_DIRS ${${_pkg}_INCLUDEDIR}) + elseif(_ENV_${_pkg}_INCLUDEDIR) + list(APPEND _${_pkg}_INCLUDE_SEARCH_DIRS ${_ENV_${_pkg}_INCLUDEDIR}) + endif() + + if(${_pkg}_ROOT) + list(APPEND _${_pkg}_INCLUDE_SEARCH_DIRS ${${_pkg}_ROOT}) + elseif(_ENV_${_pkg}_ROOT) + list(APPEND _${_pkg}_INCLUDE_SEARCH_DIRS ${_ENV_${_pkg}_ROOT}) + endif() + + if(${_pkg}_NO_SYSTEM_PATHS) + list(APPEND _${_pkg}_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + else() + list( + APPEND + _${_pkg}_INCLUDE_SEARCH_DIRS + PATHS + /usr + /usr/local/ + /usr/local/homebrew # Mac OS X + /opt + /opt/local + /opt/local/var/macports/software # Mac OS X. + /sw/local) + + if(WIN32) + list( + APPEND + _${_pkg}_INCLUDE_SEARCH_DIRS + "$ENV{LOCALAPPDATA}/${_pkg}" + "$ENV{ALLUSERSPROFILE}/${_pkg}" + "C:/Program Files/${_pkg}" + "C:/Program Files (x86)/${_pkg}" + C:/${_pkg}) + endif() + + if(${_pkg}_INC_SYSTEM_PATHS) + list(APPEND _${_pkg}_INCLUDE_SEARCH_DIRS ${${_pkg}_INC_SYSTEM_PATHS}) + endif() + endif() + + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_INCLUDE_SEARCH_DIRS") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_PATH_SUFFIXES") + + # Look for a standard ${_pkg} header file. + find_path( + ${_pkg}_INCLUDE_DIR + NAMES ${${_pkg}_INCLUDE_FILE} + HINTS ${_${_pkg}_INCLUDE_SEARCH_DIRS} + PATH_SUFFIXES ${_${_pkg}_PATH_SUFFIXES}) + + find_file( + _${_pkg}_include_file + NAMES ${${_pkg}_INCLUDE_FILE} + HINTS ${${_pkg}_INCLUDE_DIR} + PATH_SUFFIXES ${_${_pkg}_PATH_SUFFIXES} + NO_DEFAULT_PATH) + + if(COMMAND ${_pkg}_include_dir_post_process) + cmake_language(CALL ${_pkg}_include_dir_post_process ${_pkg}_INCLUDE_DIR ${${_pkg}_INCLUDE_DIR}) + elseif(${_pkg}_INCLUDE_DIR_UP_INDEX) + foreach(_ RANGE 1 ${${_pkg}_INCLUDE_DIR_UP_INDEX}) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET ${_pkg}_INCLUDE_DIR PARENT_PATH ${_pkg}_INCLUDE_DIR) + else() + get_filename_component(${_pkg}_INCLUDE_DIR ${${_pkg}_INCLUDE_DIR} DIRECTORY) + endif() + endforeach() + endif() +endif() + +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_INCLUDE_DIR") + +# ------------------------------------------------------------------------ +# Extract version information from version.hpp +# ------------------------------------------------------------------------ + +if(${_pkg}_INCLUDE_DIR) + set(${_pkg}_HAS_VERSION + FALSE + CACHE BOOL "If ${_pkg} version was found" FORCE) + if(COMMAND ${_pkg}_version_function) + cmake_language(CALL ${_pkg}_version_function ${${_pkg}_INCLUDE_DIR}) + set(${_pkg}_HAS_VERSION + TRUE + CACHE BOOL "If ${_pkg} version was found" FORCE) + else() + set(_${_pkg}_version_file_list "${_${_pkg}_include_file}") + + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20.0) + cmake_path(GET ${_pkg}_INCLUDE_FILE STEM _${_pkg}_include_basename) + else() + get_filename_component(_${_pkg}_include_basename "${${_pkg}_INCLUDE_FILE}" NAME_WE) + endif() + + string(TOLOWER ${_pkg} _${_pkg}_lowercase) + set(_${_pkg}_inc_ver_ext h hh hpp hxx h++) + set(_${_pkg}_inc_ver_suffixes -version _version -config _config) + foreach(_${_pkg}_suffix ${_${pkg}_inc_ver_suffixes}) + foreach(_${_pkg}_ext ${_${_pkg}_inc_ver_ext}) + foreach(_${_pkg}_dir ${${_pkg}_INCLUDE_DIR} ${${_pkg}_INCLUDE_DIR}/${_${_pkg}_lowercase}) + set(_${_pkg}_fname "${_${_pkg}_dir}/${_${_pkg}_include_basename}${_${_pkg}_suffix}.${_${_pkg}_ext}") + if(EXISTS "${_${_pkg}_fname}") + list(APPEND _${_pkg}_version_file_list "${_${_pkg}_fname}") + endif() + endforeach() + endforeach() + endforeach() + + foreach(_${_pkg}_file ${_${_pkg}_version_file_list}) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Attempting to read library version from: ${_${_pkg}_file}") + + file(READ ${_${_pkg}_file} _${_pkg}_include_content) + string(REGEX MATCHALL "#define[ \t]+[a-zA-Z0-9_]+VERSION[a-zA-Z0-9_ ]+" _${_pkg}_version_defines + "${_${_pkg}_include_content}") + list(APPEND _${_pkg}_version_defines "") + + # Try to determine the version number using one of: + # + # * `#define PKG_VERSION X.Y.Z` + # * `#define PKG_VERSION X.Y` + # * `#define PKG_VERSION_{MAJOR,MINOR,PATCH,PATCHLEVEL} X` + # * `#define PKG_{MAJOR,MINOR,PATCH,PATCHLEVEL}_VERSION X` + # + # Note the special case where `#define PKG_VERSION X` is interpreted as MAJOR version number + + if("${_${_pkg}_version_defines}" MATCHES + ".*#define[ \t]+${${_pkg}_DEFINE_PREFIX}_VERSION[ \t]+([0-9]+)\\.([0-9]+)\\.*([0-9]+).*") + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + " version read from ${${_pkg}_DEFINE_PREFIX}_VERSION") + set(${_pkg}_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(${_pkg}_VERSION_MINOR ${CMAKE_MATCH_2}) + set(${_pkg}_VERSION_PATCH ${CMAKE_MATCH_3}) + set(${_pkg}_VERSION ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}) + break() + elseif("${_${_pkg}_version_defines}" MATCHES + ".*#define[ \t]+${${_pkg}_DEFINE_PREFIX}_VERSION[ \t]+([0-9]+)\\.([0-9]+).*") + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + " version read from ${${_pkg}_DEFINE_PREFIX}_VERSION") + set(${_pkg}_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(${_pkg}_VERSION_MINOR ${CMAKE_MATCH_2}) + set(${_pkg}_VERSION ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}) + break() + else() + # NB: for MAJOR versions we also look at the XXX_VERSION variable if its value consists of a single integer + set(_${_pkg}_MAJOR_NAMES ${${_pkg}_DEFINE_PREFIX}_MAJOR_VERSION ${${_pkg}_DEFINE_PREFIX}_VERSION_MAJOR + ${${_pkg}_DEFINE_PREFIX}_MAJOR ${${_pkg}_DEFINE_PREFIX}_VERSION) + set(_${_pkg}_MINOR_NAMES ${${_pkg}_DEFINE_PREFIX}_MINOR_VERSION ${${_pkg}_DEFINE_PREFIX}_VERSION_MINOR + ${${_pkg}_DEFINE_PREFIX}_MINOR) + set(_${_pkg}_PATCH_NAMES + ${${_pkg}_DEFINE_PREFIX}_PATCH_VERSION ${${_pkg}_DEFINE_PREFIX}_VERSION_PATCH + ${${_pkg}_DEFINE_PREFIX}_PATCH ${${_pkg}_DEFINE_PREFIX}_PATCHLEVEL_VERSION + ${${_pkg}_DEFINE_PREFIX}_VERSION_PATCHLEVEL) + + foreach(_${_pkg}_type MAJOR MINOR PATCH) + foreach(_var ${_${_pkg}_${_${_pkg}_type}_NAMES}) + if("${_${_pkg}_version_defines}" MATCHES "#define[ \t]+${_var}[ \t]+([0-9]+)[^\\.]") + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + " ${_${_pkg}_type} version read from ${_var}") + set(${_pkg}_VERSION_${_${_pkg}_type} ${CMAKE_MATCH_1}) + break() + endif() + endforeach() + endforeach() + if((NOT "${${_pkg}_VERSION_MAJOR}" STREQUAL "") AND (NOT "${${_pkg}_VERSION_MINOR}" STREQUAL "")) + break() + endif() + endif() + endforeach() + + if((NOT "${${_pkg}_VERSION_MAJOR}" STREQUAL "") AND (NOT "${${_pkg}_VERSION_MINOR}" STREQUAL "")) + set(${_pkg}_VERSION "${${_pkg}_VERSION_MAJOR}.${${_pkg}_VERSION_MINOR}") + if(NOT "${${_pkg}_VERSION_PATCH}" STREQUAL "") + set(${_pkg}_VERSION "${${_pkg}_VERSION}.${${_pkg}_VERSION_PATCH}") + endif() + set(${_pkg}_HAS_VERSION + TRUE + CACHE BOOL "If ${_pkg} version was found" FORCE) + endif() + endif() + + if(${_pkg}_HAS_VERSION) + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION_MAJOR") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION_MINOR") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION_PATCH") + endif() +endif() + +# ============================================================================== +# Begin finding ${_pkg} libraries + +set(_${_pkg}_VARS_LIB "") +foreach(config DEBUG RELEASE) + set(_${_pkg}_VARS_LIB_${config} ${_pkg}_LIBRARYDIR ${_pkg}_LIBRARY_DIR_${config}) + list(APPEND _${_pkg}_VARS_LIB ${_${_pkg}_VARS_LIB_${config}}) + _change_detect(_${_pkg}_CHANGE_LIBDIR_${config} ${_${_pkg}_VARS_DIR} ${_${_pkg}_VARS_LIB_${config}} + ${_pkg}_INCLUDE_DIR) + # Clear ${_pkg}_LIBRARY_DIR_${config} if it did not change but other input affecting the location did. We will find a + # new one based on the new inputs. + if(_${_pkg}_CHANGE_LIBDIR_${config} AND NOT _${_pkg}_LIBRARY_DIR_${config}_CHANGED) + unset(${_pkg}_LIBRARY_DIR_${config} CACHE) + endif() + + # If ${_pkg}_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value. + if(${_pkg}_LIBRARY_DIR_${config}) + set(_${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${${_pkg}_LIBRARY_DIR_${config}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + else() + set(_${_pkg}_LIBRARY_SEARCH_DIRS_${config} "") + if(${_pkg}_LIBRARYDIR) + list(APPEND _${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${${_pkg}_LIBRARYDIR}) + elseif(_ENV_${_pkg}_LIBRARYDIR) + list(APPEND _${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${_ENV_${_pkg}_LIBRARYDIR}) + endif() + + if(${_pkg}_ROOT) + list(APPEND _${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${${_pkg}_ROOT}) + _update_library_search_dirs_with_prebuilt_paths(_${_pkg}_LIBRARY_SEARCH_DIRS_${config} "${${_pkg}_ROOT}") + elseif(_ENV_${_pkg}_ROOT) + list(APPEND _${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${_ENV_${_pkg}_ROOT}) + _update_library_search_dirs_with_prebuilt_paths(_${_pkg}_LIBRARY_SEARCH_DIRS_${config} "${_ENV_${_pkg}_ROOT}") + endif() + + if(COMMAND ${_pkg}_library_search_dirs_from_include_path) + cmake_language(CALL ${_pkg}_library_search_dirs_from_include_path ${pkg}_INCLUDE_BASED_SEARCH_PATHS + ${${_pkg}_INCLUDE_DIR}) + else() + # Add some common cases + set(${_pkg}_INCLUDE_BASED_SEARCH_PATHS ${${_pkg}_INCLUDE_DIR} ${${_pkg}_INCLUDE_DIR}/.. + ${${_pkg}_INCLUDE_DIR}/../..) + endif() + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_INCLUDE_BASED_SEARCH_PATHS") + + foreach(_dir ${${_pkg}_INCLUDE_BASED_SEARCH_PATHS}) + list(APPEND _${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${_dir}) + _update_library_search_dirs_with_prebuilt_paths(_${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${_dir}) + endforeach() + + if(${_pkg}_NO_SYSTEM_PATHS) + list(APPEND _${_pkg}_LIBRARY_SEARCH_DIRS_${config} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + elseif(${_pkg}_LIB_SYSTEM_PATHS) + list(APPEND _${_pkg}_LIBRARY_SEARCH_DIRS_${config} PATHS ${${_pkg}_LIB_SYSTEM_PATHS}) + foreach(_dir ${${_pkg}_LIB_SYSTEM_PATHS}) + _update_library_search_dirs_with_prebuilt_paths(_${_pkg}_LIBRARY_SEARCH_DIRS_${config} ${_dir}) + endforeach() + endif() + endif() +endforeach() + +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_LIBRARY_SEARCH_DIRS_RELEASE") +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_LIBRARY_SEARCH_DIRS_DEBUG") + +# ------------------------------------------------------------------------------ +# Begin finding ${_pkg} executables + +set(_${_pkg}_VARS_EXEC ${_pkg}_EXECDIR ${_pkg}_EXECUTABLE_DIR) +_change_detect(_${_pkg}_CHANGE_EXECDIR ${_${_pkg}_VARS_DIR} ${_${_pkg}_VARS_EXEC}) +# Clear ${_pkg}_EXECUTABLE_DIR if it did not change but other input affecting the location did. We will find a new one +# based on the new inputs. +if(_${_pkg}_CHANGE_EXECDIR AND NOT _${_pkg}_EXECUTABLE_DIR_CHANGED) + unset(${_pkg}_EXECUTABLE_DIR CACHE) +endif() + +# If ${_pkg}_EXECUTABLE_DIR is set, prefer its value. +if(${_pkg}_EXECUTABLE_DIR) + set(_${_pkg}_EXECUTABLE_SEARCH_DIRS ${${_pkg}_EXECUTABLE_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) +else() + set(_${_pkg}_EXECUTABLE_SEARCH_DIRS "") + if(${_pkg}_EXECDIR) + list(APPEND _${_pkg}_EXECUTABLE_SEARCH_DIRS ${${_pkg}_EXECDIR}) + elseif(_ENV_${_pkg}_EXECDIR) + list(APPEND _${_pkg}_EXECUTABLE_SEARCH_DIRS ${_ENV_${_pkg}_EXECDIR}) + endif() + + if(${_pkg}_ROOT) + list(APPEND _${_pkg}_EXECUTABLE_SEARCH_DIRS ${${_pkg}_ROOT}) + _update_library_search_dirs_with_prebuilt_paths(_${_pkg}_EXECUTABLE_SEARCH_DIRS "${${_pkg}_ROOT}") + elseif(_ENV_${_pkg}_ROOT) + list(APPEND _${_pkg}_EXECUTABLE_SEARCH_DIRS ${_ENV_${_pkg}_ROOT}) + _update_library_search_dirs_with_prebuilt_paths(_${_pkg}_EXECUTABLE_SEARCH_DIRS "${_ENV_${_pkg}_ROOT}") + endif() + + if(COMMAND ${_pkg}_exec_search_dirs_from_include_path) + cmake_language(CALL ${_pkg}_exec_search_dirs_from_include_path ${pkg}_INCLUDE_BASED_SEARCH_PATHS + ${${_pkg}_INCLUDE_DIR}) + else() + # Add some common cases + set(${_pkg}_INCLUDE_BASED_SEARCH_PATHS ${${_pkg}_INCLUDE_DIR} ${${_pkg}_INCLUDE_DIR}/.. + ${${_pkg}_INCLUDE_DIR}/../..) + endif() + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_INCLUDE_BASED_SEARCH_PATHS") + + foreach(_dir ${${_pkg}_INCLUDE_BASED_SEARCH_PATHS}) + list(APPEND _${_pkg}_EXECUTABLE_SEARCH_DIRS ${_dir}) + _update_exec_search_dirs_with_prebuilt_paths(_${_pkg}_EXECUTABLE_SEARCH_DIRS ${_dir}) + endforeach() + + if(${_pkg}_NO_SYSTEM_PATHS) + list(APPEND _${_pkg}_EXECUTABLE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + elseif(${_pkg}_LIB_SYSTEM_PATHS) + list(APPEND _${_pkg}_EXECUTABLE_SEARCH_DIRS PATHS ${${_pkg}_LIB_SYSTEM_PATHS}) + foreach(_dir ${${_pkg}_LIB_SYSTEM_PATHS}) + _update_exec_search_dirs_with_prebuilt_paths(_${_pkg}_EXECUTABLE_SEARCH_DIRS ${_dir}) + endforeach() + endif() +endif() + +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_EXECUTABLE_SEARCH_DIRS") + +# ------------------------------------------------------------------------------ + +# Properly search for shared libraries on Windows with Visual Studio +if(${_pkg}_FIND_LIBRARY_SUFFIXES) + set(_${_pkg}_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${${_pkg}_FIND_LIBRARY_SUFFIXES}) +elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + set(_${_pkg}_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES .dll) +endif() + +# Additional components may be required via component dependencies. Add any missing components to the list. +_missing_dependencies(${_pkg}_FIND_COMPONENTS _${_pkg}_EXTRA_FIND_COMPONENTS) +_debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_${_pkg}_EXTRA_FIND_COMPONENTS") +_init_component_vars(${_pkg}_FIND_COMPONENTS) +_init_component_vars(_${_pkg}_EXTRA_FIND_COMPONENTS) + +# If the user changed any of our control inputs flush previous results. +if(_${_pkg}_CHANGE_LIBDIR_DEBUG OR _${_pkg}_CHANGE_LIBDIR_RELEASE) + foreach(COMPONENT ${_${_pkg}_COMPONENTS_SEARCHED}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + foreach(config DEBUG RELEASE) + set(_var ${_pkg}_${UPPERCOMPONENT}_LIBRARY_${config}) + unset(${_var} CACHE) + set(${_var} "${_var}-NOTFOUND") + endforeach() + endforeach() + set(_${_pkg}_COMPONENTS_SEARCHED "") +endif() + +if(_${_pkg}_CHANGE_EXECDIR) + foreach(COMPONENT ${_${_pkg}_COMPONENTS_SEARCHED}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + set(_var ${_pkg}_${UPPERCOMPONENT}_EXECUTABLE) + unset(${_var} CACHE) + set(${_var} "${_var}-NOTFOUND") + endforeach() + set(_${_pkg}_COMPONENTS_SEARCHED "") +endif() + +foreach(COMPONENT ${${_pkg}_FIND_COMPONENTS}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + + set(_${_pkg}_docstring_release "${_pkg} ${COMPONENT} library (release)") + set(_${_pkg}_docstring_debug "${_pkg} ${COMPONENT} library (debug)") + set(_${_pkg}_docstring_executable "${_pkg} ${COMPONENT} executable") + + if("${${_pkg}_${COMPONENT}_TYPE}" STREQUAL "LIBRARY") + if(${_pkg}_${COMPONENT}_NAMES) + set(${_pkg}_${COMPONENT}_RELEASE_NAMES ${${_pkg}_${COMPONENT}_NAMES}) + set(${_pkg}_${COMPONENT}_DEBUG_NAMES ${${_pkg}_${COMPONENT}_NAMES}) + endif() + + # Skip finding libraries if the component is header-only + if(${_pkg}_${COMPONENT}_HEADER_ONLY) + _adjust_lib_vars(${COMPONENT}) + continue() + endif() + + # + # Find RELEASE libraries + # + if(NOT ${_pkg}_${COMPONENT}_RELEASE_NAMES) + message(SEND_ERROR "Required CMake variable ${_pkg}_${COMPONENT}_RELEASE_NAMES not defined!") + endif() + set(_${_pkg}_RELEASE_NAMES ${${_pkg}_${COMPONENT}_RELEASE_NAMES}) + + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_${_pkg}_RELEASE_NAMES}") + + # if ${_pkg}_LIBRARY_DIR_RELEASE is not defined, but ${_pkg}_LIBRARY_DIR_DEBUG is, look there first for RELEASE libs + if(NOT ${_pkg}_LIBRARY_DIR_RELEASE AND ${_pkg}_LIBRARY_DIR_DEBUG) + list(INSERT _${_pkg}_LIBRARY_SEARCH_DIRS_RELEASE 0 ${${_pkg}_LIBRARY_DIR_DEBUG}) + endif() + + if(${_pkg}_USE_RELEASE_LIBS) + _find_library( + ${_pkg}_${UPPERCOMPONENT}_LIBRARY_RELEASE + RELEASE + NAMES + ${_${_pkg}_RELEASE_NAMES} + HINTS + ${_${_pkg}_LIBRARY_SEARCH_DIRS_RELEASE} + NAMES_PER_DIR + DOC + "${_${_pkg}_docstring_release}") + endif() + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "${_pkg}_${UPPERCOMPONENT}_LIBRARY_RELEASE") + + # + # Find DEBUG libraries + # + if(NOT ${_pkg}_${COMPONENT}_DEBUG_NAMES) + if(${_pkg}_${COMPONENT}_RELEASE_NAMES) + set(${_pkg}_${COMPONENT}_DEBUG_NAMES ${${_pkg}_${COMPONENT}_RELEASE_NAMES}) + else() + message(SEND_ERROR "Required CMake variable ${_pkg}_${COMPONENT}_DEBUG_NAMES not defined!") + endif() + endif() + set(_${_pkg}_DEBUG_NAMES ${${_pkg}_${COMPONENT}_DEBUG_NAMES}) + + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_${_pkg}_DEBUG_NAMES}") + + # if ${_pkg}_LIBRARY_DIR_DEBUG is not defined, but ${_pkg}_LIBRARY_DIR_RELEASE is, look there first for DEBUG libs + if(NOT ${_pkg}_LIBRARY_DIR_DEBUG AND ${_pkg}_LIBRARY_DIR_RELEASE) + list(INSERT _${_pkg}_LIBRARY_SEARCH_DIRS_DEBUG 0 ${${_pkg}_LIBRARY_DIR_RELEASE}) + endif() + + if(${_pkg}_USE_DEBUG_LIBS) + _find_library( + ${_pkg}_${UPPERCOMPONENT}_LIBRARY_DEBUG + DEBUG + NAMES + ${_${_pkg}_DEBUG_NAMES} + HINTS + ${_${_pkg}_LIBRARY_SEARCH_DIRS_DEBUG} + NAMES_PER_DIR + DOC + "${_${_pkg}_docstring_debug}") + endif() + _adjust_lib_vars(${UPPERCOMPONENT}) + else() + # + # Find executable + # + if(NOT ${_pkg}_${COMPONENT}_NAMES) + message(SEND_ERROR "Required CMake variable ${_pkg}_${COMPONENT}_NAMES not defined!") + endif() + set(_${_pkg}_NAMES ${${_pkg}_${COMPONENT}_NAMES}) + + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Searching for ${UPPERCOMPONENT}_EXECUTABLE: ${_${_pkg}_NAMES}") + + _find_program( + ${_pkg}_${UPPERCOMPONENT}_EXECUTABLE + NAMES + ${_${_pkg}_NAMES} + HINTS + ${_${_pkg}_EXECUTABLE_SEARCH_DIRS} + NAMES_PER_DIR + DOC + "${_${_pkg}_docstring_executable}") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_${UPPERCOMPONENT}_EXECUTABLE") + + if(${_pkg}_${UPPERCOMPONENT}_EXECUTABLE) + set(${_pkg}_${UPPERCOMPONENT}_FOUND ON) + endif() + + # Make variables changeable to the advanced user + mark_as_advanced(${_pkg}_${UPPERCOMPONENT}_EXECUTABLE) + endif() +endforeach() + +# Restore the original find library ordering +if(_${_pkg}_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_${_pkg}_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +# ------------------------------------------------------------------------ +# End finding ${_pkg} libraries/executable + +set(${_pkg}_INCLUDE_DIRS ${${_pkg}_INCLUDE_DIR}) +set(${_pkg}_LIBRARY_DIRS) +if(${_pkg}_LIBRARY_DIR_RELEASE) + list(APPEND ${_pkg}_LIBRARY_DIRS ${${_pkg}_LIBRARY_DIR_RELEASE}) +endif() +if(${_pkg}_LIBRARY_DIR_DEBUG) + list(APPEND ${_pkg}_LIBRARY_DIRS ${${_pkg}_LIBRARY_DIR_DEBUG}) +endif() +if(${_pkg}_LIBRARY_DIRS) + list(REMOVE_DUPLICATES ${_pkg}_LIBRARY_DIRS) +endif() +set(${_pkg}_EXECUTABLE_DIRS ${${_pkg}_EXECUTABLE_DIR}) + +# ============================================================================== +# Call FPHSA helper, see https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html + +# Define aliases as needed by the component handler in the FPHSA helper below +foreach(_comp IN LISTS ${_pkg}_FIND_COMPONENTS) + string(TOUPPER ${_comp} _uppercomp) + if(DEFINED ${_pkg}_${_uppercomp}_FOUND) + set(${_pkg}_${_comp}_FOUND ${${_pkg}_${_uppercomp}_FOUND}) + endif() + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_${_comp}_FOUND") +endforeach() + +if(NOT ${_pkg}_HAS_VERSION) + set(_${_pkg}_version_list) + + # Try to get version number from shared library extension on UNIX systems + foreach(_comp IN LISTS ${_pkg}_FIND_COMPONENTS) + string(TOUPPER ${_comp} _uppercomp) + if(${_pkg}_${_comp}_FOUND) + _extract_version_from_lib_name(${_pkg} "${${_pkg}_${_uppercomp}_LIBRARY}") + list(APPEND _${_pkg}_version_list ${${_pkg}_VERSION}) + endif() + endforeach() + list(REMOVE_DUPLICATES _${_pkg}_version_list) + list(LENGTH _${_pkg}_version_list _${_pkg}_L) + if(NOT _${_pkg}_L EQUAL 1) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Inconsistent version numbers: ${_${_pkg}_version_list}, ignoring all of them.") + set(${_pkg}_VERSION) + set(${_pkg}_VERSION_MAJOR) + set(${_pkg}_VERSION_MINOR) + set(${_pkg}_VERSION_PATCH) + set(${_pkg}_HAS_VERSION + FALSE + CACHE BOOL "If ${pkg_name} version was found" FORCE) + set(${_pkg}_HAS_VERSION FALSE) + endif() + + if(${_pkg}_HAS_VERSION) + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION_MAJOR") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION_MINOR") + _debug_print_var("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "${_pkg}_VERSION_PATCH") + endif() +endif() + +if(${_pkg}_HAS_VERSION) + find_package_handle_standard_args( + ${_pkg} + REQUIRED_VARS ${_pkg}_INCLUDE_DIR + VERSION_VAR ${_pkg}_VERSION + HANDLE_COMPONENTS) +else() + find_package_handle_standard_args( + ${_pkg} + REQUIRED_VARS ${_pkg}_INCLUDE_DIR + HANDLE_COMPONENTS) +endif() + +if(NOT ${_pkg}_FOUND) + # ${_pkg} headers were not found so no components were found. + foreach(COMPONENT ${${_pkg}_FIND_COMPONENTS}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + set(${_pkg}_${UPPERCOMPONENT}_FOUND FALSE) + endforeach() +endif() + +# ============================================================================== +# Add imported targets + +if(${_pkg}_FOUND) + # Look for external dependencies + foreach(_${_pkg}_dep ${${_pkg}_EXTERNAL_DEPENDENCIES}) + set(_${_pkg}_dep_found FALSE) + foreach(_found_var ${${_pkg}_EXTERNAL_DEPENDENCY_${_${_pkg}_dep}_FOUND_VARS}) + if(${_found_var}) + set(_${_pkg}_dep_found TRUE) + endif() + endforeach() + + if(NOT _${_pkg}_dep_found) + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Looking for external dependency: ${_${_pkg}_dep}") + set(_${_pkg}_find_dep_args) + if(${_pkg}_EXTERNAL_DEPENDENCY_${_${_pkg}_dep}_COMPONENTS) + list(APPEND _${_pkg}_find_dep_args COMPONENTS ${${_pkg}_EXTERNAL_DEPENDENCY_${_${_pkg}_dep}_COMPONENTS}) + endif() + + find_package(${_${_pkg}_dep} ${${_pkg}_EXTERNAL_DEPENDENCY_${_${_pkg}_dep}_FIND_ARGS} ${_${_pkg}_find_dep_args}) + else() + _debug_print("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "External dependency: ${_${_pkg}_dep} already found!") + endif() + endforeach() + + foreach(_comp ${${_pkg}_FIND_COMPONENTS}) + set(_${_pkg}_tgt ${${_pkg}_NAMESPACE}::${_comp}) + string(TOUPPER ${_comp} _uppercomp) + if(${_pkg}_${_uppercomp}_FOUND) + if("${${_pkg}_${_comp}_TYPE}" STREQUAL "LIBRARY") + if(NOT TARGET ${_${_pkg}_tgt}) + if(${_pkg}_${_comp}_HEADER_ONLY) + add_library(${_${_pkg}_tgt} INTERFACE IMPORTED) + else() + add_library(${_${_pkg}_tgt} SHARED IMPORTED) + endif() + endif() + + # Always reset the target properties (in case we are called multiple times) + set_target_properties( + ${_${_pkg}_tgt} + PROPERTIES INTERFACE_COMPILE_DEFINITIONS "" + INTERFACE_INCLUDE_DIRECTORIES "" + INTERFACE_LINK_LIBRARIES "") + + if(${_pkg}_TARGET_DEFINITIONS) + target_compile_definitions(${_${_pkg}_tgt} INTERFACE ${${_pkg}_TARGET_DEFINITIONS}) + endif() + if(${_pkg}_${_comp}_TARGET_DEFINITIONS) + target_compile_definitions(${_${_pkg}_tgt} INTERFACE ${${_pkg}_${_comp}_TARGET_DEFINITIONS}) + endif() + if(${_pkg}_INCLUDE_DIRS) + target_include_directories(${_${_pkg}_tgt} INTERFACE "${${_pkg}_INCLUDE_DIRS}") + endif() + if(EXISTS "${${_pkg}_${_uppercomp}_LIBRARY}") + set_target_properties(${_${_pkg}_tgt} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${${_pkg}_${_uppercomp}_LIBRARY}") + _windows_set_import_library_path(${_${_pkg}_tgt} IMPORTED_LOCATION) + endif() + if(EXISTS "${${_pkg}_${_uppercomp}_LIBRARY_RELEASE}") + set_property( + TARGET ${_${_pkg}_tgt} + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties( + ${${_pkg}_NAMESPACE}::${_comp} + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE + "${${_pkg}_${_uppercomp}_LIBRARY_RELEASE}") + _windows_set_import_library_path(${${_pkg}_NAMESPACE}::${_comp} IMPORTED_LOCATION RELEASE) + endif() + if(EXISTS "${${_pkg}_${_uppercomp}_LIBRARY_DEBUG}") + set_property( + TARGET ${${_pkg}_NAMESPACE}::${_comp} + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties( + ${${_pkg}_NAMESPACE}::${_comp} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${${_pkg}_${_uppercomp}_LIBRARY_DEBUG}") + _windows_set_import_library_path(${${_pkg}_NAMESPACE}::${_comp} IMPORTED_LOCATION DEBUG) + endif() + + if(${_pkg}_${_uppercomp}_DEPENDENCIES) + unset(_${_pkg}_${_uppercomp}_TARGET_DEPENDENCIES) + foreach(dep ${${_pkg}_${_comp}_DEPENDENCIES}) + list(APPEND _${_pkg}_${_uppercomp}_TARGET_DEPENDENCIES ${${_pkg}_NAMESPACE}::${dep}) + endforeach() + target_link_libraries(${${_pkg}_NAMESPACE}::${_comp} + INTERFACE "${_${_pkg}_${_uppercomp}_TARGET_DEPENDENCIES}") + endif() + + if(${_pkg}_${_comp}_EXTERNAL_DEPENDENCIES) + target_link_libraries(${${_pkg}_NAMESPACE}::${_comp} INTERFACE "${${_pkg}_${_comp}_EXTERNAL_DEPENDENCIES}") + endif() + else() + set(_${_pkg}_libtype SHARED) + foreach(_${_pkg}_lib "${${_pkg}_${_uppercomp}_LIBRARY_RELEASE}" "${${_pkg}_${_uppercomp}_LIBRARY_DEBUG}") + if(EXISTS "${_${_pkg}_lib}") + set(_${_pkg}_fname "${_${_pkg}_lib}") + break() + endif() + endforeach() + if(_${_pkg}_fname) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _${_pkg}_fname EXTENSION _${_pkg}_ext) + else() + get_filename_component(_${_pkg}_ext "${_${_pkg}_fname}" EXT) + endif() + if("${_${_pkg}_ext}" STREQUAL "${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(_${_pkg}_libtype STATIC) + endif() + endif() + + if(NOT TARGET ${_${_pkg}_tgt}) + add_executable(${_${_pkg}_tgt} ${_${_pkg}_libtype} IMPORTED) + endif() + endif() + + set_target_properties(${${_pkg}_NAMESPACE}::${_comp} PROPERTIES IMPORTED_LOCATION + "${${_pkg}_${_uppercomp}_EXECUTABLE}") + endif() + + list(APPEND ${_pkg}_IMPORTED_TARGETS ${${_pkg}_NAMESPACE}::${_comp}) + endforeach() +endif() +list(REMOVE_DUPLICATES ${_pkg}_IMPORTED_TARGETS) + +if(COMMAND ${_pkg}_post_process) + cmake_language(CALL ${_pkg}_post_process ${_pkg}) +endif() + +# ============================================================================== +# Finalize + +# Report ${_pkg}_LIBRARIES +set(${_pkg}_LIBRARIES "") +foreach(_comp IN LISTS ${_pkg}_FIND_COMPONENTS) + string(TOUPPER ${_comp} _uppercomp) + if(${_pkg}_${_uppercomp}_FOUND) + list(APPEND ${_pkg}_LIBRARIES ${${_pkg}_${_uppercomp}_LIBRARY}) + endif() +endforeach() +list(REMOVE_DUPLICATES ${_pkg}_LIBRARIES) + +# Configure display of cache entries in GUI. +foreach(var ${_pkg}ROOT ${_pkg}_ROOT ${_${_pkg}_VARS_INC} ${_${_pkg}_VARS_LIB}) + get_property( + _type + CACHE ${var} + PROPERTY TYPE) + if(_type) + set_property(CACHE ${var} PROPERTY ADVANCED 1) + if("x${_type}" STREQUAL "xUNINITIALIZED") + set_property(CACHE ${var} PROPERTY TYPE PATH) + endif() + endif() +endforeach() + +# Record last used values of input variables so we can detect on the next run if the user changed them. +foreach(var ${_${_pkg}_VARS_INC} ${_${_pkg}_VARS_LIB} ${_${_pkg}_VARS_DIR} ${_${_pkg}_VARS_NAME}) + if(DEFINED ${var}) + set(_${var}_LAST + "${${var}}" + CACHE INTERNAL "Last used ${var} value.") + else() + unset(_${var}_LAST CACHE) + endif() +endforeach() + +# Maintain a persistent list of components requested anywhere since the last flush. +set(_${_pkg}_COMPONENTS_SEARCHED "${_${_pkg}_COMPONENTS_SEARCHED}") +list(APPEND _${_pkg}_COMPONENTS_SEARCHED ${${_pkg}_FIND_COMPONENTS}) +list(REMOVE_DUPLICATES _${_pkg}_COMPONENTS_SEARCHED) +list(SORT _${_pkg}_COMPONENTS_SEARCHED) +set(_${_pkg}_COMPONENTS_SEARCHED + "${_${_pkg}_COMPONENTS_SEARCHED}" + CACHE INTERNAL "Components requested for this build tree.") + +# Restore project's policies +cmake_policy(POP) + +# ============================================================================== diff --git a/cmake/modules/_find_utils_begin.cmake b/cmake/modules/_find_utils_begin.cmake new file mode 100644 index 00000000000..062c8f990a0 --- /dev/null +++ b/cmake/modules/_find_utils_begin.cmake @@ -0,0 +1,34 @@ +# ============================================================================== +# +# Copyright 2022 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============================================================================== + +set(_find_utils_vars _pkg) + +# ============================================================================== +# find_utils_push() + +if(NOT DEFINED _find_utils_push_counter) + set(_find_utils_push_counter 0) +endif() + +math(EXPR _find_utils_push_counter "${_find_utils_push_counter}+1") + +foreach(_var ${_find_utils_vars}) + set(_${_var}_${_find_utils_push_counter} ${${_var}}) +endforeach() + +# ============================================================================== diff --git a/cmake/modules/_find_utils_end.cmake b/cmake/modules/_find_utils_end.cmake new file mode 100644 index 00000000000..88e0388ca49 --- /dev/null +++ b/cmake/modules/_find_utils_end.cmake @@ -0,0 +1,29 @@ +# ============================================================================== +# +# Copyright 2022 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============================================================================== + +include(FindTemplate) + +# ============================================================================== +# find_utils_pop() + +if("${_find_utils_push_counter}" GREATER "0") + foreach(_var ${_find_utils_vars}) + set(${_var} ${_${_var}_${_find_utils_push_counter}}) + endforeach() + math(EXPR _find_utils_push_counter "${_find_utils_push_counter}-1") +endif() diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 848ad7d3615..c11fce7e62e 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -27,7 +27,7 @@ if(DEFINED ENV{MSLIBS_CACHE_PATH}) else() set(_MS_LIB_CACHE ${CMAKE_BINARY_DIR}/.mslib) endif() -message("MS LIBS CACHE PATH: ${_MS_LIB_CACHE}") +message(STATUS "MS LIBS CACHE PATH: ${_MS_LIB_CACHE}") if(NOT EXISTS ${_MS_LIB_CACHE}) file(MAKE_DIRECTORY ${_MS_LIB_CACHE}) @@ -35,7 +35,7 @@ endif() if(DEFINED ENV{MSLIBS_SERVER} AND NOT ENABLE_GITEE) set(LOCAL_LIBS_SERVER $ENV{MSLIBS_SERVER}) - message("LOCAL_LIBS_SERVER: ${LOCAL_LIBS_SERVER}") + message(STATUS "LOCAL_LIBS_SERVER: ${LOCAL_LIBS_SERVER}") endif() include(ProcessorCount) @@ -50,7 +50,7 @@ else() set(THNUM ${JOBS}) endif() endif() -message("set make thread num: ${THNUM}") +message(STATUS "set make thread num: ${THNUM}") if(LOCAL_LIBS_SERVER) if(NOT ENV{no_proxy}) @@ -75,11 +75,12 @@ function(__download_pkg pkg_name pkg_url pkg_md5) URL ${pkg_url} URL_HASH MD5=${pkg_md5}) FetchContent_GetProperties(${pkg_name}) - message("download: ${${pkg_name}_SOURCE_DIR} , ${pkg_name} , ${pkg_url}") + message(STATUS "download: ${${pkg_name}_SOURCE_DIR} , ${pkg_name} , ${pkg_url}") if(NOT ${pkg_name}_POPULATED) FetchContent_Populate(${pkg_name}) + string(TOLOWER ${pkg_name} _pkg_name) set(${pkg_name}_SOURCE_DIR - ${${pkg_name}_SOURCE_DIR} + ${${_pkg_name}_SOURCE_DIR} PARENT_SCOPE) endif() @@ -100,85 +101,17 @@ function(__download_pkg_with_git pkg_name pkg_url pkg_git_commit pkg_md5) GIT_TAG ${pkg_git_commit}) endif() FetchContent_GetProperties(${pkg_name}) - message("download: ${${pkg_name}_SOURCE_DIR} , ${pkg_name} , ${pkg_url}") + message(STATUS "download: ${${pkg_name}_SOURCE_DIR} , ${pkg_name} , ${pkg_url}") if(NOT ${pkg_name}_POPULATED) FetchContent_Populate(${pkg_name}) + string(TOLOWER ${pkg_name} _pkg_name) set(${pkg_name}_SOURCE_DIR - ${${pkg_name}_SOURCE_DIR} + ${${_pkg_name}_SOURCE_DIR} PARENT_SCOPE) endif() endfunction() -function(__find_pkg_then_add_target pkg_name pkg_exe lib_path) - - unset(${pkg_name}_LIBS) - - message("_FIND:${${pkg_name}_BASE_DIR}") - - if(pkg_exe) - find_program( - ${pkg_exe}_EXE ${pkg_exe} - PATHS ${${pkg_name}_BASE_DIR}/bin - NO_DEFAULT_PATH) - if(NOT ${pkg_exe}_EXE) - return() - endif() - if(NOT TARGET ${pkg_name}::${pkg_exe}) - add_executable(${pkg_name}::${pkg_exe} IMPORTED GLOBAL) - set_target_properties(${pkg_name}::${pkg_exe} PROPERTIES IMPORTED_LOCATION ${${pkg_exe}_EXE}) - endif() - message("found ${${pkg_exe}_EXE}") - endif() - - foreach(_LIB_NAME ${ARGN}) - set(_LIB_SEARCH_NAME ${_LIB_NAME}) - set(_LIB_TYPE SHARED) - if(${pkg_name}_USE_STATIC_LIBS) - set(_LIB_SEARCH_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}${_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}") - set(_LIB_TYPE STATIC) - endif() - set(${_LIB_NAME}_LIB ${_LIB_NAME}_LIB-NOTFOUND) - if(APPLE) - find_library( - ${_LIB_NAME}_LIB ${_LIB_SEARCH_NAME} - PATHS ${${pkg_name}_BASE_DIR}/${lib_path} - NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) - else() - find_library( - ${_LIB_NAME}_LIB ${_LIB_SEARCH_NAME} - PATHS ${${pkg_name}_BASE_DIR}/${lib_path} - NO_DEFAULT_PATH) - endif() - if(NOT ${_LIB_NAME}_LIB) - return() - endif() - - add_library(${pkg_name}::${_LIB_NAME} ${_LIB_TYPE} IMPORTED GLOBAL) - if(WIN32 AND ${_LIB_TYPE} STREQUAL "SHARED") - set_target_properties(${pkg_name}::${_LIB_NAME} PROPERTIES IMPORTED_IMPLIB_RELEASE ${${_LIB_NAME}_LIB}) - else() - set_target_properties(${pkg_name}::${_LIB_NAME} PROPERTIES IMPORTED_LOCATION ${${_LIB_NAME}_LIB}) - endif() - - if(EXISTS ${${pkg_name}_BASE_DIR}/include) - set_target_properties(${pkg_name}::${_LIB_NAME} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - "${${pkg_name}_BASE_DIR}/include") - endif() - - list(APPEND ${pkg_name}_LIBS ${pkg_name}::${_LIB_NAME}) - message("found ${${_LIB_NAME}_LIB}") - string(REGEX REPLACE "(.+)/(.+)" "\\1" LIBPATH ${${_LIB_NAME}_LIB}) - set(${pkg_name}_LIBPATH - ${LIBPATH} - CACHE STRING INTERNAL) - endforeach() - - set(${pkg_name}_LIBS - ${${pkg_name}_LIBS} - PARENT_SCOPE) -endfunction() - function(__exec_cmd) set(options) set(oneValueArgs WORKING_DIRECTORY) @@ -201,7 +134,7 @@ function(__check_patches pkg_patches) file(TOUCH ${_MS_LIB_CACHE}/${pkg_name}_patch.md5) file(READ ${_MS_LIB_CACHE}/${pkg_name}_patch.md5 ${pkg_name}_PATCHES_MD5) - message("patches md5:${${pkg_name}_PATCHES_MD5}") + message(STATUS "patches md5:${${pkg_name}_PATCHES_MD5}") set(${pkg_name}_PATCHES_NEW_MD5) foreach(_PATCH ${PKG_PATCHES}) @@ -213,11 +146,26 @@ function(__check_patches pkg_patches) set(${pkg_name}_PATCHES ${PKG_PATCHES}) file(REMOVE_RECURSE "${_MS_LIB_CACHE}/${pkg_name}-subbuild") file(WRITE ${_MS_LIB_CACHE}/${pkg_name}_patch.md5 ${${pkg_name}_PATCHES_NEW_MD5}) - message("patches changed : ${${pkg_name}_PATCHES_NEW_MD5}") + message(STATUS "patches changed : ${${pkg_name}_PATCHES_NEW_MD5}") endif() endif() endfunction() +# ~~~ +# (helper function) Convert a path to CMake format +# +# to_cmake_path() +# ~~~ +macro(to_cmake_path path_var) + if(DEFINED ${path_var}) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(CONVERT "${${path_var}}" TO_CMAKE_PATH_LIST ${path_var} NORMALIZE) + else() + file(TO_CMAKE_PATH "${${path_var}}" ${path_var}) + endif() + endif() +endmacro() + # ~~~ # Create target aliases based on a list of key-value pairs where: # - key: target alias name @@ -242,7 +190,7 @@ function(__create_target_aliases) list(GET ARGN ${idx_1} tgt_name) if(NOT TARGET ${tgt_name}) - message(FATAL_ERROR "Target ${tgt_name} cannot be found!") + message(FATAL_ERROR "Target ${tgt_name} cannot be found, not defining ${tgt_alias} alias") endif() get_target_property(_aliased ${tgt_name} ALIASED_TARGET) @@ -256,14 +204,510 @@ function(__create_target_aliases) set_property(TARGET ${tgt_name} PROPERTY IMPORTED_GLOBAL TRUE) endif() + get_target_property(_aliased ${tgt_name} ALIASED_TARGET) + if(_aliased) + set(tgt_name ${_aliased}) + endif() + get_target_property(_type ${tgt_name} TYPE) - if(_type STREQUAL "EXECUTABLE") - message(STATUS "add_executable(${tgt_alias} ALIAS ${tgt_name})") + if("${_type}" STREQUAL "EXECUTABLE") add_executable(${tgt_alias} ALIAS ${tgt_name}) else() - message(STATUS "add_library(${tgt_alias} ALIAS ${tgt_name})") add_library(${tgt_alias} ALIAS ${tgt_name}) endif() + message(STATUS "Creating alias target: ${tgt_alias} -> ${tgt_name}") + endforeach() +endfunction() + +include(FindPackageHandleStandardArgs) +# Find a Python module in the current (potential virtual) environment +# +# __find_python_module( [REQUIRED|EXACT|QUIET] [VERSION ]) +# +# Usage is similar to the builtin find_package(...) +function(__find_python_module module) + # cmake-lint: disable=C0103 + cmake_parse_arguments(PARSE_ARGV 1 PYMOD "REQUIRED;EXACT;QUIET" "VERSION" "") + + string(REPLACE "-" "_" module_name ${module}) + string(TOUPPER ${module_name} MODULE) + if(NOT PYMOD_${MODULE}) + if(PYMOD_REQUIRED) + set(PYMOD_${module}_FIND_REQUIRED TRUE) + set(PYMOD_${MODULE}_FIND_REQUIRED TRUE) + endif() + if(PYMOD_QUIET) + set(PYMOD_${module}_FIND_QUIETLY TRUE) + set(PYMOD_${MODULE}_FIND_QUIETLY TRUE) + endif() + if(PYMOD_EXACT) + set(PYMOD_${module}_FIND_VERSION_EXACT TRUE) + set(PYMOD_${MODULE}_FIND_VERSION_EXACT TRUE) + endif() + if(PYMOD_VERSION) + set(PYMOD_${module}_FIND_VERSION ${PYMOD_VERSION}) + set(PYMOD_${MODULE}_FIND_VERSION ${PYMOD_VERSION}) + endif() + + execute_process( + COMMAND "${Python_EXECUTABLE}" "-c" "import os, ${module_name}; print(os.path.dirname(${module_name}.__file__))" + RESULT_VARIABLE _${MODULE}_status + OUTPUT_VARIABLE _${MODULE}_location + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT _${MODULE}_status) + set(PYMOD_${MODULE}_PATH + ${_${MODULE}_location} + CACHE STRING "Location of Python module ${module}") + + if(PYMOD_VERSION) + execute_process( + COMMAND "${Python_EXECUTABLE}" "-c" "import ${module_name}; print(${module_name}.__version__)" + RESULT_VARIABLE _${MODULE}_status + OUTPUT_VARIABLE _${MODULE}_version + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT _${MODULE}_status) + set(PYMOD_${MODULE}_VERSION + ${_${MODULE}_version} + CACHE STRING "Version of Python module ${module}") + set(PYMOD_${module}_VERSION + ${PYMOD_${MODULE}_VERSION} + CACHE STRING "Version of Python module ${module}") + endif() + endif() + endif() + endif() + + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND CMAKE_VERSION VERSION_LESS 3.20) + set(CMAKE_FIND_PACKAGE_NAME PYMOD_${module}) + endif() + + find_package_handle_standard_args( + PYMOD_${module_name} + REQUIRED_VARS PYMOD_${MODULE}_PATH + VERSION_VAR PYMOD_${MODULE}_VERSION NAME_MISMATCHED) + + set(PYMOD_${MODULE}_FOUND + ${PYMOD_${MODULE}_FOUND} + CACHE INTERNAL "") + + mark_as_advanced(PYMOD_${MODULE}_FOUND PYMOD_${MODULE}_PATH PYMOD_${MODULE}_VERSION) +endfunction() + +function(__largest_common_prefix a b prefix) + string(LENGTH "${a}" _len_a) + string(LENGTH "${b}" _len_b) + + if(${_len_a} LESS ${_len_b}) + set(_len ${_len_a}) + else() + set(_len ${_len_b}) + endif() + + # iterate over the length + foreach(end RANGE 1 ${_len}) + # get substrings + string(SUBSTRING "${a}" 0 ${end} sub_a) + string(SUBSTRING "${b}" 0 ${end} sub_b) + + if("${sub_a}" STREQUAL "${sub_b}") + set(${prefix} + ${sub_a} + PARENT_SCOPE) + else() + break() + endif() + endforeach() +endfunction() + +macro(__calculate_root_dir pkg_name) + if(NOT ${pkg_name}_ROOT) + if(${pkg_name}_DIR) + set(_root_dir ${${pkg_name}_DIR}) + foreach(_ RANGE 2) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _root_dir PARENT_PATH _root_dir) + else() + get_filename_component(_root_dir ${_root_dir} DIRECTORY) + endif() + endforeach() + else() + set(_targets ${PKG_LIBS_CMAKE_NAMES}) + list(GET ${_inc_location_var} 0 _inc_path) + if(NOT _inc_path) + unset(_inc_path) + endif() + list(GET _targets 0 _comp) + if(TARGET ${PKG_NS_NAME}::${_comp}) + set(_target_name ${PKG_NS_NAME}::${_comp}) + elseif(TARGET ${PKG_NS_NAME}::${PKG_NS_NAME}_${_comp}) + set(_target_name ${PKG_NS_NAME}::${PKG_NS_NAME}_${_comp}) + endif() + + foreach(_prop IMPORTED_LOCATION IMPORETD_LOCATION_DEBUG IMPORTED_LOCATION_RELEASE IMPORTED_LOCATION_NONE + IMPORTED_LOCATION_NOCONFIG INTERFACE_LINK_LIBRARIES) + get_target_property(_imported_location ${_target_name} ${_prop}) + if(_imported_location) + file(TO_CMAKE_PATH "${_imported_location}" _imported_location) + break() + endif() + endforeach() + if(_imported_location) + list(GET _imported_location 0 _lib_path) + endif() + + if((NOT "${_inc_path}" STREQUAL "") AND (NOT "${_lib_path}" STREQUAL "")) + __largest_common_prefix("${_inc_path}" "${_lib_path}" _root_dir) + elseif(NOT "${_lib_path}" STREQUAL "") + set(_root_dir ${_lib_path}) + foreach(_ RANGE 1) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _root_dir PARENT_PATH _root_dir) + else() + get_filename_component(_root_dir ${_root_dir} DIRECTORY) + endif() + endforeach() + endif() + endif() + set(${pkg_name}_ROOT + ${_root_dir} + PARENT_SCOPE) + endif() +endmacro() + +function(__get_imported_location_from_interface_library tgt) + set(_basename ${tgt}) + if(_tgt MATCHES "([a-zA-Z0-9_]+)::([a-zA-Z0-9_]+)") + set(_basename ${CMAKE_MATCH_2}) + string(TOLOWER ${CMAKE_MATCH_2} _basename_lower) + endif() + + set(_imported_location) + get_target_property(_libs ${_tgt} INTERFACE_LINK_LIBRARIES) + if(_libs) + foreach(_lib ${_libs}) + if(_lib MATCHES ".*${_basename}.*" OR _lib MATCHES ".*${_basename_lower}.*") + set(_imported_location "${_lib}") + break() + endif() + endforeach() + endif() + set(_imported_location + "${_imported_location}" + PARENT_SCOPE) +endfunction() + +function(__generate_pseudo_cmake_package_config dest_dir pkg_name pkg_namespace pkg_libs pkg_exe) + + set(_comps ${pkg_libs}) + if(pkg_exe) + list(APPEND _comps ${pkg_exe}) + endif() + + find_package( + ${pkg_name} QUIET + COMPONENTS ${_comps} + REQUIRED) + + # ---------------------------------------------------------------------------- + + set(tgt_list) + foreach(_comp ${_comps}) + if(TARGET ${pkg_namespace}::${_comp}) + list(APPEND tgt_list ${pkg_namespace}::${_comp}) + endif() + if(TARGET ${pkg_namespace}::${PKG_NS_NAME}_${_comp}) + list(APPEND tgt_list ${pkg_namespace}::${PKG_NS_NAME}_${_comp}) + endif() + endforeach() + + # ---------------------------------------------------------------------------- + + file(MAKE_DIRECTORY ${dest_dir}) + string(REPLACE ";" "\;" tgt_list_escaped "${tgt_list}") + + # ---------------------------------------------------------------------------- + + set(_config_version_content + " +set(PACKAGE_VERSION \"${PKG_VER}\") + +if (PACKAGE_FIND_VERSION_RANGE) + # Package version must be in the requested version range + if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL \"INCLUDE\" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN) + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL \"INCLUDE\" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL \"EXCLUDE\" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + endif() +else() + if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() +") + file(WRITE ${dest_dir}/${pkg_name}ConfigVersion.cmake ${_config_version_content}) + + # ---------------------------------------------------------------------------- + + set(_config_content "include (\"\${CMAKE_CURRENT_LIST_DIR}/${pkg_name}Targets.cmake\")\n") + file(WRITE ${dest_dir}/${pkg_name}Config.cmake ${_config_content}) + + # ---------------------------------------------------------------------------- + + set(_targets_prefix_content + " +cmake_policy(PUSH) +cmake_policy(VERSION 2.6...3.20) + +set(CMAKE_IMPORT_FILE_VERSION 1) + +") + + set(_targets_suffix_content + " + +if(CMAKE_VERSION VERSION_LESS 3.0.0) + message(FATAL_ERROR \"This file relies on consumers using CMake 3.0.0 or greater.\") +endif() + +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) +") + + foreach(_tgt ${tgt_list}) + if(NOT TARGET ${_tgt}) + continue() + endif() + + get_target_property(_libs ${_tgt} INTERFACE_LINK_LIBRARIES) + if(_libs) + foreach(_lib ${_libs}) + if(_lib MATCHES "([a-zA-Z0-9_]+)::([a-zA-Z0-9_]+)") + set(_ns ${CMAKE_MATCH_1}) + set(_tgt ${CMAKE_MATCH_2}) + + if("${_ns}" STREQUAL "${ns}" AND TARGET ${_lib}) + list(PREPEND tgt_list ${_lib}) + endif() + endif() + endforeach() + endif() + endforeach() + + set(_tgt_props + COMPILE_DEFINITIONS + COMPILE_FEATURES + COMPILE_OPTIONS + INCLUDE_DIRECTORIES + LINK_OPTIONS + LINK_LIBRARIES + INTERFACE_COMPILE_DEFINITIONS + INTERFACE_COMPILE_FEATURES + INTERFACE_COMPILE_OPTIONS + INTERFACE_INCLUDE_DIRECTORIES + INTERFACE_LINK_OPTIONS + INTERFACE_LINK_LIBRARIES + IMPORTED_CONFIGURATIONS + IMPORTED_SONAME + IMPORTED_SONAME_DEBUG + IMPORTED_SONAME_RELEASE + IMPORTED_LOCATION + IMPORTED_LOCATION_DEBUG + IMPORTED_LOCATION_RELEASE + IMPORTED_LOCATION_NONE + IMPORTED_LOCATION_NOCONFIG) + + set(_library_content) + foreach(_tgt ${tgt_list}) + if(NOT TARGET ${_tgt}) + continue() + endif() + + list(APPEND _library_content "if(NOT TARGET ${_tgt})\n") + + get_target_property(_type ${_tgt} TYPE) + if("${_type}" STREQUAL "EXECUTABLE") + list(APPEND _library_content " add_executable(${_tgt} IMPORTED)\n") + elseif("${_type}" STREQUAL "UNKNOWN_LIBRARY") + list(APPEND _library_content " add_library(${_tgt} UNKNOWN IMPORTED)\n") + elseif("${_type}" STREQUAL "INTERFACE_LIBRARY") + list(APPEND _library_content " add_library(${_tgt} UNKNOWN IMPORTED)\n") + __get_imported_location_from_interface_library(${_tgt}) + if(_imported_location) + list(APPEND _library_content "\n set_target_properties(${_tgt} PROPERTIES\n") + list(APPEND _library_content " IMPORTED_LOCATION \"${_imported_location}\"") + list(APPEND _library_content " )\n") + endif() + elseif("${_type}" STREQUAL "STATIC_LIBRARY") + list(APPEND _library_content " add_library(${_tgt} STATIC IMPORTED)\n") + elseif("${_type}" STREQUAL "SHARED_LIBRARY") + list(APPEND _library_content " add_library(${_tgt} SHARED IMPORTED)\n") + endif() + + list(APPEND _library_content "\n set_target_properties(${_tgt} PROPERTIES\n") + foreach(_prop ${_tgt_props}) + get_target_property(_val ${_tgt} ${_prop}) + if(_val) + if(_imported_location) + list(REMOVE_ITEM _val "${_imported_location}") + endif() + string(REPLACE ";" "\;" _val "${_val}") + list(APPEND _library_content " ${_prop} \"${_val}\"\n") + endif() + endforeach() + list(APPEND _library_content " )\n\n\n") + + list(APPEND _library_content "endif()\n") + endforeach() + + if(_${pkg}_COMPONENTS_SEARCHED) + string(REPLACE ";" "\;" _val "${_${pkg}_COMPONENTS_SEARCHED}") + list(APPEND _library_content "set(_${pkg}_COMPONENTS_SEARCHED ${_val})\n\n\n") + endif() + + file(WRITE ${dest_dir}/${pkg_name}Targets.cmake ${_targets_prefix_content} ${_library_content} + ${_targets_suffix_content}) +endfunction() + +if(MS_PREFER_SYSTEM_PKGS) + string(TOLOWER ${MS_PREFER_SYSTEM_PKGS} _val) + if("${_val}" STREQUAL "all") + set(MS_PREFER_SYSTEM_PKGS ON) + elseif( + NOT + ("${_val}" STREQUAL "on" + OR "${_val}" STREQUAL "true" + OR "${_val}" STREQUAL "1" + OR "${_val}" STREQUAL "off" + OR "${_val}" STREQUAL "false" + OR "${_val}" STREQUAL "0")) + string(REPLACE "," ";" MS_PREFER_SYSTEM_PKGS ${MS_PREFER_SYSTEM_PKGS}) + foreach(_name ${MS_PREFER_SYSTEM_PKGS}) + string(TOUPPER ${_name} _name) + set(MS_${_name}_PREFER_SYSTEM ON) + message(STATUS "MS_${_name}_PREFER_SYSTEM = ${MS_${_name}_PREFER_SYSTEM}") + endforeach() + set(MS_PREFER_SYSTEM_PKGS "") + endif() +endif() + +macro( + __find_package + pkg_name + PKG_VER + PKG_LIBS + PKG_LIBS_CMAKE_NAMES + PKG_EXE + PKG_CMAKE_PKG_NO_COMPONENTS + PKG_NS_NAME + PKG_TARGET_ALIAS + search_name) + message(CHECK_START "Looking ${pkg_name} using CMake find_package(): ${search_name}") + list(APPEND CMAKE_MESSAGE_INDENT " ") + + set(pkg_name ${pkg_name}) + string(TOUPPER ${pkg_name} PKG_NAME) + + set(_find_package_args) + if(PKG_FORCE_EXACT_VERSION) + list(APPEND _find_package_args EXACT) + endif() + + if(NOT PKG_CMAKE_PKG_NO_COMPONENTS AND (PKG_LIBS OR PKG_EXE)) + list(APPEND _find_package_args COMPONENTS) + if(PKG_LIBS) + list(APPEND _find_package_args ${PKG_LIBS_CMAKE_NAMES}) + endif() + if(PKG_EXE) + list(APPEND _find_package_args ${PKG_EXE}) + endif() + endif() + # Prefer system installed libraries instead of compiling everything from source + if(${pkg_name}_DEBUG) + message(STATUS "find_package(${pkg_name} ${PKG_VER} ${_find_package_args} ${ARGN})") + endif() + find_package(${pkg_name} ${PKG_VER} ${_find_package_args} ${ARGN}) + if(${pkg_name}_FOUND) + set(_inc_location_var) + if(NOT "${${pkg_name}_INCLUDE_DIRS}" STREQUAL "") + set(_inc_location_var ${pkg_name}_INCLUDE_DIRS) + elseif(NOT "${${pkg_name}_INCLUDE_DIR}" STREQUAL "") + set(_inc_location_var ${pkg_name}_INCLUDE_DIR) + else() + set(_targets ${PKG_LIBS_CMAKE_NAMES}) + if(PKG_EXE) + list(APPEND _targets ${PKG_EXE}) + endif() + + set(_inc_location_var _inc_dirs) + set(_inc_dirs) + foreach(_comp ${_targets}) + if(TARGET ${PKG_NS_NAME}::${_comp}) + set(_target_name ${PKG_NS_NAME}::${_comp}) + elseif(TARGET ${PKG_NS_NAME}::${PKG_NS_NAME}_${_comp}) + set(_target_name ${PKG_NS_NAME}::${PKG_NS_NAME}_${_comp}) + endif() + if(_target_name) + foreach(_prop INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(_dir ${_target_name} ${_prop}) + if(_dir) + break() + endif() + endforeach() + if(_dir) + list(APPEND _inc_dirs "${_dir}") + endif() + endif() + endforeach() + list(REMOVE_DUPLICATES _inc_dirs) + endif() + set(${pkg_name}_INC + ${${_inc_location_var}} + PARENT_SCOPE) + + __calculate_root_dir(${pkg_name}) + + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "Done") + else() + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_FAIL "Failed") + endif() +endmacro() + +function(__check_package_location pkg_name pkg_namespace) + file(TO_CMAKE_PATH "${${pkg_name}_BASE_DIR}" _base_dir) + set(_tgt_list) + foreach(_comp ${ARGN}) + set(_tgt ${pkg_namespace}::${_comp}) + if(TARGET ${_tgt}) + foreach(_prop IMPORTED_LOCATION IMPORETD_LOCATION_DEBUG IMPORTED_LOCATION_RELEASE IMPORTED_LOCATION_NONE + IMPORTED_LOCATION_NOCONFIG) + get_target_property(_imported_location ${_tgt} ${_prop}) + if(_imported_location) + file(TO_CMAKE_PATH "${_imported_location}" _imported_location) + break() + endif() + endforeach() + if(_imported_location) + string(FIND "${_imported_location}" "${_base_dir}" _idx) + if(_idx LESS 0) + message( + FATAL_ERROR + "Imported location of ${_tgt} not found in ${_base_dir}! +- ${_imported_location} +Please clear up CMake cache (${CMAKE_CURRENT_BINARY_DIR}/CMakeCache.txt and re-run CMake.") + endif() + endif() + endif() endforeach() endfunction() @@ -279,7 +723,7 @@ set(MS_FIND_NO_DEFAULT_PATH ${MS_FIND_NO_DEFAULT_PATH} PARENT_SCOPE) function(mindspore_add_pkg pkg_name) - set(options) + set(options FORCE_EXACT_VERSION CMAKE_PKG_NO_COMPONENTS GEN_CMAKE_CONFIG BUILD_OPTION_PASS_PREFIX) set(oneValueArgs URL MD5 @@ -296,6 +740,8 @@ function(mindspore_add_pkg pkg_name) set(multiValueArgs CMAKE_OPTION LIBS + LIBS_CMAKE_NAMES + FORCE_CONFIG_SEARCH PRE_CONFIGURE_COMMAND CONFIGURE_COMMAND BUILD_OPTION @@ -307,7 +753,8 @@ function(mindspore_add_pkg pkg_name) ONLY_MAKE ONLY_MAKE_INCS ONLY_MAKE_LIBS - TARGET_ALIAS) + TARGET_ALIAS + PREFIX_VARS) cmake_parse_arguments(PKG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT PKG_LIB_PATH) @@ -318,44 +765,63 @@ function(mindspore_add_pkg pkg_name) set(PKG_EXE 0) endif() - set(__FIND_PKG_NAME ${pkg_name}) + if(NOT PKG_NS_NAME) + set(PKG_NS_NAME ${pkg_name}) + endif() + + if(PKG_HEAD_ONLY) + set(PKG_LIBS ${PKG_HEAD_ONLY}) + endif() + + if(NOT PKG_LIBS_CMAKE_NAMES) + set(PKG_LIBS_CMAKE_NAMES ${PKG_LIBS}) + else() + list(LENGTH PKG_LIBS _N_libs) + list(LENGTH PKG_LIBS_CMAKE_NAMES _N_libs_cmake_names) + if(NOT _N_libs EQUAL _N_libs_cmake_names) + message(FATAL_ERROR "Number of values for LIBS and LIBS_CMAKE_NAMES should be identical!") + endif() + endif() + string(TOUPPER ${pkg_name} PKG_NAME) - string(TOLOWER ${pkg_name} pkg_name) - message(CHECK_START "Looking for ${__FIND_PKG_NAME},${pkg_name}") - if(MS_PREFER_LOCAL_PKG OR MS_${PKG_NAME}_PREFER_LOCAL) - # Prefer system installed libraries instead of compiling everything from source + message(CHECK_START "Adding external dependency: ${pkg_name}") + list(APPEND CMAKE_MESSAGE_INDENT " ") - # TODO(dnguyen): Is this really required? + if(MS_PREFER_SYSTEM_PKGS OR MS_${PKG_NAME}_PREFER_SYSTEM) + set(_args) + if(PKG_FORCE_CONFIG_SEARCH) + list(APPEND _args CONFIG) + endif() + __find_package( + "${pkg_name}" + "${PKG_VER}" + "${PKG_LIBS}" + "${PKG_LIBS_CMAKE_NAMES}" + "${PKG_EXE}" + "${PKG_CMAKE_PKG_NO_COMPONENTS}" + "${PKG_NS_NAME}" + "${PKG_TARGET_ALIAS}" + "system packages" + ${_args}) - # check options - set(${pkg_name}_CONFIG_TXT - "${CMAKE_CXX_COMPILER_VERSION}-${CMAKE_C_COMPILER_VERSION} - ${ARGN} - ${${pkg_name}_USE_STATIC_LIBS}- ${${pkg_name}_PATCHES_HASH} - ${${pkg_name}_CXXFLAGS}--${${pkg_name}_CFLAGS}--${${pkg_name}_LDFLAGS}") - string(REPLACE ";" "-" ${pkg_name}_CONFIG_TXT ${${pkg_name}_CONFIG_TXT}) - string(MD5 ${pkg_name}_CONFIG_HASH ${${pkg_name}_CONFIG_TXT}) - - if(PKG_HEAD_ONLY) - # ~~~ - # 1. Find package using CMake discovery - # 2. Set target aliases - # ~~~ - set(${pkg_name}_INC - ${${pkg_name}_BASE_DIR}/${PKG_HEAD_ONLY} - PARENT_SCOPE) - add_library(${pkg_name} INTERFACE) - target_include_directories(${pkg_name} INTERFACE ${${pkg_name}_INC}) - if(${PKG_RELEASE}) - __find_pkg_then_add_target(${pkg_name} ${PKG_EXE} ${PKG_LIB_PATH} ${PKG_LIBS}) + if(${pkg_name}_FOUND) + if(${pkg_name}_DIR) + message(STATUS "Package CMake config dir: ${${pkg_name}_DIR}") endif() + __create_target_aliases(${PKG_TARGET_ALIAS}) + + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "Done") + return() else() - file(WRITE ${${pkg_name}_BASE_DIR}/options.txt ${${pkg_name}_CONFIG_TXT}) - message("${pkg_name}_SOURCE_DIR : ${${pkg_name}_SOURCE_DIR}") + # Cleanup potential variables + foreach(_var_suffix INCLUDE_DIR INCLUDE_DIRS LIBRARIES) + set(var ${pkg_name}_${_var_suffix}) + endforeach() endif() - __create_target_aliases(${PKG_TARGET_ALIAS}) - return() + # Otherwise we try to compile from source endif() # ============================================================================== @@ -382,42 +848,30 @@ function(mindspore_add_pkg pkg_name) ${${pkg_name}_BASE_DIR} CACHE STRING INTERNAL) - if(EXISTS ${${pkg_name}_BASE_DIR}/options.txt AND PKG_HEAD_ONLY) - set(${pkg_name}_INC - ${${pkg_name}_BASE_DIR}/${PKG_HEAD_ONLY} - PARENT_SCOPE) - add_library(${pkg_name} INTERFACE) - target_include_directories(${pkg_name} INTERFACE ${${pkg_name}_INC}) - if(${PKG_RELEASE}) - __find_pkg_then_add_target(${pkg_name} ${PKG_EXE} ${PKG_LIB_PATH} ${PKG_LIBS}) - endif() - __create_target_aliases(${PKG_TARGET_ALIAS}) - return() - endif() - - set(${__FIND_PKG_NAME}_ROOT ${${pkg_name}_BASE_DIR}) - set(${__FIND_PKG_NAME}_ROOT - ${${pkg_name}_BASE_DIR} - PARENT_SCOPE) - - if(PKG_LIBS) - __find_pkg_then_add_target(${pkg_name} ${PKG_EXE} ${PKG_LIB_PATH} ${PKG_LIBS}) - if(${pkg_name}_LIBS) - set(${pkg_name}_INC - ${${pkg_name}_BASE_DIR}/include - PARENT_SCOPE) - message("Found libs: ${${pkg_name}_LIBS}") - __create_target_aliases(${PKG_TARGET_ALIAS}) - return() - endif() - elseif(NOT PKG_HEAD_ONLY) - find_package(${__FIND_PKG_NAME} ${PKG_VER} ${MS_FIND_NO_DEFAULT_PATH}) - if(${__FIND_PKG_NAME}_FOUND) - set(${pkg_name}_INC - ${${pkg_name}_BASE_DIR}/include - PARENT_SCOPE) - message("Found pkg: ${__FIND_PKG_NAME}") + if(EXISTS "${${pkg_name}_BASE_DIR}") + __find_package( + "${pkg_name}" + "${PKG_VER}" + "${PKG_LIBS}" + "${PKG_LIBS_CMAKE_NAMES}" + "${PKG_EXE}" + "${PKG_CMAKE_PKG_NO_COMPONENTS}" + "${PKG_NS_NAME}" + "${PKG_TARGET_ALIAS}" + "MindSpore build dir" + CONFIG + ${MS_FIND_NO_DEFAULT_PATH} + PATHS + "${${pkg_name}_BASE_DIR}") + if(${pkg_name}_FOUND) + if(${pkg_name}_DIR) + message(STATUS "Package CMake config dir: ${${pkg_name}_DIR}") + endif() + __check_package_location(${pkg_name} ${PKG_NS_NAME} ${PKG_LIBS_CMAKE_NAMES} ${PKG_EXE}) __create_target_aliases(${PKG_TARGET_ALIAS}) + + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "Done") return() endif() endif() @@ -438,7 +892,7 @@ function(mindspore_add_pkg pkg_name) set(${pkg_name}_SOURCE_DIR ${PKG_DIR}) endif() file(WRITE ${${pkg_name}_BASE_DIR}/options.txt ${${pkg_name}_CONFIG_TXT}) - message("${pkg_name}_SOURCE_DIR : ${${pkg_name}_SOURCE_DIR}") + message(STATUS "${pkg_name}_SOURCE_DIR : ${${pkg_name}_SOURCE_DIR}") foreach(_PATCH_FILE ${PKG_PATCHES}) get_filename_component(_PATCH_FILE_NAME ${_PATCH_FILE} NAME) @@ -448,7 +902,7 @@ function(mindspore_add_pkg pkg_name) NEWLINE_STYLE LF @ONLY) - message("patching ${${pkg_name}_SOURCE_DIR} -p1 < ${_LF_PATCH_FILE}") + message(STATUS "patching ${${pkg_name}_SOURCE_DIR} -p1 < ${_LF_PATCH_FILE}") execute_process( COMMAND ${Patch_EXECUTABLE} -p1 INPUT_FILE ${_LF_PATCH_FILE} @@ -477,18 +931,7 @@ function(mindspore_add_pkg pkg_name) endif() if(${pkg_name}_SOURCE_DIR) - if(PKG_HEAD_ONLY) - file(GLOB ${pkg_name}_SOURCE_SUBDIRS ${${pkg_name}_SOURCE_DIR}/*) - file(COPY ${${pkg_name}_SOURCE_SUBDIRS} DESTINATION ${${pkg_name}_BASE_DIR}) - set(${pkg_name}_INC - ${${pkg_name}_BASE_DIR}/${PKG_HEAD_ONLY} - PARENT_SCOPE) - if(NOT PKG_RELEASE) - add_library(${pkg_name} INTERFACE) - target_include_directories(${pkg_name} INTERFACE ${${pkg_name}_INC}) - endif() - - elseif(PKG_ONLY_MAKE) + if(PKG_ONLY_MAKE) __exec_cmd(COMMAND ${CMAKE_MAKE_PROGRAM} ${${pkg_name}_CXXFLAGS} -j${THNUM} WORKING_DIRECTORY ${${pkg_name}_SOURCE_DIR}) set(PKG_INSTALL_INCS ${PKG_ONLY_MAKE_INCS}) @@ -590,6 +1033,9 @@ function(mindspore_add_pkg pkg_name) ${${pkg_name}_SOURCE_DIR}) endif() set(${pkg_name}_BUILD_OPTION ${PKG_BUILD_OPTION}) + if(PKG_BUILD_OPTION_PASS_PREFIX) + set(${pkg_name}_BUILD_OPTION ${${pkg_name}_BUILD_OPTION} PREFIX="${${pkg_name}_BASE_DIR}") + endif() if(NOT PKG_CONFIGURE_COMMAND) set(${pkg_name}_BUILD_OPTION ${${pkg_name}_BUILD_OPTION} ${${pkg_name}_MAKE_CFLAGS} ${${pkg_name}_MAKE_CXXFLAGS} ${${pkg_name}_MAKE_LDFLAGS}) @@ -614,24 +1060,40 @@ function(mindspore_add_pkg pkg_name) endif() endif() - if(PKG_LIBS) - __find_pkg_then_add_target(${pkg_name} ${PKG_EXE} ${PKG_LIB_PATH} ${PKG_LIBS}) - set(${pkg_name}_INC - ${${pkg_name}_BASE_DIR}/include - PARENT_SCOPE) - if(NOT ${pkg_name}_LIBS) - message(FATAL_ERROR "Can not find pkg: ${pkg_name}") - endif() - else() - find_package(${__FIND_PKG_NAME} ${PKG_VER} QUIET ${MS_FIND_NO_DEFAULT_PATH}) - if(${__FIND_PKG_NAME}_FOUND) - set(${pkg_name}_INC - ${${pkg_name}_BASE_DIR}/include - PARENT_SCOPE) - message("Found pkg: ${${__FIND_PKG_NAME}_LIBRARIES}") - __create_target_aliases(${PKG_TARGET_ALIAS}) - return() - endif() + if(PKG_GEN_CMAKE_CONFIG) + set(_cmake_data_dir ${${pkg_name}_BASE_DIR}/${pkg_name}/share/${pkg_name}) + + message(STATUS "Generating fake CMake config file...") + + list(PREPEND CMAKE_PREFIX_PATH "${${pkg_name}_BASE_DIR}") + set(${PKG_NAME}_ROOT "${${pkg_name}_BASE_DIR}") + set(${pkg_name}_ROOT "${${pkg_name}_BASE_DIR}") + __generate_pseudo_cmake_package_config("${_cmake_data_dir}" ${pkg_name} ${PKG_NS_NAME} "${PKG_LIBS_CMAKE_NAMES}" + "${PKG_EXE}") + list(POP_FRONT CMAKE_PREFIX_PATH) endif() + + __find_package( + "${pkg_name}" + "${PKG_VER}" + "${PKG_LIBS}" + "${PKG_LIBS_CMAKE_NAMES}" + "${PKG_EXE}" + "${PKG_CMAKE_PKG_NO_COMPONENTS}" + "${PKG_NS_NAME}" + "${PKG_TARGET_ALIAS}" + "MindSpore build dir" + REQUIRED + CONFIG + ${MS_FIND_NO_DEFAULT_PATH} + HINTS + "${${pkg_name}_BASE_DIR}") + if(${pkg_name}_DIR) + message(STATUS "Package CMake config dir: ${${pkg_name}_DIR}") + endif() + __check_package_location(${pkg_name} ${PKG_NS_NAME} ${PKG_LIBS_CMAKE_NAMES} ${PKG_EXE}) __create_target_aliases(${PKG_TARGET_ALIAS}) + + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "Done") endfunction()