summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2019-09-30 17:02:08 +0200
committerTobias Hunger <tobias.hunger@qt.io>2019-10-01 14:16:14 +0000
commit1b0710a39380c7f75bba2d777e137f247fcbd5b7 (patch)
treeef4656e8275117366679f17cf756190274a7c928
parentf23b7e1476ded2be43d5e3f03195f522d307b163 (diff)
pro2cmake: Handle SOURCES subtractions
SOURCES -= foo.cpp statements should now be handled correctly by the script. The script uses the same principle as for subdir handling: go through all scopes to collect source removals, and then generate new scopes with total conditions that take into account both additions and subtractions and their conditions. Should handle NO_PCH_SOURCES case as well. Tested on gui.pro, network.pro and qtconnectivity bluetooth.pro. Change-Id: I0cc913ef64cecf09e8ada4e6a3ce3ccb4365b44e Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
-rwxr-xr-xutil/cmake/pro2cmake.py151
1 files changed, 151 insertions, 0 deletions
diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py
index 96d9712bb2..b10df35ffb 100755
--- a/util/cmake/pro2cmake.py
+++ b/util/cmake/pro2cmake.py
@@ -68,6 +68,7 @@ from typing import (
FrozenSet,
Tuple,
Match,
+ Type,
)
from special_case_helper import SpecialCaseHandler
from helper import (
@@ -1886,6 +1887,12 @@ def write_source_file_list(
for key in keys:
sources += scope.get_files(key, use_vpath=True)
+ # Remove duplicates, like in the case when NO_PCH_SOURCES ends up
+ # adding the file to SOURCES, but SOURCES might have already
+ # contained it before. Preserves order in Python 3.7+ because
+ # dict keys are ordered.
+ sources = list(dict.fromkeys(sources))
+
write_list(cm_fh, sources, cmake_parameter, indent, header=header, footer=footer)
@@ -2398,6 +2405,144 @@ def write_wayland_part(cm_fh: typing.IO[str], target: str, scope:Scope, indent:
cm_fh.write(f"\n{spaces(indent)}endif()\n")
+def handle_source_subtractions(scopes: List[Scope]):
+ """
+ Handles source subtractions like SOURCES -= painting/qdrawhelper.cpp
+ by creating a new scope with a new condition containing all addition
+ and subtraction conditions.
+
+ Algorithm is as follows:
+ - Go through each scope and find files in SOURCES starting with "-"
+ - Save that file and the scope condition in modified_sources dict.
+ - Remove the file from the found scope (optionally remove the
+ NO_PCH_SOURCES entry for that file as well).
+ - Go through each file in modified_sources dict.
+ - Find scopes where the file is added, remove the file from that
+ scope and save the condition.
+ - Create a new scope just for that file with a new simplified
+ condition that takes all the other conditions into account.
+ """
+
+ def remove_file_from_operation(
+ scope: Scope, ops_key: str, file: str, op_type: Type[Operation]
+ ) -> bool:
+ """
+ Remove a source file from an operation in a scope.
+ Example: remove foo.cpp from any operations that have
+ ops_key="SOURCES" in "scope", where the operation is of
+ type "op_type".
+
+ The implementation is very rudimentary and might not work in
+ all cases.
+
+ Returns True if a file was found and removed in any operation.
+ """
+ file_removed = False
+ ops = scope._operations.get(ops_key, list())
+ for op in ops:
+ if not isinstance(op, op_type):
+ continue
+ if file in op._value:
+ op._value.remove(file)
+ file_removed = True
+ for include_child_scope in scope._included_children:
+ file_removed = file_removed or remove_file_from_operation(
+ include_child_scope, ops_key, file, op_type
+ )
+ return file_removed
+
+ def join_all_conditions(set_of_alternatives: Set[str]):
+ final_str = ""
+ if set_of_alternatives:
+ alternatives = [f"({alternative})" for alternative in set_of_alternatives]
+ final_str = " OR ".join(sorted(alternatives))
+ return final_str
+
+ modified_sources: Dict[str, Dict[str, Union[Set[str], bool]]] = {}
+
+ new_scopes = []
+ top_most_scope = scopes[0]
+
+ for scope in scopes:
+ sources = scope.get_files("SOURCES")
+ for file in sources:
+ # Find subtractions.
+ if file.startswith("-"):
+ file_without_minus = file[1:]
+
+ if file_without_minus not in modified_sources:
+ modified_sources[file_without_minus] = {}
+
+ subtractions = modified_sources[file_without_minus].get("subtractions", set())
+
+ # Add the condition to the set of conditions and remove
+ # the file subtraction from the processed scope, which
+ # will be later re-added in a new scope.
+ if scope.condition:
+ subtractions.add(scope.total_condition)
+ remove_file_from_operation(scope, "SOURCES", file_without_minus, RemoveOperation)
+ if subtractions:
+ modified_sources[file_without_minus]["subtractions"] = subtractions
+
+ # In case if the source is also listed in a
+ # NO_PCH_SOURCES operation, remove it from there as
+ # well, and add it back later.
+ no_pch_source_removed = remove_file_from_operation(
+ scope, "NO_PCH_SOURCES", file_without_minus, AddOperation
+ )
+ if no_pch_source_removed:
+ modified_sources[file_without_minus]["add_to_no_pch_sources"] = True
+
+ for modified_source in modified_sources:
+ additions = modified_sources[modified_source].get("additions", set())
+ subtractions = modified_sources[modified_source].get("subtractions", set())
+ add_to_no_pch_sources = modified_sources[modified_source].get(
+ "add_to_no_pch_sources", False
+ )
+
+ for scope in scopes:
+ sources = scope.get_files("SOURCES")
+ if modified_source in sources:
+ # Remove the source file from any addition operations
+ # that mention it.
+ remove_file_from_operation(scope, "SOURCES", modified_source, AddOperation)
+ if scope.total_condition:
+ additions.add(scope.total_condition)
+
+ # Construct a condition that takes into account all addition
+ # and subtraction conditions.
+ addition_str = join_all_conditions(additions)
+ if addition_str:
+ addition_str = f"({addition_str})"
+ subtraction_str = join_all_conditions(subtractions)
+ if subtraction_str:
+ subtraction_str = f"NOT ({subtraction_str})"
+
+ condition_str = addition_str
+ if condition_str and subtraction_str:
+ condition_str += " AND "
+ condition_str += subtraction_str
+ condition_simplified = simplify_condition(condition_str)
+
+ # Create a new scope with that condition and add the source
+ # operations.
+ new_scope = Scope(
+ parent_scope=top_most_scope,
+ file=top_most_scope.file,
+ condition=condition_simplified,
+ base_dir=top_most_scope.basedir,
+ )
+ new_scope.total_condition = condition_simplified
+ new_scope._append_operation("SOURCES", AddOperation([modified_source]))
+ if add_to_no_pch_sources:
+ new_scope._append_operation("NO_PCH_SOURCES", AddOperation([modified_source]))
+
+ new_scopes.append(new_scope)
+
+ # Add all the newly created scopes.
+ scopes += new_scopes
+
+
def write_main_part(
cm_fh: IO[str],
name: str,
@@ -2424,6 +2569,12 @@ def write_main_part(
# Merge scopes based on their conditions:
scopes = merge_scopes(scopes)
+ # Handle SOURCES -= foo calls, and merge scopes one more time
+ # because there might have been several files removed with the same
+ # scope condition.
+ handle_source_subtractions(scopes)
+ scopes = merge_scopes(scopes)
+
assert len(scopes)
assert scopes[0].total_condition == "ON"