From 9ddfe1b6a8bd92d4e22bffc07bab0dd050e03b00 Mon Sep 17 00:00:00 2001 From: Patrick Stewart Date: Sat, 21 Dec 2024 00:38:22 +0900 Subject: [PATCH] Add find_package overrides that also work in CONFIG mode (#498) (#604) --- README.md | 7 ++++++ cmake/CPM.cmake | 25 +++++++++++++++---- test/integration/test_basics.rb | 4 ++- .../local_dependency/ModuleCMakeLists.txt.in | 24 +++++++++++------- test/unit/modules.cmake | 23 +++++++++++------ 5 files changed, 60 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 33fbbc8..d3a6bcb 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,13 @@ In the case that `find_package` requires additional arguments, the parameter `FI Note that this does not apply to dependencies that have been defined with a truthy `FORCE` parameter. These will be added as defined. +### CPM_DONT_UPDATE_MODULE_PATH + +By default, CPM will override any `find_package` commands to use the CPM downloaded version. +This is equivalent to the `OVERRIDE_FIND_PACKAGE` FetchContent option, which has no effect in CPM. +To disable this behaviour set the `CPM_DONT_UPDATE_MODULE_PATH` option. +This will not work for `find_package(CONFIG)` in CMake versions before 3.24. + ### CPM_USE_NAMED_CACHE_DIRECTORIES If set, CPM use additional directory level in cache to improve readability of packages names in IDEs like CLion. It changes cache structure, so all dependencies are downloaded again. There is no problem to mix both structures in one cache directory but then there may be 2 copies of some dependencies. diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake index 6e26079..0875dab 100644 --- a/cmake/CPM.cmake +++ b/cmake/CPM.cmake @@ -162,7 +162,7 @@ set(CPM_SOURCE_CACHE CACHE PATH "Directory to download CPM dependencies" ) -if(NOT CPM_DONT_UPDATE_MODULE_PATH) +if(NOT CPM_DONT_UPDATE_MODULE_PATH AND NOT DEFINED CMAKE_FIND_PACKAGE_REDIRECTS_DIR) set(CPM_MODULE_PATH "${CMAKE_BINARY_DIR}/CPM_modules" CACHE INTERNAL "" @@ -269,10 +269,25 @@ endfunction() # finding the system library function(cpm_create_module_file Name) if(NOT CPM_DONT_UPDATE_MODULE_PATH) - # erase any previous modules - file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake - "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)" - ) + if(DEFINED CMAKE_FIND_PACKAGE_REDIRECTS_DIR) + # Redirect find_package calls to the CPM package. This is what FetchContent does when you set + # OVERRIDE_FIND_PACKAGE. The CMAKE_FIND_PACKAGE_REDIRECTS_DIR works for find_package in CONFIG + # mode, unlike the Find${Name}.cmake fallback. CMAKE_FIND_PACKAGE_REDIRECTS_DIR is not defined + # in script mode, or in CMake < 3.24. + # https://cmake.org/cmake/help/latest/module/FetchContent.html#fetchcontent-find-package-integration-examples + string(TOLOWER ${Name} NameLower) + file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${NameLower}-config.cmake + "include(\"${CMAKE_CURRENT_LIST_DIR}/${NameLower}-extra.cmake\" OPTIONAL)\n" + "include(\"${CMAKE_CURRENT_LIST_DIR}/${Name}Extra.cmake\" OPTIONAL)\n" + ) + file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${NameLower}-version.cmake + "set(PACKAGE_VERSION_COMPATIBLE TRUE)\n" "set(PACKAGE_VERSION_EXACT TRUE)\n" + ) + else() + file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake + "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)" + ) + endif() endif() endfunction() diff --git a/test/integration/test_basics.rb b/test/integration/test_basics.rb index 5cb6ccf..ebd5572 100644 --- a/test/integration/test_basics.rb +++ b/test/integration/test_basics.rb @@ -31,7 +31,9 @@ class Basics < IntegrationTest assert_same_path File.join(prj.bin_dir, 'cpm-package-lock.cmake'), check_and_get('CPM_PACKAGE_LOCK_FILE') assert_equal 'OFF', check_and_get('CPM_DONT_UPDATE_MODULE_PATH', 'BOOL') - assert_same_path File.join(prj.bin_dir, 'CPM_modules'), check_and_get('CPM_MODULE_PATH') + if @cache.entries['CMAKE_FIND_PACKAGE_REDIRECTS_DIR'].nil? + assert_same_path File.join(prj.bin_dir, 'CPM_modules'), check_and_get('CPM_MODULE_PATH') + end end # Test when env CPM_SOURCE_CACHE is set diff --git a/test/unit/local_dependency/ModuleCMakeLists.txt.in b/test/unit/local_dependency/ModuleCMakeLists.txt.in index 8c87ec1..5ab7b3e 100644 --- a/test/unit/local_dependency/ModuleCMakeLists.txt.in +++ b/test/unit/local_dependency/ModuleCMakeLists.txt.in @@ -8,6 +8,10 @@ option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF) # ---- Dependencies ---- +if (@TEST_FORCE_MODULE_MODE@) + unset(CMAKE_FIND_PACKAGE_REDIRECTS_DIR CACHE) +endif() + include(@CPM_PATH@/CPM.cmake) CPMAddPackage( @@ -15,21 +19,23 @@ CPMAddPackage( SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/dependency ) -# ---- check if generated modules override find_package ---- - -if (@test_check_find_package@) - find_package(@TEST_DEPENDENCY_NAME@ REQUIRED) -endif() - # ---- Call dependency method to validate correct addition of directory ---- dependency_function() -# ---- Check parameters ---- - +# ---- Check newly added ---- include(@CPM_PATH@/testing.cmake) - ASSERT_TRUTHY(@TEST_DEPENDENCY_NAME@_ADDED) + +# ---- Check if generated modules override find_package ---- + +if (@TEST_FIND_PACKAGE@) + find_package(@TEST_DEPENDENCY_NAME@ @TEST_FIND_PACKAGE_CONFIG@ REQUIRED) + find_package(@TEST_CANT_FIND_PACKAGE_NAME@ @TEST_FIND_PACKAGE_CONFIG@ QUIET) + ASSERT_FALSY(@TEST_CANT_FIND_PACKAGE_NAME@_FOUND) +endif() + +# ---- Check parameters ---- ASSERT_DEFINED(@TEST_DEPENDENCY_NAME@_SOURCE_DIR) ASSERT_DEFINED(@TEST_DEPENDENCY_NAME@_BINARY_DIR) ASSERT_EQUAL("${CPM_LAST_PACKAGE_NAME}" "@TEST_DEPENDENCY_NAME@") diff --git a/test/unit/modules.cmake b/test/unit/modules.cmake index a0dec8e..c5e5653 100644 --- a/test/unit/modules.cmake +++ b/test/unit/modules.cmake @@ -3,7 +3,8 @@ include(${CPM_PATH}/testing.cmake) set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/modules) -function(init_project_with_dependency TEST_DEPENDENCY_NAME) +function(init_project_with_dependency TEST_DEPENDENCY_NAME TEST_CANT_FIND_PACKAGE_NAME) + set(TEST_FIND_PACKAGE ON) configure_package_config_file( "${CMAKE_CURRENT_LIST_DIR}/local_dependency/ModuleCMakeLists.txt.in" "${CMAKE_CURRENT_LIST_DIR}/local_dependency/CMakeLists.txt" @@ -18,11 +19,17 @@ function(init_project_with_dependency TEST_DEPENDENCY_NAME) assert_equal(${ret} "0") endfunction() -init_project_with_dependency(A) -assert_exists(${TEST_BUILD_DIR}/CPM_modules) -assert_exists(${TEST_BUILD_DIR}/CPM_modules/FindA.cmake) -assert_not_exists(${TEST_BUILD_DIR}/CPM_modules/FindB.cmake) +init_project_with_dependency(A B) +init_project_with_dependency(B A) -init_project_with_dependency(B) -assert_not_exists(${TEST_BUILD_DIR}/CPM_modules/FindA.cmake) -assert_exists(${TEST_BUILD_DIR}/CPM_modules/FindB.cmake) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24.0") + set(TEST_FIND_PACKAGE_CONFIG CONFIG) + init_project_with_dependency(A B) + init_project_with_dependency(B A) + + # Test the fallback path for CMake <3.24 works + set(TEST_FIND_PACKAGE_CONFIG) + set(TEST_FORCE_MODULE_MODE ON) + init_project_with_dependency(A B) + init_project_with_dependency(B A) +endif()