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:
parent
199cce0c20
commit
35a30c7ebb
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user