From bac56fd4d0d9a19790cf897aab3f979e0134eabd Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 4 Mar 2022 15:49:02 +0100 Subject: pro2cmake: Introduce qmake2cmake convenience scripts Add qmake2cmake[.bat] wrapper scripts that can be used to convert user projects to CMake. For now, user projects are internally handled as Qt examples with one difference: the generation of example-specific installation code is suppressed. Fixes: QTBUG-98655 Change-Id: I1a57f6d12efe0bdf383592ab33682a611692db80 Reviewed-by: Alexandru Croitor --- util/cmake/pro2cmake.py | 158 ++++++++++++++++++++++++++++++--------------- util/cmake/qmake2cmake | 4 ++ util/cmake/qmake2cmake.bat | 2 + 3 files changed, 111 insertions(+), 53 deletions(-) create mode 100755 util/cmake/qmake2cmake create mode 100644 util/cmake/qmake2cmake.bat (limited to 'util') diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py index c30591591b..2fcefdb51d 100755 --- a/util/cmake/pro2cmake.py +++ b/util/cmake/pro2cmake.py @@ -82,7 +82,6 @@ from helper import ( LibraryMapping, ) - cmake_version_string = "3.16" cmake_api_version = 3 @@ -136,7 +135,13 @@ def _parse_commandline(): "--is-example", action="store_true", dest="is_example", - help="Treat the input .pro file as an example.", + help="Treat the input .pro file as a Qt example.", + ) + parser.add_argument( + "--is-user-project", + action="store_true", + dest="is_user_project", + help="Treat the input .pro file as a user project.", ) parser.add_argument( "-s", @@ -1826,7 +1831,12 @@ def replace_path_constants(path: str, scope: Scope) -> str: def handle_subdir( - scope: Scope, cm_fh: IO[str], *, indent: int = 0, is_example: bool = False + scope: Scope, + cm_fh: IO[str], + *, + indent: int = 0, + is_example: bool = False, + is_user_project: bool = False, ) -> None: # Global nested dictionary that will contain sub_dir assignments and their conditions. @@ -1891,7 +1901,13 @@ def handle_subdir( ) do_include(subdir_scope) - cmakeify_scope(subdir_scope, cm_fh, indent=indent, is_example=is_example) + cmakeify_scope( + subdir_scope, + cm_fh, + indent=indent, + is_example=is_example, + is_user_project=is_user_project, + ) else: print(f" XXXX: SUBDIR {sd} in {scope}: Not found.") @@ -3890,19 +3906,26 @@ def find_qml_resource(resources: List[QtResource]): def write_example( - cm_fh: IO[str], scope: Scope, gui: bool = False, *, indent: int = 0, is_plugin: bool = False + cm_fh: IO[str], + scope: Scope, + gui: bool = False, + *, + indent: int = 0, + is_plugin: bool = False, + is_user_project: bool = False, ) -> str: binary_name = scope.TARGET assert binary_name config = scope.get("CONFIG") is_qml_plugin = ("qml" in scope.get("QT")) or "qmltypes" in config - example_install_dir = scope.expandString("target.path") - if not example_install_dir: - example_install_dir = "${INSTALL_EXAMPLESDIR}" - example_install_dir = example_install_dir.replace( - "$$[QT_INSTALL_EXAMPLES]", "${INSTALL_EXAMPLESDIR}" - ) + if not is_user_project: + example_install_dir = scope.expandString("target.path") + if not example_install_dir: + example_install_dir = "${INSTALL_EXAMPLESDIR}" + example_install_dir = example_install_dir.replace( + "$$[QT_INSTALL_EXAMPLES]", "${INSTALL_EXAMPLESDIR}" + ) project_version = scope.get_string("VERSION", "1.0") cm_fh.write( @@ -3914,12 +3937,13 @@ def write_example( if scope.get_files("FORMS"): cm_fh.write("set(CMAKE_AUTOUIC ON)\n") cm_fh.write("\n") - cm_fh.write( - "if(NOT DEFINED INSTALL_EXAMPLESDIR)\n" - ' set(INSTALL_EXAMPLESDIR "examples")\n' - "endif()\n\n" - f'set(INSTALL_EXAMPLEDIR "{example_install_dir}")\n\n' - ) + if not is_user_project: + cm_fh.write( + "if(NOT DEFINED INSTALL_EXAMPLESDIR)\n" + ' set(INSTALL_EXAMPLESDIR "examples")\n' + "endif()\n\n" + f'set(INSTALL_EXAMPLEDIR "{example_install_dir}")\n\n' + ) recursive_evaluate_scope(scope) @@ -4108,13 +4132,14 @@ def write_example( handling_first_scope = False - cm_fh.write( - f"\ninstall(TARGETS {binary_name}\n" - f' RUNTIME DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n' - f' BUNDLE DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n' - f' LIBRARY DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n' - f")\n" - ) + if not is_user_project: + cm_fh.write( + f"\ninstall(TARGETS {binary_name}\n" + f' RUNTIME DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n' + f' BUNDLE DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n' + f' LIBRARY DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n' + f")\n" + ) return binary_name @@ -4505,7 +4530,12 @@ def write_qml_plugin_epilogue( def handle_app_or_lib( - scope: Scope, cm_fh: IO[str], *, indent: int = 0, is_example: bool = False + scope: Scope, + cm_fh: IO[str], + *, + indent: int = 0, + is_example: bool = False, + is_user_project=False, ) -> None: assert scope.TEMPLATE in ("app", "lib") @@ -4527,7 +4557,9 @@ def handle_app_or_lib( assert not is_example target = write_3rdparty_library(cm_fh, scope, indent=indent) elif is_example: - target = write_example(cm_fh, scope, gui, indent=indent, is_plugin=is_plugin) + target = write_example( + cm_fh, scope, gui, indent=indent, is_plugin=is_plugin, is_user_project=is_user_project + ) elif is_qt_plugin: assert not is_example target = write_plugin(cm_fh, scope, indent=indent) @@ -4806,40 +4838,53 @@ endif() def cmakeify_scope( - scope: Scope, cm_fh: IO[str], *, indent: int = 0, is_example: bool = False + scope: Scope, + cm_fh: IO[str], + *, + indent: int = 0, + is_example: bool = False, + is_user_project: bool = False, ) -> None: template = scope.TEMPLATE - temp_buffer = io.StringIO() - - # Handle top level repo project in a special way. - if is_top_level_repo_project(scope.file_absolute_path): - create_top_level_cmake_conf() - handle_top_level_repo_project(scope, temp_buffer) - # Same for top-level tests. - elif is_top_level_repo_tests_project(scope.file_absolute_path): - handle_top_level_repo_tests_project(scope, temp_buffer) - elif is_config_test_project(scope.file_absolute_path): - handle_config_test_project(scope, temp_buffer) - elif template == "subdirs": - handle_subdir(scope, temp_buffer, indent=indent, is_example=is_example) - elif template in ("app", "lib"): - handle_app_or_lib(scope, temp_buffer, indent=indent, is_example=is_example) + if is_user_project: + if template == "subdirs": + handle_subdir(scope, cm_fh, indent=indent, is_example=True, is_user_project=True) + elif template in ("app", "lib"): + handle_app_or_lib(scope, cm_fh, indent=indent, is_example=True, is_user_project=True) else: - print(f" XXXX: {scope.file}: Template type {template} not yet supported.") + temp_buffer = io.StringIO() + + # Handle top level repo project in a special way. + if is_top_level_repo_project(scope.file_absolute_path): + create_top_level_cmake_conf() + handle_top_level_repo_project(scope, temp_buffer) + # Same for top-level tests. + elif is_top_level_repo_tests_project(scope.file_absolute_path): + handle_top_level_repo_tests_project(scope, temp_buffer) + elif is_config_test_project(scope.file_absolute_path): + handle_config_test_project(scope, temp_buffer) + elif template == "subdirs": + handle_subdir(scope, temp_buffer, indent=indent, is_example=is_example) + elif template in ("app", "lib"): + handle_app_or_lib(scope, temp_buffer, indent=indent, is_example=is_example) + else: + print(f" XXXX: {scope.file}: Template type {template} not yet supported.") - buffer_value = temp_buffer.getvalue() + buffer_value = temp_buffer.getvalue() - if is_top_level_repo_examples_project(scope.file_absolute_path): - # Wrap top level examples project with some commands which - # are necessary to build examples as part of the overall - # build. - buffer_value = f"qt_examples_build_begin()\n\n{buffer_value}\nqt_examples_build_end()\n" + if is_top_level_repo_examples_project(scope.file_absolute_path): + # Wrap top level examples project with some commands which + # are necessary to build examples as part of the overall + # build. + buffer_value = f"qt_examples_build_begin()\n\n{buffer_value}\nqt_examples_build_end()\n" - cm_fh.write(buffer_value) + cm_fh.write(buffer_value) -def generate_new_cmakelists(scope: Scope, *, is_example: bool = False, debug: bool = False) -> None: +def generate_new_cmakelists( + scope: Scope, *, is_example: bool = False, is_user_project: bool = True, debug: bool = False +) -> None: if debug: print("Generating CMakeLists.gen.txt") with open(scope.generated_cmake_lists_path, "w") as cm_fh: @@ -4848,7 +4893,9 @@ def generate_new_cmakelists(scope: Scope, *, is_example: bool = False, debug: bo is_example_heuristic = is_example_project(scope.file_absolute_path) final_is_example_decision = is_example or is_example_heuristic - cmakeify_scope(scope, cm_fh, is_example=final_is_example_decision) + cmakeify_scope( + scope, cm_fh, is_example=final_is_example_decision, is_user_project=is_user_project + ) def do_include(scope: Scope, *, debug: bool = False) -> None: @@ -5044,7 +5091,12 @@ def main() -> None: print(f'Skipping conversion of project: "{project_file_absolute_path}"') continue - generate_new_cmakelists(file_scope, is_example=args.is_example, debug=args.debug) + generate_new_cmakelists( + file_scope, + is_example=args.is_example, + is_user_project=args.is_user_project, + debug=args.debug, + ) copy_generated_file = True diff --git a/util/cmake/qmake2cmake b/util/cmake/qmake2cmake new file mode 100755 index 0000000000..58841e42ec --- /dev/null +++ b/util/cmake/qmake2cmake @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +script_dir_path=`dirname $0` +script_dir_path=`(cd "$script_dir_path"; /bin/pwd)` +python3 $script_dir_path/pro2cmake.py --is-user-project $@ diff --git a/util/cmake/qmake2cmake.bat b/util/cmake/qmake2cmake.bat new file mode 100644 index 0000000000..30edc45800 --- /dev/null +++ b/util/cmake/qmake2cmake.bat @@ -0,0 +1,2 @@ +@echo off +python %~dp0\pro2cmake.py --is-user-project %* -- cgit v1.2.3