summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Hunger <tobias.hunger@qt.io>2019-05-07 11:27:33 +0200
committerTobias Hunger <tobias.hunger@qt.io>2019-05-09 07:37:42 +0000
commit5608bf3cbadefb2c73b23e4b90b8211d034f2221 (patch)
treee5937ae63f37d53a4a3d46de9af1f3fb24cf5c07
parent5c98110fca071f4c0c8bcc68b8d8e12b96a0fce2 (diff)
CMake: pro2cmake.py: Add basic support for examples
Examples need to be built stand-alone and as part of Qt, so they need a special CMakeLists.txt file that supports both use-cases. Add an --is-example switch to pro2cmake to make it generate these special CMakeLists.txt files. This is basic support only and is currently still missing the necessary find_package calls. Change-Id: Ie770287350fb8a41e872cb0ea607923caa33073d Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
-rwxr-xr-xutil/cmake/pro2cmake.py157
1 files changed, 118 insertions, 39 deletions
diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py
index 820a95d728..556bc59c2b 100755
--- a/util/cmake/pro2cmake.py
+++ b/util/cmake/pro2cmake.py
@@ -67,6 +67,11 @@ def _parse_commandline():
dest='debug_full_pro_structure', action='store_true',
help='Dump the full structure of the qmake .pro-file '
'(with includes).')
+
+ parser.add_argument('--example', action='store_true',
+ dest="is_example",
+ help='Treat the input .pro file as an example.')
+
parser.add_argument('files', metavar='<.pro/.pri file>', type=str,
nargs='+', help='The .pro/.pri file to process')
@@ -826,7 +831,7 @@ def map_condition(condition: str) -> str:
def handle_subdir(scope: Scope, cm_fh: typing.IO[str], *,
- indent: int = 0) -> None:
+ indent: int = 0, is_example: bool=False) -> None:
ind = ' ' * indent
for sd in scope.get_files('SUBDIRS'):
if os.path.isdir(sd):
@@ -839,7 +844,7 @@ def handle_subdir(scope: Scope, cm_fh: typing.IO[str], *,
'', scope.basedir)
do_include(subdir_scope)
- cmakeify_scope(subdir_scope, cm_fh, indent=indent)
+ cmakeify_scope(subdir_scope, cm_fh, indent=indent, is_example=is_example)
elif sd.startswith('-'):
cm_fh.write('{}### remove_subdirectory'
'("{}")\n'.format(ind, sd[1:]))
@@ -853,7 +858,7 @@ def handle_subdir(scope: Scope, cm_fh: typing.IO[str], *,
elif cond:
cm_fh.write('\n{}if({})\n'.format(ind, cond))
- handle_subdir(c, cm_fh, indent=indent + 1)
+ handle_subdir(c, cm_fh, indent=indent + 1, is_example=is_example)
if cond:
cm_fh.write('{}endif()\n'.format(ind))
@@ -914,10 +919,10 @@ def write_source_file_list(cm_fh: typing.IO[str], scope, cmake_parameter: str,
cm_fh.write(header)
extra_indent = ''
if cmake_parameter:
- cm_fh.write('{} {}\n'.format(ind, cmake_parameter))
+ cm_fh.write('{}{}\n'.format(ind, cmake_parameter))
extra_indent = ' '
for s in sort_sources(sources):
- cm_fh.write('{} {}{}\n'.format(ind, extra_indent, s))
+ cm_fh.write('{}{}{}\n'.format(ind, extra_indent, s))
cm_fh.write(footer)
@@ -951,6 +956,54 @@ def write_library_list(cm_fh: typing.IO[str], cmake_keyword: str,
cm_fh.write('{} {}\n'.format(ind, d))
+def write_all_source_file_lists(cm_fh: typing.IO[str], scope: Scope, header: str, *,
+ indent: int = 0, footer: str = ''):
+ write_source_file_list(cm_fh, scope, header,
+ ['SOURCES', 'HEADERS', 'OBJECTIVE_SOURCES', 'NO_PCH_SOURCES', 'FORMS'],
+ indent)
+
+
+def write_defines(cm_fh: typing.IO[str], scope: Scope, header: str, *,
+ indent: int = 0, footer: str = ''):
+ ind = spaces(indent)
+
+ defines = scope.expand('DEFINES')
+ defines += [d[2:] for d in scope.expand('QMAKE_CXXFLAGS') if d.startswith('-D')]
+ if defines:
+ cm_fh.write('{}{}\n'.format(ind, header))
+ for d in defines:
+ d = d.replace('=\\\\\\"$$PWD/\\\\\\"',
+ '="${CMAKE_CURRENT_SOURCE_DIR}/"')
+ cm_fh.write('{} {}\n'.format(ind, d))
+ if footer:
+ cm_fh.write('{}{}\n'.format(ind, footer))
+
+def write_include_paths(cm_fh: typing.IO[str], scope: Scope, header: str, *,
+ indent: int = 0, footer: str = ''):
+ ind = spaces(indent)
+
+ includes = scope.get_files('INCLUDEPATH')
+ if includes:
+ cm_fh.write('{}{}\n'.format(ind, header))
+ for i in includes:
+ i = i.rstrip('/') or ('/')
+ cm_fh.write('{} {}\n'.format(ind, i))
+ if footer:
+ cm_fh.write('{}{}\n'.format(ind, footer))
+
+
+def write_compile_options(cm_fh: typing.IO[str], scope: Scope, header: str, *,
+ indent: int = 0, footer: str = ''):
+ ind = spaces(indent)
+
+ compile_options = [d for d in scope.expand('QMAKE_CXXFLAGS') if not d.startswith('-D')]
+ if compile_options:
+ cm_fh.write('{}{}\n'.format(ind, header))
+ for co in compile_options:
+ cm_fh.write('{} "{}"\n'.format(ind, co))
+ if footer:
+ cm_fh.write('{}{}\n'.format(ind, footer))
+
def write_library_section(cm_fh: typing.IO[str], scope: Scope,
public: typing.List[str],
@@ -1001,37 +1054,23 @@ def write_sources_section(cm_fh: typing.IO[str], scope: Scope, *,
if plugin_type:
cm_fh.write('{} TYPE {}\n'.format(ind, plugin_type))
- source_keys: typing.List[str] = []
- write_source_file_list(cm_fh, scope, 'SOURCES',
- ['SOURCES', 'HEADERS', 'OBJECTIVE_SOURCES', 'NO_PCH_SOURCES', 'FORMS'],
- indent)
+ write_all_source_file_lists(cm_fh, scope, 'SOURCES', indent=indent + 1)
- write_source_file_list(cm_fh, scope, 'DBUS_ADAPTOR_SOURCES', ['DBUS_ADAPTORS',], indent)
+ write_source_file_list(cm_fh, scope, 'DBUS_ADAPTOR_SOURCES', ['DBUS_ADAPTORS',], indent + 1)
dbus_adaptor_flags = scope.expand('QDBUSXML2CPP_ADAPTOR_HEADER_FLAGS')
if dbus_adaptor_flags:
cm_fh.write('{} DBUS_ADAPTOR_FLAGS\n'.format(ind))
cm_fh.write('{} "{}"\n'.format(ind, '" "'.join(dbus_adaptor_flags)))
- write_source_file_list(cm_fh, scope, 'DBUS_INTERFACE_SOURCES', ['DBUS_INTERFACES',], indent)
+ write_source_file_list(cm_fh, scope, 'DBUS_INTERFACE_SOURCES', ['DBUS_INTERFACES',], indent + 1)
dbus_interface_flags = scope.expand('QDBUSXML2CPP_INTERFACE_HEADER_FLAGS')
if dbus_interface_flags:
cm_fh.write('{} DBUS_INTERFACE_FLAGS\n'.format(ind))
cm_fh.write('{} "{}"\n'.format(ind, '" "'.join(dbus_interface_flags)))
- defines = scope.expand('DEFINES')
- defines += [d[2:] for d in scope.expand('QMAKE_CXXFLAGS') if d.startswith('-D')]
- 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_files('INCLUDEPATH')
- if includes:
- cm_fh.write('{} INCLUDE_DIRECTORIES\n'.format(ind))
- for i in includes:
- i = i.rstrip('/') or ('/')
- cm_fh.write('{} {}\n'.format(ind, i))
+ write_defines(cm_fh, scope, 'DEFINES', indent=indent + 1)
+
+ write_include_paths(cm_fh, scope, 'INCLUDE_DIRECTORIES', indent=indent + 1)
write_library_section(cm_fh, scope,
['QMAKE_USE', 'LIBS'],
@@ -1040,11 +1079,7 @@ def write_sources_section(cm_fh: typing.IO[str], scope: Scope, *,
['QT',],
indent=indent, known_libraries=known_libraries)
- compile_options = [d for d in scope.expand('QMAKE_CXXFLAGS') if not d.startswith('-D')]
- if compile_options:
- cm_fh.write('{} COMPILE_OPTIONS\n'.format(ind))
- for co in compile_options:
- cm_fh.write('{} "{}"\n'.format(ind, co))
+ write_compile_options(cm_fh, scope, 'COMPILE_OPTIONS', indent=indent + 1)
link_options = scope.get('QMAKE_LFLAGS')
if link_options:
@@ -1482,6 +1517,43 @@ def write_binary(cm_fh: typing.IO[str], scope: Scope,
known_libraries={'Qt::Core', }, extra_keys=['target.path', 'INSTALLS'])
+def write_example(cm_fh: typing.IO[str], scope: Scope,
+ gui: bool = False, *, indent: int = 0) -> None:
+ binary_name = scope.TARGET
+ assert binary_name
+
+#find_package(Qt5 COMPONENTS Widgets REQUIRED)
+#target_link_libraries(mimetypebrowser Qt::Widgets)
+
+ cm_fh.write('cmake_minimum_required(VERSION 3.14)\n' +
+ 'project(mimetypebrowser LANGUAGES CXX)\n\n' +
+ 'set(CMAKE_INCLUDE_CURRENT_DIR ON)\n\n' +
+ 'set(CMAKE_AUTOMOC ON)\n' +
+ 'set(CMAKE_AUTORCC ON)\n' +
+ 'set(CMAKE_AUTOUIC ON)\n\n' +
+ 'set(INSTALL_EXAMPLEDIR "examples")\n\n')
+
+ add_executable = 'add_executable({}'.format(binary_name);
+ if gui:
+ add_executable += ' WIN32_EXECUTABLE MACOSX_BUNDLE'
+
+ write_all_source_file_lists(cm_fh, scope, add_executable, indent=0)
+
+ cm_fh.write(')\n')
+
+ write_include_paths(cm_fh, scope, 'target_include_directories({}'.format(binary_name),
+ indent=0, footer=')')
+ write_defines(cm_fh, scope, 'target_compile_definitions({}'.format(binary_name),
+ indent=0, footer=')')
+ write_compile_options(cm_fh, scope, 'target_compile_options({}'.format(binary_name),
+ indent=0, footer=')')
+
+ cm_fh.write('\ninstall(TARGETS mimetypebrowser\n' +
+ ' RUNTIME_DESTINATION "${INSTALL_EXAMPLEDIR}"\n' +
+ ' BUNDLE_DESTINATION "${INSTALL_EXAMPLESDIR}"\n' +
+ ')\n')
+
+
def write_plugin(cm_fh, scope, *, indent: int = 0):
plugin_name = scope.TARGET
assert plugin_name
@@ -1491,52 +1563,59 @@ def write_plugin(cm_fh, scope, *, indent: int = 0):
def handle_app_or_lib(scope: Scope, cm_fh: typing.IO[str], *,
- indent: int = 0) -> None:
+ indent: int = 0, is_example: bool=False) -> None:
assert scope.TEMPLATE in ('app', 'lib')
is_lib = scope.TEMPLATE == 'lib'
is_plugin = any('qt_plugin' == s for s in scope.get('_LOADED'))
if is_lib or 'qt_module' in scope.get('_LOADED'):
+ assert not is_example
write_module(cm_fh, scope, indent=indent)
elif is_plugin:
+ assert not is_example
write_plugin(cm_fh, scope, indent=indent)
elif 'qt_tool' in scope.get('_LOADED'):
+ assert not is_example
write_tool(cm_fh, scope, indent=indent)
else:
if 'testcase' in scope.get('CONFIG') \
or 'testlib' in scope.get('CONFIG'):
+ assert not is_example
write_test(cm_fh, scope, indent=indent)
else:
gui = 'console' not in scope.get('CONFIG')
- write_binary(cm_fh, scope, gui, indent=indent)
+ if is_example:
+ write_example(cm_fh, scope, gui, indent=indent)
+ else:
+ write_binary(cm_fh, scope, gui, indent=indent)
ind = spaces(indent)
write_source_file_list(cm_fh, scope, '',
['QMAKE_DOCS',],
- indent,
+ indent + 1,
header = '{}add_qt_docs(\n'.format(ind),
footer = '{})\n'.format(ind))
def cmakeify_scope(scope: Scope, cm_fh: typing.IO[str], *,
- indent: int = 0) -> None:
+ indent: int = 0, is_example: bool=False) -> None:
template = scope.TEMPLATE
if template == 'subdirs':
- handle_subdir(scope, cm_fh, indent=indent)
+ handle_subdir(scope, cm_fh, indent=indent, is_example=is_example)
elif template in ('app', 'lib'):
- handle_app_or_lib(scope, cm_fh, indent=indent)
+ handle_app_or_lib(scope, cm_fh, indent=indent, is_example=is_example)
else:
print(' XXXX: {}: Template type {} not yet supported.'
.format(scope.file, template))
-def generate_cmakelists(scope: Scope) -> None:
+def generate_cmakelists(scope: Scope, *, is_example: bool=False) -> None:
with open(scope.cMakeListsFile, 'w') as cm_fh:
assert scope.file
cm_fh.write('# Generated from {}.\n\n'
.format(os.path.basename(scope.file)))
- cmakeify_scope(scope, cm_fh)
+ cmakeify_scope(scope, cm_fh, is_example=is_example)
def do_include(scope: Scope, *, debug: bool = False) -> None:
@@ -1600,7 +1679,7 @@ def main() -> None:
print(file_scope.dump())
print('\n#### End of full .pro/.pri file structure.\n')
- generate_cmakelists(file_scope)
+ generate_cmakelists(file_scope, is_example=args.is_example)
os.chdir(backup_current_dir)