diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e00a4f1..6906bb45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,8 @@ macro(tristate_option opt help) endif() endmacro() +set(ZNC_CMAKE_FIND_DEPS "") + tristate_option(OPENSSL "Support SSL") if(WANT_OPENSSL) find_package(OpenSSL ${TRISTATE_OPENSSL_REQUIRED}) @@ -95,6 +97,8 @@ if(WANT_OPENSSL) HAVE_SSL_SESSION_get0_cipher) endfunction() check_SSL_SESSION_get0_cipher() + set(ZNC_CMAKE_FIND_DEPS + "${ZNC_CMAKE_FIND_DEPS}\nfind_dependency(OpenSSL)") endif() endif() set(HAVE_LIBSSL "${OPENSSL_FOUND}") @@ -146,6 +150,9 @@ if(WANT_ICU) pkg_check_modules(ICU ${TRISTATE_ICU_REQUIRED} IMPORTED_TARGET icu-uc) endif() set(HAVE_ICU "${ICU_FOUND}") +if(ICU_FOUND) + set(ZNC_CMAKE_FIND_DEPS "${ZNC_CMAKE_FIND_DEPS}\nfind_dependency_pc(ICU icu-uc)") +endif() set(WANT_PERL false CACHE BOOL "Support Perl modules") set(WANT_PYTHON false CACHE BOOL "Support Python modules") @@ -421,6 +428,7 @@ include(CMakePackageConfigHelpers) write_basic_package_version_file("ZNCConfigVersion.cmake" COMPATIBILITY AnyNewerVersion) install(FILES + "${PROJECT_SOURCE_DIR}/cmake/CMakeFindDependencyMacroPC.cmake" "${PROJECT_BINARY_DIR}/ZNCConfig.cmake" "${PROJECT_BINARY_DIR}/ZNCConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_DATADIR}/znc/cmake") diff --git a/ZNCConfig.cmake.in b/ZNCConfig.cmake.in index a41aa78d..68d3e82f 100644 --- a/ZNCConfig.cmake.in +++ b/ZNCConfig.cmake.in @@ -14,6 +14,10 @@ # limitations under the License. # +include(CMakeFindDependencyMacro) +include("${CMAKE_CURRENT_LIST_DIR}/CMakeFindDependencyMacroPC.cmake") +@ZNC_CMAKE_FIND_DEPS@ + include("${CMAKE_CURRENT_LIST_DIR}/znc_internal.cmake") include("${CMAKE_CURRENT_LIST_DIR}/znc_public.cmake") include(CMakeParseArguments) diff --git a/cmake/CMakeFindDependencyMacroPC.cmake b/cmake/CMakeFindDependencyMacroPC.cmake new file mode 100644 index 00000000..6dda0ec4 --- /dev/null +++ b/cmake/CMakeFindDependencyMacroPC.cmake @@ -0,0 +1,99 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CMakeFindDependencyMacro +------------------------ + +.. command:: find_dependency + + The ``find_dependency()`` macro wraps a :command:`find_package` call for + a package dependency:: + + find_dependency( [...]) + + It is designed to be used in a + :ref:`Package Configuration File ` + (``Config.cmake``). ``find_dependency`` forwards the correct + parameters for ``QUIET`` and ``REQUIRED`` which were passed to + the original :command:`find_package` call. Any additional arguments + specified are forwarded to :command:`find_package`. + + If the dependency could not be found it sets an informative diagnostic + message and calls :command:`return` to end processing of the calling + package configuration file and return to the :command:`find_package` + command that loaded it. + + .. note:: + + The call to :command:`return` makes this macro unsuitable to call + from :ref:`Find Modules`. + +Package Dependency Search Optimizations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If ``find_dependency`` is called with arguments identical to a previous +call in the same directory, perhaps due to diamond-shaped package +dependencies, the underlying call to :command:`find_package` is optimized +out. This optimization is important to support large package dependency +graphs while avoiding a combinatorial explosion of repeated searches. +However, the heuristic cannot account for ambient variables that +affect package behavior, such as ``_USE_STATIC_LIBS``, +offered by some packages. Therefore package configuration files should +avoid setting such variables before their calls to ``find_dependency``. + +.. versionchanged:: 3.15 + Previously, the underlying call to :command:`find_package` was always + optimized out if the package had already been found. CMake 3.15 + removed the optimization to support cases in which ``find_dependency`` + call arguments request different components. + +.. versionchanged:: 3.26 + The pre-3.15 optimization was restored, but with the above-described + heuristic to account for varying ``find_dependency`` call arguments. + +#]=======================================================================] + +macro(find_dependency_pc dep) +find_dependency(PkgConfig) + string(SHA256 cmake_fd_call_hash "${dep};${ARGN};${${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED}") + if(_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND) + unset(cmake_fd_call_hash) + else() + list(APPEND _CMAKE_${dep}_HASH_STACK ${cmake_fd_call_hash}) + set(cmake_fd_quiet_arg) + if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY) + set(cmake_fd_quiet_arg QUIET) + endif() + set(cmake_fd_required_arg) + if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED) + set(cmake_fd_required_arg REQUIRED) + endif() + + get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY + _CMAKE_${dep}_TRANSITIVE_DEPENDENCY + ) + + pkg_check_modules(${dep} + ${cmake_fd_quiet_arg} + ${cmake_fd_required_arg} + IMPORTED_TARGET ${ARGN} + ) + list(POP_BACK _CMAKE_${dep}_HASH_STACK cmake_fd_call_hash) + set("_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND" "${${dep}_FOUND}") + + if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive) + set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE) + endif() + + unset(cmake_fd_alreadyTransitive) + unset(cmake_fd_call_hash) + unset(cmake_fd_quiet_arg) + unset(cmake_fd_required_arg) + if (NOT ${dep}_FOUND) + set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency ${dep} could not be found.") + set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False) + return() + endif() + endif() +endmacro()