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',
|
||||
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)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user