summaryrefslogtreecommitdiffstats
path: root/util/cmake/pro2cmake.py
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2019-08-01 19:14:58 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2019-08-07 11:55:28 +0000
commitb4ef975a0a6e8c22d3c0851f9d7b11738d37b662 (patch)
treeec5a61420bde635c26a2c3776fc13f52b5b3bf06 /util/cmake/pro2cmake.py
parent2c7ccfefedd582403902879857f34cc2dd373773 (diff)
Handle conditions for SUBDIRS *more* correctly
There are project files that not only do SUBDIRS -= foo depending on some condition, but also SUBDIRS += foo. To handle these cases correctly we need to do a whole pass across all scopes and collect all addition and subtraction conditions. Once we have that information, we can compute a final condition for a particular subdirectory. After we have the condition information for all subdirectories, we can simplify all those conditions using SimPy, and group all subdirectories that have the same simplified condition. Finally we print out the subdirectories grouped by the simplified condition. The end result is similar to how we have extend_target() calls with multiple sources grouped into a single conditional call, except in this case it's subdirectories. Amends b26b1455d75709a53f50e1d3d41c384f8e90b576. Change-Id: I5b648ac67264ba9a940561baee5b49c43c13b721 Reviewed-by: Leander Beernaert <leander.beernaert@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io> Reviewed-by: Qt CMake Build Bot
Diffstat (limited to 'util/cmake/pro2cmake.py')
-rwxr-xr-xutil/cmake/pro2cmake.py180
1 files changed, 124 insertions, 56 deletions
diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py
index 71887bb908..c8a6ba7f88 100755
--- a/util/cmake/pro2cmake.py
+++ b/util/cmake/pro2cmake.py
@@ -1042,67 +1042,135 @@ def map_condition(condition: str) -> str:
return cmake_condition.strip()
-def handle_subdir(scope: Scope, cm_fh: typing.IO[str], *,
- indent: int = 0, is_example: bool=False) -> None:
- ind = ' ' * indent
-
- def find_all_remove_subdir(scope: Scope,
- current_conditions: typing.FrozenSet[str]=None,
- rm_subdir_conditions: typing.Dict[str, typing.Set[typing.FrozenSet[str]]]=None) -> typing.Dict[str, typing.Set[typing.FrozenSet[str]]]:
- rm_subdir_conditions = rm_subdir_conditions if rm_subdir_conditions is not None else dict()
+def handle_subdir(scope: Scope,
+ cm_fh: typing.IO[str],
+ *,
+ indent: int = 0,
+ is_example: bool = False) -> None:
+
+ # Global nested dictionary that will contain sub_dir assignments and their conditions.
+ # Declared as a global in order not to pollute the nested function signatures with giant
+ # type hints.
+ sub_dirs: typing.Dict[str, typing.Dict[str, typing.Set[typing.FrozenSet[str]]]] = {}
+
+ # Collects assignment conditions into global sub_dirs dict.
+ def collect_subdir_info(sub_dir_assignment: str,
+ *,
+ current_conditions: typing.FrozenSet[str] = None):
+ subtraction = sub_dir_assignment.startswith('-')
+ if subtraction:
+ subdir_name = sub_dir_assignment[1:]
+ else:
+ subdir_name = sub_dir_assignment
+ if subdir_name not in sub_dirs:
+ sub_dirs[subdir_name] = {}
+ additions = sub_dirs[subdir_name].get('additions', set())
+ subtractions = sub_dirs[subdir_name].get('subtractions', set())
+ if current_conditions:
+ if subtraction:
+ subtractions.add(current_conditions)
+ else:
+ additions.add(current_conditions)
+ if additions:
+ sub_dirs[subdir_name]['additions'] = additions
+ if subtractions:
+ sub_dirs[subdir_name]['subtractions'] = subtractions
+
+ # Recursive helper that collects subdir info for given scope,
+ # and the children of the given scope.
+ def handle_subdir_helper(scope: Scope,
+ cm_fh: typing.IO[str],
+ *,
+ indent: int = 0,
+ current_conditions: typing.FrozenSet[str] = None,
+ is_example: bool = False):
for sd in scope.get_files('SUBDIRS'):
- if sd.startswith('-') and current_conditions is not None:
- conditions = rm_subdir_conditions.get(sd[1:], set())
- conditions.add(current_conditions)
- rm_subdir_conditions[sd[1:]] = conditions
- current_conditions = current_conditions if current_conditions is not None else frozenset()
- for child_scope in scope.children:
- assert child_scope.condition
- find_all_remove_subdir(child_scope, frozenset((*current_conditions, child_scope.condition)), rm_subdir_conditions)
- return rm_subdir_conditions
-
- rm_subdir_conditions = find_all_remove_subdir(scope)
-
- for sd in scope.get_files('SUBDIRS'):
- if os.path.isdir(sd):
- conditions = rm_subdir_conditions.get(sd)
+ # Collect info about conditions and SUBDIR assignments in the
+ # current scope.
+ if os.path.isdir(sd) or sd.startswith('-'):
+ collect_subdir_info(sd, current_conditions=current_conditions)
+ # For the file case, directly write into the file handle.
+ elif os.path.isfile(sd):
+ subdir_result = parseProFile(sd, debug=False)
+ subdir_scope \
+ = Scope.FromDict(scope, sd,
+ subdir_result.asDict().get('statements'),
+ '', scope.basedir)
+
+ do_include(subdir_scope)
+ cmakeify_scope(subdir_scope, cm_fh, indent=indent, is_example=is_example)
+ else:
+ print(' XXXX: SUBDIR {} in {}: Not found.'.format(sd, scope))
+
+ # Collect info about conditions and SUBDIR assignments in child
+ # scopes, aka recursively call the same function, but with an
+ # updated current_conditions frozen set.
+ for c in scope.children:
+ handle_subdir_helper(c, cm_fh,
+ indent=indent + 1,
+ is_example=is_example,
+ current_conditions=frozenset((*current_conditions, c.condition)))
+
+ def group_and_print_sub_dirs(indent: int = 0):
+ # Simplify conditions, and group
+ # subdirectories with the same conditions.
+ grouped_sub_dirs = {}
+ for subdir_name in sub_dirs:
+ additions = sub_dirs[subdir_name].get('additions', set())
+ subtractions = sub_dirs[subdir_name].get('subtractions', set())
+
+ # An empty condition key represents the group of sub dirs
+ # that should be added unconditionally.
+ condition_key = ''
+ if additions or subtractions:
+ addition_str = ''
+ subtraction_str = ''
+ if additions:
+ addition_str = " OR ".join(sorted("(" + " AND ".join(condition) + ")"
+ for condition in additions))
+ if addition_str:
+ addition_str = '({})'.format(addition_str)
+ if subtractions:
+ subtraction_str = " OR ".join(sorted("(" + " AND ".join(condition) + ")"
+ for condition in subtractions))
+ if subtraction_str:
+ subtraction_str = 'NOT ({})'.format(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)
+ condition_key = condition_simplified
+
+ sub_dir_list_by_key = grouped_sub_dirs.get(condition_key, [])
+ sub_dir_list_by_key.append(subdir_name)
+ grouped_sub_dirs[condition_key] = sub_dir_list_by_key
+
+ # Print the groups.
+ ind = ' ' * indent
+ for condition_key in grouped_sub_dirs:
cond_ind = ind
- if conditions:
- conditions_str = " OR ".join(sorted("(" + " AND ".join(condition) + ")" for condition in conditions))
- conditions_str_wrapped = "NOT ({})".format(conditions_str)
- conditions_simplified = simplify_condition(conditions_str_wrapped)
- cm_fh.write(f'{ind}if({conditions_simplified})\n')
+ if condition_key:
+ cm_fh.write(f'{ind}if({condition_key})\n')
cond_ind += " "
- cm_fh.write(f'{cond_ind}add_subdirectory({sd})\n')
- if conditions:
+
+ sub_dir_list_by_key = grouped_sub_dirs.get(condition_key, [])
+ for subdir_name in sub_dir_list_by_key:
+ cm_fh.write(f'{cond_ind}add_subdirectory({subdir_name})\n')
+ if condition_key:
cm_fh.write(f'{ind}endif()\n')
- elif os.path.isfile(sd):
- subdir_result = parseProFile(sd, debug=False)
- subdir_scope \
- = Scope.FromDict(scope, sd,
- subdir_result.asDict().get('statements'),
- '', scope.basedir)
-
- do_include(subdir_scope)
- cmakeify_scope(subdir_scope, cm_fh, indent=indent, is_example=is_example)
- elif sd.startswith('-'):
- pass
- else:
- print(' XXXX: SUBDIR {} in {}: Not found.'.format(sd, scope))
- for c in scope.children:
- cond = c.condition
- temp_buf = io.StringIO('') # we do not want to print empty conditions
- handle_subdir(c, temp_buf, indent=indent + 1, is_example=is_example)
- sub_call_str = temp_buf.getvalue()
- if sub_call_str:
- if cond == 'else':
- cm_fh.write('\n{}else()\n'.format(ind))
- elif cond:
- cm_fh.write('\n{}if({})\n'.format(ind, cond))
- cm_fh.write(sub_call_str)
- if cond:
- cm_fh.write('{}endif()\n'.format(ind))
+ # A set of conditions which will be ANDed together. The set is recreated with more conditions
+ # as the scope deepens.
+ current_conditions = frozenset()
+
+ # Do the work.
+ handle_subdir_helper(scope, cm_fh,
+ indent=indent,
+ current_conditions=current_conditions,
+ is_example=is_example)
+ group_and_print_sub_dirs(indent=indent)
def sort_sources(sources: typing.List[str]) -> typing.List[str]: