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>
This commit is contained in:
parent
5c98110fca
commit
5608bf3cba
@ -67,6 +67,11 @@ def _parse_commandline():
|
|||||||
dest='debug_full_pro_structure', action='store_true',
|
dest='debug_full_pro_structure', action='store_true',
|
||||||
help='Dump the full structure of the qmake .pro-file '
|
help='Dump the full structure of the qmake .pro-file '
|
||||||
'(with includes).')
|
'(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,
|
parser.add_argument('files', metavar='<.pro/.pri file>', type=str,
|
||||||
nargs='+', help='The .pro/.pri file to process')
|
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], *,
|
def handle_subdir(scope: Scope, cm_fh: typing.IO[str], *,
|
||||||
indent: int = 0) -> None:
|
indent: int = 0, is_example: bool=False) -> None:
|
||||||
ind = ' ' * indent
|
ind = ' ' * indent
|
||||||
for sd in scope.get_files('SUBDIRS'):
|
for sd in scope.get_files('SUBDIRS'):
|
||||||
if os.path.isdir(sd):
|
if os.path.isdir(sd):
|
||||||
@ -839,7 +844,7 @@ def handle_subdir(scope: Scope, cm_fh: typing.IO[str], *,
|
|||||||
'', scope.basedir)
|
'', scope.basedir)
|
||||||
|
|
||||||
do_include(subdir_scope)
|
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('-'):
|
elif sd.startswith('-'):
|
||||||
cm_fh.write('{}### remove_subdirectory'
|
cm_fh.write('{}### remove_subdirectory'
|
||||||
'("{}")\n'.format(ind, sd[1:]))
|
'("{}")\n'.format(ind, sd[1:]))
|
||||||
@ -853,7 +858,7 @@ def handle_subdir(scope: Scope, cm_fh: typing.IO[str], *,
|
|||||||
elif cond:
|
elif cond:
|
||||||
cm_fh.write('\n{}if({})\n'.format(ind, 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:
|
if cond:
|
||||||
cm_fh.write('{}endif()\n'.format(ind))
|
cm_fh.write('{}endif()\n'.format(ind))
|
||||||
@ -951,6 +956,54 @@ def write_library_list(cm_fh: typing.IO[str], cmake_keyword: str,
|
|||||||
cm_fh.write('{} {}\n'.format(ind, d))
|
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,
|
def write_library_section(cm_fh: typing.IO[str], scope: Scope,
|
||||||
public: typing.List[str],
|
public: typing.List[str],
|
||||||
@ -1001,37 +1054,23 @@ def write_sources_section(cm_fh: typing.IO[str], scope: Scope, *,
|
|||||||
if plugin_type:
|
if plugin_type:
|
||||||
cm_fh.write('{} TYPE {}\n'.format(ind, plugin_type))
|
cm_fh.write('{} TYPE {}\n'.format(ind, plugin_type))
|
||||||
|
|
||||||
source_keys: typing.List[str] = []
|
write_all_source_file_lists(cm_fh, scope, 'SOURCES', indent=indent + 1)
|
||||||
write_source_file_list(cm_fh, scope, 'SOURCES',
|
|
||||||
['SOURCES', 'HEADERS', 'OBJECTIVE_SOURCES', 'NO_PCH_SOURCES', 'FORMS'],
|
|
||||||
indent)
|
|
||||||
|
|
||||||
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')
|
dbus_adaptor_flags = scope.expand('QDBUSXML2CPP_ADAPTOR_HEADER_FLAGS')
|
||||||
if dbus_adaptor_flags:
|
if dbus_adaptor_flags:
|
||||||
cm_fh.write('{} DBUS_ADAPTOR_FLAGS\n'.format(ind))
|
cm_fh.write('{} DBUS_ADAPTOR_FLAGS\n'.format(ind))
|
||||||
cm_fh.write('{} "{}"\n'.format(ind, '" "'.join(dbus_adaptor_flags)))
|
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')
|
dbus_interface_flags = scope.expand('QDBUSXML2CPP_INTERFACE_HEADER_FLAGS')
|
||||||
if dbus_interface_flags:
|
if dbus_interface_flags:
|
||||||
cm_fh.write('{} DBUS_INTERFACE_FLAGS\n'.format(ind))
|
cm_fh.write('{} DBUS_INTERFACE_FLAGS\n'.format(ind))
|
||||||
cm_fh.write('{} "{}"\n'.format(ind, '" "'.join(dbus_interface_flags)))
|
cm_fh.write('{} "{}"\n'.format(ind, '" "'.join(dbus_interface_flags)))
|
||||||
|
|
||||||
defines = scope.expand('DEFINES')
|
write_defines(cm_fh, scope, 'DEFINES', indent=indent + 1)
|
||||||
defines += [d[2:] for d in scope.expand('QMAKE_CXXFLAGS') if d.startswith('-D')]
|
|
||||||
if defines:
|
write_include_paths(cm_fh, scope, 'INCLUDE_DIRECTORIES', indent=indent + 1)
|
||||||
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_library_section(cm_fh, scope,
|
write_library_section(cm_fh, scope,
|
||||||
['QMAKE_USE', 'LIBS'],
|
['QMAKE_USE', 'LIBS'],
|
||||||
@ -1040,11 +1079,7 @@ def write_sources_section(cm_fh: typing.IO[str], scope: Scope, *,
|
|||||||
['QT',],
|
['QT',],
|
||||||
indent=indent, known_libraries=known_libraries)
|
indent=indent, known_libraries=known_libraries)
|
||||||
|
|
||||||
compile_options = [d for d in scope.expand('QMAKE_CXXFLAGS') if not d.startswith('-D')]
|
write_compile_options(cm_fh, scope, 'COMPILE_OPTIONS', indent=indent + 1)
|
||||||
if compile_options:
|
|
||||||
cm_fh.write('{} COMPILE_OPTIONS\n'.format(ind))
|
|
||||||
for co in compile_options:
|
|
||||||
cm_fh.write('{} "{}"\n'.format(ind, co))
|
|
||||||
|
|
||||||
link_options = scope.get('QMAKE_LFLAGS')
|
link_options = scope.get('QMAKE_LFLAGS')
|
||||||
if link_options:
|
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'])
|
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):
|
def write_plugin(cm_fh, scope, *, indent: int = 0):
|
||||||
plugin_name = scope.TARGET
|
plugin_name = scope.TARGET
|
||||||
assert plugin_name
|
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], *,
|
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')
|
assert scope.TEMPLATE in ('app', 'lib')
|
||||||
|
|
||||||
is_lib = scope.TEMPLATE == 'lib'
|
is_lib = scope.TEMPLATE == 'lib'
|
||||||
is_plugin = any('qt_plugin' == s for s in scope.get('_LOADED'))
|
is_plugin = any('qt_plugin' == s for s in scope.get('_LOADED'))
|
||||||
|
|
||||||
if is_lib or 'qt_module' 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)
|
write_module(cm_fh, scope, indent=indent)
|
||||||
elif is_plugin:
|
elif is_plugin:
|
||||||
|
assert not is_example
|
||||||
write_plugin(cm_fh, scope, indent=indent)
|
write_plugin(cm_fh, scope, indent=indent)
|
||||||
elif 'qt_tool' in scope.get('_LOADED'):
|
elif 'qt_tool' in scope.get('_LOADED'):
|
||||||
|
assert not is_example
|
||||||
write_tool(cm_fh, scope, indent=indent)
|
write_tool(cm_fh, scope, indent=indent)
|
||||||
else:
|
else:
|
||||||
if 'testcase' in scope.get('CONFIG') \
|
if 'testcase' in scope.get('CONFIG') \
|
||||||
or 'testlib' in scope.get('CONFIG'):
|
or 'testlib' in scope.get('CONFIG'):
|
||||||
|
assert not is_example
|
||||||
write_test(cm_fh, scope, indent=indent)
|
write_test(cm_fh, scope, indent=indent)
|
||||||
else:
|
else:
|
||||||
gui = 'console' not in scope.get('CONFIG')
|
gui = 'console' not in scope.get('CONFIG')
|
||||||
|
if is_example:
|
||||||
|
write_example(cm_fh, scope, gui, indent=indent)
|
||||||
|
else:
|
||||||
write_binary(cm_fh, scope, gui, indent=indent)
|
write_binary(cm_fh, scope, gui, indent=indent)
|
||||||
|
|
||||||
ind = spaces(indent)
|
ind = spaces(indent)
|
||||||
write_source_file_list(cm_fh, scope, '',
|
write_source_file_list(cm_fh, scope, '',
|
||||||
['QMAKE_DOCS',],
|
['QMAKE_DOCS',],
|
||||||
indent,
|
indent + 1,
|
||||||
header = '{}add_qt_docs(\n'.format(ind),
|
header = '{}add_qt_docs(\n'.format(ind),
|
||||||
footer = '{})\n'.format(ind))
|
footer = '{})\n'.format(ind))
|
||||||
|
|
||||||
|
|
||||||
def cmakeify_scope(scope: Scope, cm_fh: typing.IO[str], *,
|
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
|
template = scope.TEMPLATE
|
||||||
if template == 'subdirs':
|
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'):
|
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:
|
else:
|
||||||
print(' XXXX: {}: Template type {} not yet supported.'
|
print(' XXXX: {}: Template type {} not yet supported.'
|
||||||
.format(scope.file, template))
|
.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:
|
with open(scope.cMakeListsFile, 'w') as cm_fh:
|
||||||
assert scope.file
|
assert scope.file
|
||||||
cm_fh.write('# Generated from {}.\n\n'
|
cm_fh.write('# Generated from {}.\n\n'
|
||||||
.format(os.path.basename(scope.file)))
|
.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:
|
def do_include(scope: Scope, *, debug: bool = False) -> None:
|
||||||
@ -1600,7 +1679,7 @@ def main() -> None:
|
|||||||
print(file_scope.dump())
|
print(file_scope.dump())
|
||||||
print('\n#### End of full .pro/.pri file structure.\n')
|
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)
|
os.chdir(backup_current_dir)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user