diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-09-22 18:28:01 +0200 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-09-23 05:28:31 +0000 |
commit | d8b18385e88df29dd0ce38db484d1d7912ddea15 (patch) | |
tree | 21f26772245cd3d3f853b8173dbfd540eff7f16c | |
parent | 303095e686bc647b0d6766fa70b18a8bd41f1caf (diff) |
pro2cmake: Improve handling of requires clauses
Change the grammar to parse and extract the whole expression
that is present in the requires clause.
Make sure to preprocess the parsed content as a condition,
so that the value passed to map_condition and simplify_condition
is valid and the functions can handle more complicated conditions
like qtConfig() and if().
Wrap the final condition with an extra pair of parentheses, so that
the negated condition is computed correctly.
Handle the require clause in subdir projects, top level tests projects,
regular test projects, as well as top level repo projects.
Examples are not yet handled, because the would require some kind of
CMake public api to e.g. query if a feature is enabled.
Change-Id: I9af96cf022e47b66f24db3ca15d3803dda7a5d7c
Reviewed-by: Qt CMake Build Bot
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rwxr-xr-x | util/cmake/pro2cmake.py | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py index aad0d621f6..797844f7d5 100755 --- a/util/cmake/pro2cmake.py +++ b/util/cmake/pro2cmake.py @@ -49,6 +49,7 @@ import xml.etree.ElementTree as ET from argparse import ArgumentParser from textwrap import dedent +from textwrap import indent as textwrap_indent from itertools import chain from functools import lru_cache from shutil import copyfile @@ -1271,8 +1272,22 @@ class QmakeParser: Load = add_element("Load", pp.Keyword("load") + CallArgs("loaded")) Include = add_element("Include", pp.Keyword("include") + CallArgs("included")) Option = add_element("Option", pp.Keyword("option") + CallArgs("option")) + RequiresCondition = add_element("RequiresCondition", pp.originalTextFor(pp.nestedExpr())) + + def parse_requires_condition(s, l, t): + # The following expression unwraps the condition via the additional info + # set by originalTextFor. + condition_without_parentheses = s[t._original_start + 1 : t._original_end - 1] + + # And this replaces the colons with '&&' similar how it's done for 'Condition'. + condition_without_parentheses = ( + condition_without_parentheses.strip().replace(":", " && ").strip(" && ") + ) + return condition_without_parentheses + + RequiresCondition.setParseAction(parse_requires_condition) Requires = add_element( - "Requires", pp.Keyword("requires") + CallArgs("project_required_condition") + "Requires", pp.Keyword("requires") + RequiresCondition("project_required_condition") ) # ignore the whole thing... @@ -1598,7 +1613,7 @@ def handle_subdir( current_conditions=frozenset((*current_conditions, child_condition)), ) - def group_and_print_sub_dirs(indent: int = 0): + def group_and_print_sub_dirs(scope: Scope, indent: int = 0): # Simplify conditions, and group # subdirectories with the same conditions. grouped_sub_dirs = {} @@ -1652,6 +1667,9 @@ def handle_subdir( sub_dir_list_by_key.append(subdir_name) grouped_sub_dirs[condition_key] = sub_dir_list_by_key + # Print any requires() blocks. + cm_fh.write(expand_project_requirements(scope)) + # Print the groups. ind = spaces(indent) for condition_key in grouped_sub_dirs: @@ -1678,7 +1696,7 @@ def handle_subdir( handle_subdir_helper( scope, cm_fh, indent=indent, current_conditions=current_conditions, is_example=is_example ) - group_and_print_sub_dirs(indent=indent) + group_and_print_sub_dirs(scope, indent=indent) def sort_sources(sources: List[str]) -> List[str]: @@ -2352,19 +2370,22 @@ def write_statecharts(cm_fh: IO[str], target: str, scope: Scope, indent: int = 0 cm_fh.write(")\n") -def expand_project_requirements(scope: Scope) -> str: +def expand_project_requirements(scope: Scope, skip_message: bool = False) -> str: requirements = "" for requirement in scope.get("_REQUIREMENTS"): original_condition = simplify_condition(map_condition(requirement)) - inverted_requirement = simplify_condition(f"NOT {map_condition(requirement)}") + inverted_requirement = simplify_condition(f"NOT ({map_condition(requirement)})") + if not skip_message: + message = f""" +{spaces(7)}message(NOTICE "Skipping the build as the condition \\"{original_condition}\\" is not met.")""" + else: + message = "" requirements += dedent( f"""\ - if({inverted_requirement}) - message(NOTICE "Skipping the build as the condition \\"{original_condition}\\" is not met.") + if({inverted_requirement}){message} return() endif() - - """ +""" ) return requirements @@ -2683,6 +2704,11 @@ def write_test(cm_fh: IO[str], scope: Scope, gui: bool = False, *, indent: int = for path in importpath: extra.append(f' "{path}"') + requires_content = expand_project_requirements(scope, skip_message=True) + if requires_content: + requires_content += "\n" + cm_fh.write(requires_content) + write_main_part( cm_fh, test_name, @@ -3131,16 +3157,21 @@ def handle_top_level_repo_tests_project(scope: Scope, cm_fh: IO[str]): else: qt_lib = "Tests_FIXME" + requires_content = expand_project_requirements(scope, skip_message=True) + if requires_content: + requires_content = f"\n\n{textwrap_indent(requires_content, spaces(3))}" + content = dedent( f"""\ if(NOT TARGET Qt::Test) cmake_minimum_required(VERSION {cmake_version_string}) project({qt_lib} VERSION 6.0.0 LANGUAGES C CXX) find_package(Qt6 ${{PROJECT_VERSION}} REQUIRED COMPONENTS BuildInternals Core SET_ME_TO_SOMETHING_USEFUL) - find_package(Qt6 ${{PROJECT_VERSION}} OPTIONAL_COMPONENTS SET_ME_TO_SOMETHING_USEFUL) + find_package(Qt6 ${{PROJECT_VERSION}} OPTIONAL_COMPONENTS SET_ME_TO_SOMETHING_USEFUL){requires_content} qt_set_up_standalone_tests_build() endif() - qt_build_tests()""" + qt_build_tests() +""" ) cm_fh.write(f"{content}") |