From 35a30c7ebbd50e8b5b1fad7c00bd6c36b0dca8b9 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Thu, 7 Feb 2019 15:30:44 +0100 Subject: [PATCH] CMake: pro2cmake.py: Expand qmake values in file names, etc. Expand qmake values when dealing with source file names, include directories and more. This handles cases where variables are used to refer to sources (e.g. $$VERSIONTAGGING_SOURCES in corelib) as well as things like $$QT_SOURCE_TREE and friends. Note that $$PWD and $$OUT_PWD are still need hand-holding since they refer to the scopes directory relative to the top level directory -- which pro2cmake.py does not know. Change-Id: I011ef55416ff820053d5f844b3008836849f5075 Reviewed-by: Albert Astals Cid Reviewed-by: Frederik Gladhorn --- util/cmake/pro2cmake.py | 64 +++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py index 5c804826c42..9cd1b7a5424 100755 --- a/util/cmake/pro2cmake.py +++ b/util/cmake/pro2cmake.py @@ -77,14 +77,10 @@ def spaces(indent: int) -> str: def map_to_file(f: str, top_dir: str, current_dir: str, want_absolute_path: bool = False) -> typing.Optional[str]: - if f == '$$NO_PCH_SOURCES': - return None if f.startswith('$$PWD/') or f == '$$PWD': # INCLUDEPATH += $$PWD return os.path.join(os.path.relpath(current_dir, top_dir), f[6:]) if f.startswith('$$OUT_PWD/'): return "${CMAKE_CURRENT_BUILD_DIR}/" + f[10:] - if f.startswith('$$QT_SOURCE_TREE'): - return "${PROJECT_SOURCE_DIR}/" + f[17:] if f.startswith("./"): return os.path.join(current_dir, f) if current_dir != '.' else f[2:] if want_absolute_path and not os.path.isabs(f): @@ -102,8 +98,6 @@ def map_source_to_cmake(source: str, base_dir: str, return source[2:] if source == '.': return "${CMAKE_CURRENT_SOURCE_DIR}" - if source.startswith('$$QT_SOURCE_TREE/'): - return "${PROJECT_SOURCE_DIR}/" + source[17:] if os.path.exists(os.path.join(base_dir, source)): return source @@ -201,7 +195,10 @@ class Scope(object): parent_scope: typing.Optional[Scope], file: typing.Optional[str] = None, condition: str = '', base_dir: str = '', - operations: typing.Mapping[str, typing.List[Operation]] = {}) -> None: + operations: typing.Mapping[str, typing.List[Operation]] = { + 'QT_SOURCE_TREE': [SetOperation('${PROJECT_SOURCE_DIR}')], + 'QT_BUILD_TREE': [SetOperation('${PROJECT_BUILD_DIR}')], + }) -> None: if parent_scope: parent_scope._add_child(self) else: @@ -453,6 +450,33 @@ class Scope(object): assert len(v) == 1 return v[0] + def _expand_value(self, value: str) -> typing.List[str]: + result = value + pattern = re.compile(r'\$\$\{?([A-Za-z_][A-Za-z0-9_]*)\}?') + match = re.search(pattern, result) + while match: + if match.group(0) == value: + return self.expand(match.group(1), '') + else: + result = result[:match.start()] \ + + self.expandString(match.group(1)) \ + + result[match.end():] + match = re.search(pattern, result) + return [result] + + def expand(self, key: str, default=None) -> typing.List[str]: + value = self.get(key, default) + result: typing.List[str] = [] + assert isinstance(value, list) + for v in value: + result += self._expand_value(v) + return result + + def expandString(self, key: str) -> str: + result = self._expand_value(self.getString(key)) + assert len(result) == 1 + return result[0] + @property def TEMPLATE(self) -> str: return self.getString('TEMPLATE', 'app') @@ -715,10 +739,10 @@ def write_sources_section(cm_fh: typing.IO[str], scope: Scope, *, if plugin_type: cm_fh.write('{} TYPE {}\n'.format(ind, plugin_type[0])) - sources = scope.get('SOURCES') + scope.get('HEADERS') \ - + scope.get('OBJECTIVE_SOURCES') + scope.get('NO_PCH_SOURCES') \ - + scope.get('FORMS') - resources = scope.get('RESOURCES') + sources = scope.expand('SOURCES') + scope.expand('HEADERS') \ + + scope.expand('OBJECTIVE_SOURCES') + scope.expand('NO_PCH_SOURCES') \ + + scope.expand('FORMS') + resources = scope.expand('RESOURCES') if resources: qrc_only = True for r in resources: @@ -731,7 +755,7 @@ def write_sources_section(cm_fh: typing.IO[str], scope: Scope, *, else: sources += resources - vpath = scope.get('VPATH') + vpath = scope.expand('VPATH') sources = [map_source_to_cmake(s, scope.basedir, vpath) for s in sources] if sources: @@ -739,26 +763,27 @@ def write_sources_section(cm_fh: typing.IO[str], scope: Scope, *, for l in sort_sources(sources): cm_fh.write('{} {}\n'.format(ind, l)) - defines = scope.get('DEFINES') + defines = scope.expand('DEFINES') if defines: cm_fh.write('{} DEFINES\n'.format(ind)) for d in defines: d = d.replace('=\\\\\\"$$PWD/\\\\\\"', '="${CMAKE_CURRENT_SOURCE_DIR}/"') cm_fh.write('{} {}\n'.format(ind, d)) - includes = scope.get('INCLUDEPATH') + includes = scope.expand('INCLUDEPATH') if includes: cm_fh.write('{} INCLUDE_DIRECTORIES\n'.format(ind)) for i in includes: i = i.rstrip('/') or ('/') + i = map_source_to_cmake(i, scope.basedir, vpath) cm_fh.write('{} {}\n'.format(ind, i)) - dependencies = [map_qt_library(q) for q in scope.get('QT') + dependencies = [map_qt_library(q) for q in scope.expand('QT') if map_qt_library(q) not in known_libraries] - dependencies += [map_qt_library(q) for q in scope.get('QT_FOR_PRIVATE') + dependencies += [map_qt_library(q) for q in scope.expand('QT_FOR_PRIVATE') if map_qt_library(q) not in known_libraries] - dependencies += scope.get('QMAKE_USE_PRIVATE') + scope.get('QMAKE_USE') \ - + scope.get('LIBS_PRIVATE') + scope.get('LIBS') + dependencies += scope.expand('QMAKE_USE_PRIVATE') + scope.expand('QMAKE_USE') \ + + scope.expand('LIBS_PRIVATE') + scope.expand('LIBS') if dependencies: cm_fh.write('{} LIBRARIES\n'.format(ind)) is_framework = False @@ -807,7 +832,8 @@ def is_simple_condition(condition: str) -> bool: def write_ignored_keys(scope: Scope, ignored_keys, indent) -> str: result = '' for k in sorted(ignored_keys): - if k == '_INCLUDED' or k == 'TARGET' or k == 'QMAKE_DOCS': + if k == '_INCLUDED' or k == 'TARGET' or k == 'QMAKE_DOCS' or k == 'QT_SOURCE_TREE' \ + or k == 'QT_BUILD_TREE': # All these keys are actually reported already continue values = scope.get(k)