summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2019-09-22 18:28:01 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2019-09-23 05:28:31 +0000
commitd8b18385e88df29dd0ce38db484d1d7912ddea15 (patch)
tree21f26772245cd3d3f853b8173dbfd540eff7f16c
parent303095e686bc647b0d6766fa70b18a8bd41f1caf (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-xutil/cmake/pro2cmake.py53
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}")