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 <albert.astals.cid@kdab.com>
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
This commit is contained in:
Tobias Hunger 2019-02-07 15:30:44 +01:00
parent 199cce0c20
commit 35a30c7ebb

View File

@ -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)