From b1c2c908fad9204629091152668996591466f224 Mon Sep 17 00:00:00 2001 From: Mustafa Kemal Gilor Date: Mon, 3 Jun 2024 11:46:19 +0300 Subject: [PATCH] conan-provider.cmake: introduce a new policy scope, set min cmake version cmake has the notion of "policy scopes" to limit the scope of the policies. this patch introduces a module-level policy scope and sets the minimum required cmake version to 3.24, so the cmake features depend on policy settings such as `if(... IN_LIST ...)` behaves as expected even if the consuming project does not declare a cmake minimum version requirement. also, this change now enforces the version requirement so the code would fail immediately if the cmake version is less than the minimum. Signed-off-by: Mustafa Kemal Gilor --- conan_provider.cmake | 14 +++++++++++++ .../find_module/policy_scope/CMakeLists.txt | 21 +++++++++++++++++++ tests/test_smoke.py | 17 +++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 tests/resources/find_module/policy_scope/CMakeLists.txt diff --git a/conan_provider.cmake b/conan_provider.cmake index 6bf31b18..edb51e2a 100644 --- a/conan_provider.cmake +++ b/conan_provider.cmake @@ -22,6 +22,18 @@ set(CONAN_MINIMUM_VERSION 2.0.5) +# Create a new policy scope and set the minimum required cmake version so the +# features behind a policy setting like if(... IN_LIST ...) behaves as expected +# even if the parent project does not specify a minimum cmake version or a minimum +# version less than this module requires (e.g. 3.0) before the first project() call. +# (see: https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.html) +# +# The policy-affecting calls like cmake_policy(SET...) or `cmake_minimum_required` only +# affects the current policy scope, i.e. between the PUSH and POP in this case. +# +# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Policies.html#the-policy-stack +cmake_policy(PUSH) +cmake_minimum_required(VERSION 3.24) function(detect_os OS OS_API_LEVEL OS_SDK OS_SUBSYSTEM OS_VERSION) # it could be cross compilation @@ -647,3 +659,5 @@ if(NOT _cmake_program) get_filename_component(PATH_TO_CMAKE_BIN "${CMAKE_COMMAND}" DIRECTORY) set(PATH_TO_CMAKE_BIN "${PATH_TO_CMAKE_BIN}" CACHE INTERNAL "Path where the CMake executable is") endif() + +cmake_policy(POP) diff --git a/tests/resources/find_module/policy_scope/CMakeLists.txt b/tests/resources/find_module/policy_scope/CMakeLists.txt new file mode 100644 index 00000000..87df4cfe --- /dev/null +++ b/tests/resources/find_module/policy_scope/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.0) +project(MyApp CXX) + +set(CMAKE_CXX_STANDARD 17) +find_package(hello REQUIRED) +# Request that Findbye.cmake (generated by Conan) +# is used instead of bye-config.cmake +find_package(bye MODULE REQUIRED) + +# The `find_package` will include the conan_provider.cmake file +# which has policy-affecting code. We expect no changes to the current +# policy scope. + +add_executable(app main.cpp) +target_link_libraries(app hello::hello bye::bye) + +set(test_list a b c d e f) +if("a" IN_LIST test_list) + # see https://cmake.org/cmake/help/latest/policy/CMP0057.html + message(ERROR "this should not happen as IN_LIST is a CMake 3.3 feature.") +endif() \ No newline at end of file diff --git a/tests/test_smoke.py b/tests/test_smoke.py index e44f83f6..ee06ec48 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -277,6 +277,23 @@ def test_cmake_builtin_module(self, capfd, basic_cmake_project): out, _ = capfd.readouterr() assert "Found Threads: TRUE" in out + def test_policy_scope(self, capfd, basic_cmake_project): + """ + Ensure that the policy settings of the user project is not affected by the + "module's policy-affecting calls. + """ + source_dir, binary_dir = basic_cmake_project + shutil.copytree(resources_dir / 'find_module' / 'policy_scope', source_dir, dirs_exist_ok=True) + + run(f"cmake -S {source_dir} -B {binary_dir} -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES={conan_provider} -DCMAKE_BUILD_TYPE=Release", check=False) + out, err = capfd.readouterr() + assert not re.search(rf'CMake Error at {conan_provider}.*\(if\):\n if given arguments', err) + assert "Conan: Target declared 'hello::hello'" in out + assert "Conan: Target declared 'bye::bye'" in out + assert "\"a\" \"IN_LIST\" \"test_list\"" in err + assert "this should not happen as IN_LIST is a CMake 3.3 feature." not in err + + class TestCMakeModulePath: