From 38bf9b71024ddb7a8fe44d5d5a8469f7352b2e6d Mon Sep 17 00:00:00 2001 From: Luis Martinez de Bartolome Izquierdo Date: Wed, 7 Jul 2021 17:26:05 +0200 Subject: [PATCH] CMakeDeps checks build profile + CMakeDeps check real targets (#9206) * CMakeDeps checks build profile + CMakeDeps check real targets * Added test of a build module declaring component targets * Default check False and introduced switch * Moved test and removed duplicated ones * Recover test --- conan/tools/_check_build_profile.py | 10 + conan/tools/cmake/cmakedeps/cmakedeps.py | 14 ++ .../tools/cmake/cmakedeps/templates/config.py | 19 +- .../cmake/cmakedeps/templates/target_data.py | 1 - .../cmake/cmakedeps/templates/targets.py | 12 -- conan/tools/cmake/toolchain.py | 3 + conan/tools/gnu/autotoolsdeps.py | 2 + conan/tools/gnu/autotoolstoolchain.py | 3 + conan/tools/google/bazeldeps.py | 2 + conan/tools/google/toolchain.py | 2 + conan/tools/meson/toolchain.py | 3 + conan/tools/microsoft/msbuilddeps.py | 3 + conan/tools/microsoft/toolchain.py | 2 + conans/test/assets/genconanfile.py | 1 + .../cmakedeps/test_cmakedeps_build_modules.py | 2 + .../test_cmakedeps_components_names.py | 178 +++++++++++++----- .../toolchains/test_check_build_profile.py | 64 +++++++ 17 files changed, 262 insertions(+), 59 deletions(-) create mode 100644 conan/tools/_check_build_profile.py create mode 100644 conans/test/integration/toolchains/test_check_build_profile.py diff --git a/conan/tools/_check_build_profile.py b/conan/tools/_check_build_profile.py new file mode 100644 index 00000000000..0544861194f --- /dev/null +++ b/conan/tools/_check_build_profile.py @@ -0,0 +1,10 @@ + +check_msg = "Using the new toolchains and generators without specifying " \ + "a build profile (e.g: -pr:b=default) is discouraged and "\ + "might cause failures and unexpected behavior" + + +def check_using_build_profile(conanfile): + """FIXME: Remove this in Conan 2.0 where the two profiles are always applied""" + if not hasattr(conanfile, "settings_build"): + conanfile.output.warn(check_msg) diff --git a/conan/tools/cmake/cmakedeps/cmakedeps.py b/conan/tools/cmake/cmakedeps/cmakedeps.py index f589386d912..9ee9319c648 100644 --- a/conan/tools/cmake/cmakedeps/cmakedeps.py +++ b/conan/tools/cmake/cmakedeps/cmakedeps.py @@ -1,5 +1,6 @@ import os +from conan.tools._check_build_profile import check_using_build_profile from conan.tools.cmake.cmakedeps.templates.config import ConfigTemplate from conan.tools.cmake.cmakedeps.templates.config_version import ConfigVersionTemplate from conan.tools.cmake.cmakedeps.templates.macros import MacrosTemplate @@ -26,7 +27,20 @@ def __init__(self, conanfile): # a suffix. It is necessary in case of same require and build_require and will cause an error self.build_context_suffix = {} + check_using_build_profile(self._conanfile) + + # Enable/Disable checking if a component target exists or not + self.check_components_exist = False + def generate(self): + # FIXME: Remove this in 2.0 + if not hasattr(self._conanfile, "settings_build") and \ + (self.build_context_activated or self.build_context_build_modules or + self.build_context_suffix): + raise ConanException("The 'build_context_activated' and 'build_context_build_modules' of" + " the CMakeDeps generator cannot be used without specifying a build" + " profile. e.g: -pr:b=default") + # Current directory is the generators_folder generator_files = self.content for generator_file, content in generator_files.items(): diff --git a/conan/tools/cmake/cmakedeps/templates/config.py b/conan/tools/cmake/cmakedeps/templates/config.py index f0e152b9325..bfd457583db 100644 --- a/conan/tools/cmake/cmakedeps/templates/config.py +++ b/conan/tools/cmake/cmakedeps/templates/config.py @@ -23,7 +23,9 @@ def filename(self): def context(self): return {"file_name": self.file_name, "pkg_name": self.pkg_name, - "config_suffix": self.config_suffix} + "config_suffix": self.config_suffix, + "target_namespace": self.target_namespace, + "check_components_exist": self.cmakedeps.check_components_exist} @property def template(self): @@ -45,10 +47,23 @@ def template(self): endif() endforeach() - # Only the first installed configuration is included to avoid the collission + # Only the first installed configuration is included to avoid the collision foreach(_BUILD_MODULE {{ '${' + pkg_name + '_BUILD_MODULES_PATHS' + config_suffix + '}' }} ) conan_message(STATUS "Conan: Including build module from '${_BUILD_MODULE}'") include({{ '${_BUILD_MODULE}' }}) endforeach() + {% if check_components_exist %} + # Check that the specified components in the find_package(Foo COMPONENTS x y z) are there + # This is the variable filled by CMake with the requested components in find_package + if({{ target_namespace }}_FIND_COMPONENTS) + foreach(_FIND_COMPONENT {{ '${'+target_namespace+'_FIND_COMPONENTS}' }}) + if (TARGET {{ target_namespace }}::${_FIND_COMPONENT}) + conan_message(STATUS "Conan: Component '${_FIND_COMPONENT}' found in package '{{ pkg_name }}'") + else() + conan_message(FATAL_ERROR "Conan: Component '${_FIND_COMPONENT}' NOT found in package '{{ pkg_name }}'") + endif() + endforeach() + endif() + {% endif %} """) diff --git a/conan/tools/cmake/cmakedeps/templates/target_data.py b/conan/tools/cmake/cmakedeps/templates/target_data.py index 2a2bc7769fd..156fecb9b02 100644 --- a/conan/tools/cmake/cmakedeps/templates/target_data.py +++ b/conan/tools/cmake/cmakedeps/templates/target_data.py @@ -215,4 +215,3 @@ def join_paths_single_var(values): build_modules = cpp_info.get_property("cmake_build_modules", "CMakeDeps") or [] self.build_modules_paths = join_paths(build_modules) - diff --git a/conan/tools/cmake/cmakedeps/templates/targets.py b/conan/tools/cmake/cmakedeps/templates/targets.py index 046a52c6c65..59bdd3e1c16 100644 --- a/conan/tools/cmake/cmakedeps/templates/targets.py +++ b/conan/tools/cmake/cmakedeps/templates/targets.py @@ -53,16 +53,4 @@ def template(self): foreach(f ${CONFIG_FILES}) include(${f}) endforeach() - - # This is the variable filled by CMake with the requested components in find_package - if({{ target_namespace }}_FIND_COMPONENTS) - foreach(_FIND_COMPONENT {{ '${'+target_namespace+'_FIND_COMPONENTS}' }}) - list(FIND {{ pkg_name }}_COMPONENT_NAMES "${_FIND_COMPONENT}" _index) - if(${_index} EQUAL -1) - conan_message(FATAL_ERROR "Conan: Component '${_FIND_COMPONENT}' NOT found in package '{{ pkg_name }}'") - else() - conan_message(STATUS "Conan: Component '${_FIND_COMPONENT}' found in package '{{ pkg_name }}'") - endif() - endforeach() - endif() """) diff --git a/conan/tools/cmake/toolchain.py b/conan/tools/cmake/toolchain.py index 7d9f5fce795..db4aba8cfaf 100644 --- a/conan/tools/cmake/toolchain.py +++ b/conan/tools/cmake/toolchain.py @@ -8,6 +8,7 @@ from jinja2 import Template from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE +from conan.tools._check_build_profile import check_using_build_profile from conan.tools._compilers import architecture_flag, use_win_mingw from conan.tools.cmake.utils import is_multi_configuration, get_file_name from conan.tools.microsoft.toolchain import write_conanvcvars @@ -699,6 +700,8 @@ def __init__(self, conanfile, generator=None): ("rpath", SkipRPath), ("shared", SharedLibBock)]) + check_using_build_profile(self._conanfile) + def _context(self): """ Returns dict, the context for the template """ diff --git a/conan/tools/gnu/autotoolsdeps.py b/conan/tools/gnu/autotoolsdeps.py index 7873ff40804..970168f2091 100644 --- a/conan/tools/gnu/autotoolsdeps.py +++ b/conan/tools/gnu/autotoolsdeps.py @@ -1,3 +1,4 @@ +from conan.tools._check_build_profile import check_using_build_profile from conan.tools.env import Environment from conan.tools.gnu.gnudeps_flags import GnuDepsFlags from conans.model.new_build_info import NewCppInfo @@ -9,6 +10,7 @@ def __init__(self, conanfile): # alter some value self._conanfile = conanfile self._cpp_info = None + check_using_build_profile(self._conanfile) @property def cpp_info(self): diff --git a/conan/tools/gnu/autotoolstoolchain.py b/conan/tools/gnu/autotoolstoolchain.py index 1b3fddcae4e..ac3f7815804 100644 --- a/conan/tools/gnu/autotoolstoolchain.py +++ b/conan/tools/gnu/autotoolstoolchain.py @@ -1,6 +1,7 @@ import json from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE +from conan.tools._check_build_profile import check_using_build_profile from conan.tools._compilers import architecture_flag, build_type_flags, cppstd_flag from conan.tools.apple.apple import apple_min_version_flag, to_apple_arch, \ apple_sdk_path @@ -62,6 +63,8 @@ def __init__(self, conanfile): # -isysroot makes all includes for your library relative to the build directory self.apple_isysroot_flag = "-isysroot {}".format(sdk_path) if sdk_path else None + check_using_build_profile(self._conanfile) + def _cxx11_abi_define(self): # https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html # The default is libstdc++11, only specify the contrary '_GLIBCXX_USE_CXX11_ABI=0' diff --git a/conan/tools/google/bazeldeps.py b/conan/tools/google/bazeldeps.py index dea0cb7fe2f..b9fc50640ca 100644 --- a/conan/tools/google/bazeldeps.py +++ b/conan/tools/google/bazeldeps.py @@ -2,12 +2,14 @@ from jinja2 import Template +from conan.tools._check_build_profile import check_using_build_profile from conans.util.files import save class BazelDeps(object): def __init__(self, conanfile): self._conanfile = conanfile + check_using_build_profile(self._conanfile) def generate(self): local_repositories = [] diff --git a/conan/tools/google/toolchain.py b/conan/tools/google/toolchain.py index cb518fd7cdb..5a88a2381be 100644 --- a/conan/tools/google/toolchain.py +++ b/conan/tools/google/toolchain.py @@ -1,6 +1,7 @@ import json from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE +from conan.tools._check_build_profile import check_using_build_profile from conans.util.files import save @@ -8,6 +9,7 @@ class BazelToolchain(object): def __init__(self, conanfile): self._conanfile = conanfile + check_using_build_profile(self._conanfile) def generate(self): bazel_config = self._conanfile.conf["tools.google.bazel:config"] diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py index 357bf884460..7ea919c932c 100644 --- a/conan/tools/meson/toolchain.py +++ b/conan/tools/meson/toolchain.py @@ -2,6 +2,7 @@ from jinja2 import Template +from conan.tools._check_build_profile import check_using_build_profile from conan.tools.env import VirtualBuildEnv from conan.tools.microsoft.toolchain import write_conanvcvars from conans.client.build.cppstd_flags import cppstd_from_settings @@ -112,6 +113,8 @@ def from_build_env(name): self.cpp_link_args = self._to_meson_value(self._env_array('LDFLAGS')) self.pkg_config_path = "'%s'" % self._conanfile.generators_folder + check_using_build_profile(self._conanfile) + @staticmethod def _to_meson_value(value): # https://mesonbuild.com/Machine-files.html#data-types diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py index 2b9af3445ed..daf91f70c5b 100644 --- a/conan/tools/microsoft/msbuilddeps.py +++ b/conan/tools/microsoft/msbuilddeps.py @@ -5,6 +5,7 @@ from jinja2 import Template +from conan.tools._check_build_profile import check_using_build_profile from conans.errors import ConanException from conans.model.build_info import DepCppInfo from conans.util.files import load, save @@ -109,6 +110,8 @@ def __init__(self, conanfile): raise ConanException("tools.microsoft.msbuilddeps:exclude_code_analysis must be a" " list of package names patterns like ['pkga*']") + check_using_build_profile(self._conanfile) + def generate(self): # TODO: Apply config from command line, something like # configuration = self.conanfile.config.generators["msbuild"].configuration diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index 4db4a3af0c2..07abb4ff081 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -2,6 +2,7 @@ import textwrap from xml.dom import minidom +from conan.tools._check_build_profile import check_using_build_profile from conan.tools.env.environment import register_environment_script from conan.tools.microsoft.visual import vcvars_command, vcvars_arch from conans.client.tools import intel_compilervars_command @@ -87,6 +88,7 @@ def __init__(self, conanfile): self.runtime_library = self._runtime_library(conanfile.settings) self.cppstd = conanfile.settings.get_safe("compiler.cppstd") self.toolset = self._msvs_toolset(conanfile.settings) + check_using_build_profile(self._conanfile) def _name_condition(self, settings): props = [("Configuration", self.configuration), diff --git a/conans/test/assets/genconanfile.py b/conans/test/assets/genconanfile.py index 095e8816eab..9de05949f59 100644 --- a/conans/test/assets/genconanfile.py +++ b/conans/test/assets/genconanfile.py @@ -198,6 +198,7 @@ def with_cmake_build(self): self._generators = self._generators or [] self._generators.append("CMakeDeps") self._generators.append("CMakeToolchain") + self.with_settings("os", "compiler", "arch", "build_type") self._cmake_build = True return self diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py index c2eb81625cb..0b5ec1f46e0 100644 --- a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py +++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py @@ -6,6 +6,7 @@ import pytest from conans.model.ref import ConanFileReference, PackageReference +from conans.test.assets.genconanfile import GenConanfile from conans.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID @@ -266,3 +267,4 @@ def test_multi_generator_macos(self): assert str(t.out).count('>> Build-module is included') == 2 # FIXME: Known bug assert '>> nonamespace libs: library::library' in t.out t.run_command('cmake --build . --config Release') # Compiles and links. + diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_components_names.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_components_names.py index 550cbd234e0..61b18280d67 100644 --- a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_components_names.py +++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_components_names.py @@ -101,7 +101,7 @@ def test(self): set(CMAKE_CXX_ABI_COMPILED 1) cmake_minimum_required(VERSION 3.0) project(PackageTest CXX) - + find_package(greetings) add_executable(example example.cpp) @@ -430,7 +430,6 @@ class TestComponentsCMakeGenerators: def test_component_not_found(self): conanfile = textwrap.dedent(""" from conans import ConanFile - class GreetingsConan(ConanFile): def package_info(self): self.cpp_info.components["hello"].libs = ["hello"] @@ -441,10 +440,8 @@ def package_info(self): conanfile = textwrap.dedent(""" from conans import ConanFile - class WorldConan(ConanFile): requires = "greetings/0.0.1" - def package_info(self): self.cpp_info.components["helloworld"].requires = ["greetings::non-existent"] """) @@ -454,46 +451,6 @@ def package_info(self): assert ("Component 'greetings::non-existent' not found in 'greetings' " "package requirement" in client.out) - def test_component_not_found_cmake(self): - conanfile = textwrap.dedent(""" - from conans import ConanFile - - class GreetingsConan(ConanFile): - def package_info(self): - self.cpp_info.components["hello"].cxxflags = ["flags"] - """) - client = TestClient() - client.save({"conanfile.py": conanfile}) - client.run("create . greetings/0.0.1@") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - from conan.tools.cmake import CMake - - class ConsumerConan(ConanFile): - settings = "build_type", "os", "arch", "compiler" - generators = "CMakeDeps", "CMakeToolchain" - requires = "greetings/0.0.1" - - def build(self): - cmake = CMake(self) - cmake.configure() - """) - cmakelists = textwrap.dedent(""" - set(CMAKE_CXX_COMPILER_WORKS 1) - set(CMAKE_CXX_ABI_COMPILED 1) - cmake_minimum_required(VERSION 3.0) - project(Consumer CXX) - - find_package(greetings COMPONENTS hello) - find_package(greetings COMPONENTS non-existent) - """) - client.save({"conanfile.py": conanfile, "CMakeLists.txt": cmakelists}) - client.run("install .") - client.run("build .", assert_error=True) - assert "Conan: Component 'hello' found in package 'greetings'" in client.out - assert "Conan: Component 'non-existent' NOT found in package 'greetings'" in client.out - def test_component_not_found_same_name_as_pkg_require(self): zlib = GenConanfile("zlib", "0.1").with_setting("build_type").with_generator("CMakeDeps") mypkg = GenConanfile("mypkg", "0.1").with_setting("build_type").with_generator("CMakeDeps") @@ -506,6 +463,49 @@ def test_component_not_found_same_name_as_pkg_require(self): consumer = GenConanfile("consumer", "0.1").with_setting("build_type")\ .with_generator("CMakeDeps")\ .with_requirement(ConanFileReference("final", "0.1", None, None)) + + consumer = textwrap.dedent(""" + from conans import ConanFile + from conan.tools.cmake import CMakeDeps + class HelloConan(ConanFile): + name = 'consumer' + version = '0.1' + + def generate(self): + deps = CMakeDeps(self) + deps.check_components_exist = True + deps.generate() + + def requirements(self): + self.requires("final/0.1") + + settings = "build_type" + """) + + def test_component_not_found(self): + conanfile = textwrap.dedent(""" + from conans import ConanFile + class GreetingsConan(ConanFile): + def package_info(self): + self.cpp_info.components["hello"].libs = ["hello"] + """) + client = TestClient() + client.save({"conanfile.py": conanfile}) + client.run("create . greetings/0.0.1@") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class WorldConan(ConanFile): + requires = "greetings/0.0.1" + def package_info(self): + self.cpp_info.components["helloworld"].requires = ["greetings::non-existent"] + """) + client.save({"conanfile.py": conanfile}) + client.run("create . world/0.0.1@") + client.run("install world/0.0.1@ -g CMakeDeps", assert_error=True) + assert ("Component 'greetings::non-existent' not found in 'greetings' " + "package requirement" in client.out) + client = TestClient() client.save({"zlib.py": zlib, "mypkg.py": mypkg, "final.py": final, "consumer.py": consumer}) client.run("create zlib.py") @@ -644,3 +644,93 @@ def build(self): assert 'middle: Release!' in client.out assert 'expected/1.0: Hello World Release!' in client.out assert 'variant/1.0: Hello World Release!' in client.out + + +@pytest.mark.parametrize("check_components_exist", [False, True, None]) +def test_targets_declared_in_build_modules(check_components_exist): + """If a require is declaring the component targets in a build_module, CMakeDeps is + fine with it, not needed to locate it as a conan declared component""" + + client = TestClient() + conanfile_hello = str(GenConanfile().with_name("hello").with_version("1.0") + .with_exports_sources("*.cmake", "*.h")) + conanfile_hello += """ + def package(self): + self.copy("*.h", dst="include") + self.copy("*.cmake", dst="cmake") + + def package_info(self): + self.cpp_info.set_property("cmake_build_modules", ["cmake/my_modules.cmake"]) + """ + my_modules = textwrap.dedent(""" + add_library(cool_component INTERFACE) + target_include_directories(cool_component INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../include/) + add_library(hello::invented ALIAS cool_component) + """) + hello_h = "int cool_header_only=1;" + client.save({"conanfile.py": conanfile_hello, + "my_modules.cmake": my_modules, "hello.h": hello_h}) + client.run("create .") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + from conan.tools.cmake import CMake, CMakeDeps + + class HelloConan(ConanFile): + name = 'app' + version = '1.0' + exports_sources = "*.txt", "*.cpp" + generators = "CMakeToolchain" + requires = ("hello/1.0", ) + settings = "os", "compiler", "arch", "build_type" + + def generate(self): + deps = CMakeDeps(self) + {} + deps.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + """) + if check_components_exist is False: + conanfile = conanfile.format("deps.check_components_exist=False") + elif check_components_exist is True: + conanfile = conanfile.format("deps.check_components_exist=True") + else: + conanfile = conanfile.format("") + + main_cpp = textwrap.dedent(""" + #include + #include "hello.h" + + int main(){ + std::cout << "cool header value: " << cool_header_only; + return 0; + } + """) + + cmakelist = textwrap.dedent(""" + set(CMAKE_CXX_COMPILER_WORKS 1) + set(CMAKE_CXX_ABI_COMPILED 1) + set(CMAKE_C_COMPILER_WORKS 1) + set(CMAKE_C_ABI_COMPILED 1) + cmake_minimum_required(VERSION 3.15) + project(project CXX) + + find_package(hello COMPONENTS invented missing) + add_executable(myapp main.cpp) + target_link_libraries(myapp hello::invented) + """) + client.save({"conanfile.py": conanfile, + "CMakeLists.txt": cmakelist, "main.cpp": main_cpp}) + client.run("create .", assert_error=check_components_exist) + assert bool(check_components_exist) == ("Conan: Component 'missing' NOT found in package " + "'hello'" in client.out) + + assert "Conan: Including build module" in client.out + assert "my_modules.cmake" in client.out + assert bool(check_components_exist) == ("Conan: Component 'invented' found in package 'hello'" + in client.out) diff --git a/conans/test/integration/toolchains/test_check_build_profile.py b/conans/test/integration/toolchains/test_check_build_profile.py new file mode 100644 index 00000000000..c805cdf972c --- /dev/null +++ b/conans/test/integration/toolchains/test_check_build_profile.py @@ -0,0 +1,64 @@ +import pytest + +from conan.tools._check_build_profile import check_msg +from conans.test.assets.genconanfile import GenConanfile +from conans.test.utils.tools import TestClient + + +@pytest.mark.parametrize("tool_class", ["CMakeDeps", "CMakeToolchain", "AutotoolsToolchain", + "AutotoolsDeps", "MSBuildToolchain", "MSBuildDeps", + "BazelDeps", "BazelToolchain", "MesonToolchain"]) +def test_warning_message(tool_class): + """FIXME: Remove in Conan 2.0""" + client = TestClient() + r = str(GenConanfile().with_name("lib").with_version("1.0") + .with_settings("os", "arch", "build_type", "compiler") + .with_import("from conan.tools.cmake import CMakeDeps, CMakeToolchain") + .with_import("from conan.tools.gnu import AutotoolsDeps, AutotoolsToolchain") + .with_import("from conan.tools.microsoft import MSBuildDeps, MSBuildToolchain") + .with_import("from conan.tools.google import BazelDeps, BazelToolchain") + .with_import("from conan.tools.meson import MesonToolchain")) + + r += """ + def generate(self): + {}(self) + """.format(tool_class) + + client.save({"conanfile.py": r}) + + client.run("create . ") + assert check_msg in client.out + + client.run("create . -pr:b=default") + assert check_msg not in client.out + + +@pytest.mark.parametrize("cmake_deps_property", ["build_context_activated", + "build_context_build_modules", + "build_context_suffix", + False]) +def test_error_cmake_deps_without_build_profile(cmake_deps_property): + client = TestClient() + r = str(GenConanfile().with_name("lib").with_version("1.0") + .with_settings("os", "arch", "build_type", "compiler") + .with_import("from conan.tools.cmake import CMakeDeps")) + + r += """ + def generate(self): + deps = CMakeDeps(self) + {} + deps.generate() + """.format("deps.{} = ['foo']".format(cmake_deps_property) if cmake_deps_property else "") + + client.save({"conanfile.py": r}) + + client.run("create . ", assert_error=cmake_deps_property) + if cmake_deps_property: + assert "The 'build_context_activated' and 'build_context_build_modules' of the CMakeDeps " \ + "generator cannot be used without specifying a build profile. e.g: -pr:b=default"\ + in client.out + + client.run("create . -pr:b=default") + assert "The 'build_context_activated' and 'build_context_build_modules' of the CMakeDeps " \ + "generator cannot be used without specifying a build profile. e.g: -pr:b=default" \ + not in client.out