diff --git a/conan/tools/__init__.py b/conan/tools/__init__.py index 06b817f9800..a8a45d35375 100644 --- a/conan/tools/__init__.py +++ b/conan/tools/__init__.py @@ -1,9 +1,4 @@ from conans.model.build_info import CppInfo as _CppInfo -from conan.tools.helpers import ( - default_config_options, - default_configure, - default_package_id -) def CppInfo(conanfile): diff --git a/conans/client/conanfile/configure.py b/conans/client/conanfile/configure.py index cabfb324df2..4cff7a65a44 100644 --- a/conans/client/conanfile/configure.py +++ b/conans/client/conanfile/configure.py @@ -1,7 +1,7 @@ from conans.errors import conanfile_exception_formatter from conans.model.pkg_type import PackageType from conans.model.requires import BuildRequirements, TestRequirements, ToolRequirements -from conan.tools import default_config_options, default_configure +from conans.client.conanfile.implementations import auto_shared_fpic_config_options, auto_shared_fpic_configure def run_configure_method(conanfile, down_options, profile_options, ref): @@ -10,8 +10,8 @@ def run_configure_method(conanfile, down_options, profile_options, ref): if hasattr(conanfile, "config_options"): with conanfile_exception_formatter(conanfile, "config_options"): conanfile.config_options() - else: - default_config_options(conanfile) + elif "auto_shared_fpic" in conanfile.implements: + auto_shared_fpic_config_options(conanfile) # Assign only the current package options values, but none of the dependencies is_consumer = conanfile._conan_is_consumer @@ -20,8 +20,8 @@ def run_configure_method(conanfile, down_options, profile_options, ref): if hasattr(conanfile, "configure"): with conanfile_exception_formatter(conanfile, "configure"): conanfile.configure() - else: - default_configure(conanfile) + elif "auto_shared_fpic" in conanfile.implements: + auto_shared_fpic_configure(conanfile) self_options, up_options = conanfile.options.get_upstream_options(down_options, ref, is_consumer) diff --git a/conan/tools/helpers.py b/conans/client/conanfile/implementations.py similarity index 78% rename from conan/tools/helpers.py rename to conans/client/conanfile/implementations.py index 5e9d40fe0f1..133ddcea7e5 100644 --- a/conan/tools/helpers.py +++ b/conans/client/conanfile/implementations.py @@ -1,12 +1,12 @@ from conans.model.pkg_type import PackageType -def default_config_options(conanfile): +def auto_shared_fpic_config_options(conanfile): if conanfile.settings.get_safe("os") == "Windows": conanfile.options.rm_safe("fPIC") -def default_configure(conanfile): +def auto_shared_fpic_configure(conanfile): if conanfile.options.get_safe("header_only"): conanfile.options.rm_safe("fPIC") conanfile.options.rm_safe("shared") @@ -14,6 +14,6 @@ def default_configure(conanfile): conanfile.options.rm_safe("fPIC") -def default_package_id(conanfile): +def auto_header_only_package_id(conanfile): if conanfile.options.get_safe("header_only") or conanfile.package_type is PackageType.HEADER: conanfile.info.clear() diff --git a/conans/client/graph/compute_pid.py b/conans/client/graph/compute_pid.py index 66181e61e7a..8dc42beb680 100644 --- a/conans/client/graph/compute_pid.py +++ b/conans/client/graph/compute_pid.py @@ -3,7 +3,7 @@ from conans.errors import conanfile_exception_formatter, ConanInvalidConfiguration, \ conanfile_remove_attr, ConanException from conans.model.info import ConanInfo, RequirementsInfo, RequirementInfo, PythonRequiresInfo -from conan.tools import default_package_id +from conans.client.conanfile.implementations import auto_header_only_package_id def compute_package_id(node, new_config): @@ -82,6 +82,7 @@ def run_validate_package_id(conanfile): with conanfile_exception_formatter(conanfile, "package_id"): with conanfile_remove_attr(conanfile, ['cpp_info', 'settings', 'options'], "package_id"): conanfile.package_id() - else: - default_package_id(conanfile) + elif "auto_header_only" in conanfile.implements: + auto_header_only_package_id(conanfile) + conanfile.info.validate() diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 43cd2f397ac..33847dc1477 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -48,6 +48,8 @@ class ConanFile: default_options = None package_type = None + implements = [] + provides = None deprecated = None diff --git a/conans/test/functional/toolchains/cmake/test_cmake.py b/conans/test/functional/toolchains/cmake/test_cmake.py index feeeef80a50..38f7319fd30 100644 --- a/conans/test/functional/toolchains/cmake/test_cmake.py +++ b/conans/test/functional/toolchains/cmake/test_cmake.py @@ -57,6 +57,7 @@ class App(ConanFile): generators = "CMakeDeps" options = {"shared": [True, False], "fPIC": [True, False]} default_options = {"shared": False, "fPIC": True} + implements = ["auto_shared_fpic", "auto_header_only"] def generate(self): tc = CMakeToolchain(self) @@ -395,6 +396,7 @@ def test_toolchain_linux(self, build_type, cppstd, arch, libcxx, shared): "CMAKE_EXE_LINKER_FLAGS": arch_str, "COMPILE_DEFINITIONS": defines, # fPIC is managed automatically depending on the shared option value + # if implements = ["auto_shared_fpic", "auto_header_only"] "CMAKE_POSITION_INDEPENDENT_CODE": "ON" if not shared else "" } diff --git a/conans/test/integration/options/test_configure_options.py b/conans/test/integration/options/test_configure_options.py index f007fc835a4..5bfff4b95b8 100644 --- a/conans/test/integration/options/test_configure_options.py +++ b/conans/test/integration/options/test_configure_options.py @@ -27,8 +27,8 @@ class ConfigureOptionsTest(unittest.TestCase): ]) def test_methods_not_defined(self, settings_os, shared, fpic, header_only, result): """ - Test that options are managed automatically when methods config_otpions and configure are not - defined. + Test that options are managed automatically when methods config_options and configure are not + defined and implements = ["auto_shared_fpic", "auto_header_only"]. Check that header only package gets its unique package ID. """ client = TestClient() @@ -39,6 +39,7 @@ class Pkg(ConanFile): settings = "os", "compiler", "arch", "build_type" options = {{"shared": [True, False], "fPIC": [True, False], "header_only": [True, False]}} default_options = {{"shared": {shared}, "fPIC": {fpic}, "header_only": {header_only}}} + implements = ["auto_shared_fpic", "auto_header_only"] def build(self): shared = self.options.get_safe("shared") @@ -73,7 +74,7 @@ def build(self): ]) def test_optout(self, settings_os, shared, fpic, header_only, result): """ - Test that options are not managed automatically when methods are defined. + Test that options are not managed automatically when methods are defined even if implements = ["auto_shared_fpic", "auto_header_only"] Check that header only package gets its unique package ID. """ client = TestClient() @@ -84,6 +85,7 @@ class Pkg(ConanFile): settings = "os", "compiler", "arch", "build_type" options = {{"shared": [True, False], "fPIC": [True, False], "header_only": [True, False]}} default_options = {{"shared": {shared}, "fPIC": {fpic}, "header_only": {header_only}}} + implements = ["auto_shared_fpic", "auto_header_only"] def config_options(self): pass @@ -104,53 +106,6 @@ def build(self): if header_only: self.assertIn("Package 'da39a3ee5e6b4b0d3255bfef95601890afd80709' created", client.out) - @parameterized.expand([ - ["Linux", False, False, False, [False, False, False]], - ["Windows", False, False, False, [False, None, False]], - ["Windows", True, False, False, [True, None, False]], - ["Windows", False, False, True, [None, None, True]], - ["Linux", False, False, True, [None, None, True]], - ["Linux", True, True, False, [True, None, False]], - ["Linux", True, False, False, [True, None, False]], - ["Linux", True, True, True, [None, None, True]], - ["Linux", True, True, True, [None, None, True]], - ["Linux", False, True, False, [False, True, False]], - ["Linux", False, True, False, [False, True, False]], - ]) - def test_methods_defined_explicit(self, settings_os, shared, fpic, header_only, result): - """ - Test that options are managed when the tool is used in methods defined by user. - Check that header only package gets its unique package ID. - """ - client = TestClient() - conanfile = textwrap.dedent(f"""\ - from conan import ConanFile - from conan.tools import default_config_options, default_configure - - class Pkg(ConanFile): - settings = "os", "compiler", "arch", "build_type" - options = {{"shared": [True, False], "fPIC": [True, False], "header_only": [True, False]}} - default_options = {{"shared": {shared}, "fPIC": {fpic}, "header_only": {header_only}}} - - def config_options(self): - default_config_options(self) - - def configure(self): - default_configure(self) - - def build(self): - shared = self.options.get_safe("shared") - fpic = self.options.get_safe("fPIC") - header_only = self.options.get_safe("header_only") - self.output.info(f"shared: {{shared}}, fPIC: {{fpic}}, header only: {{header_only}}") - """) - client.save({"conanfile.py": conanfile}) - client.run(f"create . --name=pkg --version=0.1 -s os={settings_os}") - result = f"shared: {result[0]}, fPIC: {result[1]}, header only: {result[2]}" - self.assertIn(result, client.out) - if header_only: - self.assertIn("Package 'da39a3ee5e6b4b0d3255bfef95601890afd80709' created", client.out) - def test_header_package_type_pid(self): """ Test that we get the pid for header only when package type is set to header-library @@ -162,6 +117,7 @@ def test_header_package_type_pid(self): class Pkg(ConanFile): settings = "os", "compiler", "arch", "build_type" package_type = "header-library" + implements = ["auto_shared_fpic", "auto_header_only"] """) client.save({"conanfile.py": conanfile}) diff --git a/conans/test/integration/package_id/test_default_package_id.py b/conans/test/integration/package_id/test_default_package_id.py index 627756567f4..323c8b48bf7 100644 --- a/conans/test/integration/package_id/test_default_package_id.py +++ b/conans/test/integration/package_id/test_default_package_id.py @@ -23,9 +23,9 @@ def test_default_package_id_options(typedep, typeconsumer, different_id): """ c = TestClient() dep = GenConanfile("dep", "0.1").with_option("myopt", [True, False]) \ - .with_package_type(typedep) + .with_package_type(typedep).with_class_attribute('implements = ["auto_shared_fpic", "auto_header_only"]') consumer = GenConanfile("consumer", "0.1").with_requires("dep/0.1")\ - .with_package_type(typeconsumer) + .with_package_type(typeconsumer).with_class_attribute('implements = ["auto_shared_fpic", "auto_header_only"]') c.save({"dep/conanfile.py": dep, "consumer/conanfile.py": consumer})