From 86bbbd07f7ebf18cb83c15abfaf5865bbfb7469d Mon Sep 17 00:00:00 2001 From: Luis Caro Campos <3535649+jcar87@users.noreply.github.com> Date: Thu, 8 Aug 2024 18:01:03 +0100 Subject: [PATCH] qt refactor option handling and error reporting --- recipes/qt/5.x.x/conanfile.py | 69 ++++++++++++++++++++--------- recipes/qt/6.x.x/conanfile.py | 81 ++++++++++++++++++++++------------- 2 files changed, 100 insertions(+), 50 deletions(-) diff --git a/recipes/qt/5.x.x/conanfile.py b/recipes/qt/5.x.x/conanfile.py index 3f3977990a25bb..03e21569835c80 100644 --- a/recipes/qt/5.x.x/conanfile.py +++ b/recipes/qt/5.x.x/conanfile.py @@ -123,9 +123,10 @@ class QtConan(ConanFile): "sysroot": None, "config": None, "multiconfiguration": False, - "essential_modules": not os.getenv('CONAN_CENTER_BUILD_SERVICE') } - default_options.update({f"{status}_modules": False for status in _module_statuses if status != "essential"}) + # essential_modules, addon_modules, deprecated_modules, preview_modules: + # these are only provided for convenience, set to False by default + default_options.update({f"{status}_modules": False for status in _module_statuses}) no_copy_source = True short_paths = True @@ -249,25 +250,43 @@ def configure(self): for m in submodules_tree: assert m in ["qtbase", "qtqa", "qtrepotools"] or m in self._submodules, "module %s is not present in recipe options : (%s)" % (m, ",".join(self._submodules)) - for m in self._submodules: - if m not in submodules_tree: - delattr(self.options, m) + for module in self._submodules: + if module not in submodules_tree: + self.output.debug(f"qt5: removing {module} from options as it is not an option for this version, or it is ignored or obsolete") + self.options.rm_safe(module) + + # Requested modules: + # - any module for non-removed options that have 'True' value + # - any enabled via `xxx_modules` that does not have a 'False' value + # Note that at this point, the submodule options dont have a value unless one is given externally + # to the recipe (e.g. via the command line, a profile, or a consumer) + requested_modules = set([module for module in self._submodules if self.options.get_safe(module)]) + for module in [m for m in self._submodules if m in submodules_tree]: + status = submodules_tree[module]['status'] + is_disabled = self.options.get_safe(module) == False + if self.options.get_safe(f"{status}_modules"): + if not is_disabled: + requested_modules.add(module) + else: + self.output.debug(f"qt5: {module} requested because {status}_modules=True" + f" but it has been explicitly disabled with {module}=False") - def _enablemodule(mod): - if mod != "qtbase": - setattr(self.options, mod, True) - for req in submodules_tree[mod]["depends"]: - _enablemodule(req) + self.output.debug(f"qt5: requested modules {requested_modules}") - for module in self._submodules: - if self.options.get_safe(module): - _enablemodule(module) - else: - if module in submodules_tree: - for status in self._module_statuses: - if getattr(self.options, f"{status}_modules") and submodules_tree[module]['status'] == status: - _enablemodule(module) - break + required_modules = set() + for module in requested_modules: + required_modules.update(submodules_tree[module]["depends"]) + + required_but_disabled = [m for m in required_modules if self.options.get_safe(m) == False] + self.output.debug(f"qt5: required_modules modules {required_modules}") + if required_but_disabled: + raise ConanInvalidConfiguration(f"Modules {', '.join(required_but_disabled)} are required by other options, but are explicitly disabled") + + enabled_modules = requested_modules.union(required_modules) + enabled_modules.discard("qtbase") + + for module in list(enabled_modules): + setattr(self.options, module, True) for module in self._submodules: if module in self.options and not self.options.get_safe(module): @@ -283,6 +302,16 @@ def _enablemodule(mod): if self.options.qtwebengine: self.options.with_fontconfig = True + for status in self._module_statuses: + # These are convenience only, should not affect package_id + option_name = f"{status}_modules" + self.output.debug(f"qt5 removing convenience option: {option_name}," + f" see individual module options") + self.options.rm_safe(option_name) + + for option in self.options.items(): + self.output.debug(f"qt5 option {option[0]}={option[1]}") + def validate(self): if self.settings.compiler.get_safe("cppstd"): check_min_cppstd(self, "11") @@ -438,8 +467,6 @@ def package_id(self): self.info.settings.compiler.runtime_type = "Release/Debug" if self.info.settings.os == "Android": del self.info.options.android_sdk - for status in self._module_statuses: - delattr(self.info.options, f"{status}_modules") def build_requirements(self): if self._settings_build.os == "Windows" and is_msvc(self): diff --git a/recipes/qt/6.x.x/conanfile.py b/recipes/qt/6.x.x/conanfile.py index 15b0c62488f23c..9efa3f7c03d86b 100644 --- a/recipes/qt/6.x.x/conanfile.py +++ b/recipes/qt/6.x.x/conanfile.py @@ -122,9 +122,10 @@ class QtConan(ConanFile): "sysroot": None, "multiconfiguration": False, "disabled_features": "", - "essential_modules": not os.getenv('CONAN_CENTER_BUILD_SERVICE') } - default_options.update({f"{status}_modules": False for status in _module_statuses if status != "essential"}) + # essential_modules, addon_modules, deprecated_modules, preview_modules: + # these are only provided for convenience, set to False by default + default_options.update({f"{status}_modules": False for status in _module_statuses}) short_paths = True @@ -182,9 +183,10 @@ def config_options(self): if self.settings.os != "Linux": self.options.qtwayland = False - for m in self._submodules: - if m not in self._get_module_tree: - delattr(self.options, m) + for submodule in self._submodules: + if submodule not in self._get_module_tree: + self.output.debug(f"Qt6: Removing {submodule} option as it is not in the module tree for this version, or is marked as obsolete or ignore") + self.options.rm_safe(submodule) @property def _minimum_compilers_version(self): @@ -213,28 +215,41 @@ def configure(self): if self.options.multiconfiguration: del self.settings.build_type - def _enablemodule(mod): - if mod != "qtbase": - setattr(self.options, mod, True) - for req in self._get_module_tree[mod]["depends"]: - _enablemodule(req) - - # enable all modules which are - # - required by a module explicitely enabled by the consumer - for module_name, module in self._get_module_tree.items(): - if getattr(self.options, module_name): - _enablemodule(module_name) - else: - for status in self._module_statuses: - if getattr(self.options, f"{status}_modules") and module['status'] == status: - _enablemodule(module_name) - break - - # disable all modules which are: - # - not explicitely enabled by the consumer and - # - not required by a module explicitely enabled by the consumer - for module in self._get_module_tree: - if getattr(self.options, module).value is None: + # Requested modules: + # - any module for non-removed options that have 'True' value + # - any enabled via `xxx_modules` that does not have a 'False' value + # Note that at this point, the submodule options dont have a value unless one is given externally + # to the recipe (e.g. via the command line, a profile, or a consumer) + requested_modules = set([module for module in self._submodules if self.options.get_safe(module)]) + for module in [m for m in self._submodules if m in self._get_module_tree]: + status = self._get_module_tree[module]['status'] + is_disabled = self.options.get_safe(module) == False + if self.options.get_safe(f"{status}_modules"): + if not is_disabled: + requested_modules.add(module) + else: + self.output.debug(f"qt6: {module} requested because {status}_modules=True" + f" but it has been explicitly disabled with {module}=False") + + self.output.debug(f"qt6: requested modules {requested_modules}") + + required_modules = set() + for module in requested_modules: + required_modules.update(self._get_module_tree[module]["depends"]) + + required_but_disabled = [m for m in required_modules if self.options.get_safe(m) == False] + self.output.debug(f"qt6: required_modules modules {required_modules}") + if required_but_disabled: + raise ConanInvalidConfiguration(f"Modules {', '.join(required_but_disabled)} are required by other options, but are explicitly disabled") + + enabled_modules = requested_modules.union(required_modules) + enabled_modules.discard("qtbase") + + for module in list(enabled_modules): + setattr(self.options, module, True) + + for module in self._submodules: + if module in self.options and not self.options.get_safe(module): setattr(self.options, module, False) if not self.options.get_safe("qtmultimedia"): @@ -247,6 +262,16 @@ def _enablemodule(mod): if self.options.get_safe("qtwebengine"): self.options.with_fontconfig = True + for status in self._module_statuses: + # These are convenience only, should not affect package_id + option_name = f"{status}_modules" + self.output.debug(f"qt5 removing convenience option: {option_name}," + f" see individual module options") + self.options.rm_safe(option_name) + + for option in self.options.items(): + self.output.debug(f"qt6 option: {option}") + def validate(self): if os.getenv('CONAN_CENTER_BUILD_SERVICE') is not None: if self.info.settings.compiler == "gcc" and Version(self.info.settings.compiler.version) >= "11" or \ @@ -649,8 +674,6 @@ def package_id(self): self.info.settings.compiler.runtime_type = "Release/Debug" if self.info.settings.os == "Android": del self.info.options.android_sdk - for status in self._module_statuses: - delattr(self.info.options, f"{status}_modules") def source(self): destination = self.source_folder