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 <alexandru.croitor@qt.io>
This commit is contained in:
parent
928828b549
commit
bac56fd4d0
@ -82,7 +82,6 @@ from helper import (
|
|||||||
LibraryMapping,
|
LibraryMapping,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
cmake_version_string = "3.16"
|
cmake_version_string = "3.16"
|
||||||
cmake_api_version = 3
|
cmake_api_version = 3
|
||||||
|
|
||||||
@ -136,7 +135,13 @@ def _parse_commandline():
|
|||||||
"--is-example",
|
"--is-example",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
dest="is_example",
|
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(
|
parser.add_argument(
|
||||||
"-s",
|
"-s",
|
||||||
@ -1826,7 +1831,12 @@ def replace_path_constants(path: str, scope: Scope) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def handle_subdir(
|
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:
|
) -> None:
|
||||||
|
|
||||||
# Global nested dictionary that will contain sub_dir assignments and their conditions.
|
# Global nested dictionary that will contain sub_dir assignments and their conditions.
|
||||||
@ -1891,7 +1901,13 @@ def handle_subdir(
|
|||||||
)
|
)
|
||||||
|
|
||||||
do_include(subdir_scope)
|
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:
|
else:
|
||||||
print(f" XXXX: SUBDIR {sd} in {scope}: Not found.")
|
print(f" XXXX: SUBDIR {sd} in {scope}: Not found.")
|
||||||
|
|
||||||
@ -3890,19 +3906,26 @@ def find_qml_resource(resources: List[QtResource]):
|
|||||||
|
|
||||||
|
|
||||||
def write_example(
|
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:
|
) -> str:
|
||||||
binary_name = scope.TARGET
|
binary_name = scope.TARGET
|
||||||
assert binary_name
|
assert binary_name
|
||||||
config = scope.get("CONFIG")
|
config = scope.get("CONFIG")
|
||||||
is_qml_plugin = ("qml" in scope.get("QT")) or "qmltypes" in config
|
is_qml_plugin = ("qml" in scope.get("QT")) or "qmltypes" in config
|
||||||
|
|
||||||
example_install_dir = scope.expandString("target.path")
|
if not is_user_project:
|
||||||
if not example_install_dir:
|
example_install_dir = scope.expandString("target.path")
|
||||||
example_install_dir = "${INSTALL_EXAMPLESDIR}"
|
if not example_install_dir:
|
||||||
example_install_dir = example_install_dir.replace(
|
example_install_dir = "${INSTALL_EXAMPLESDIR}"
|
||||||
"$$[QT_INSTALL_EXAMPLES]", "${INSTALL_EXAMPLESDIR}"
|
example_install_dir = example_install_dir.replace(
|
||||||
)
|
"$$[QT_INSTALL_EXAMPLES]", "${INSTALL_EXAMPLESDIR}"
|
||||||
|
)
|
||||||
|
|
||||||
project_version = scope.get_string("VERSION", "1.0")
|
project_version = scope.get_string("VERSION", "1.0")
|
||||||
cm_fh.write(
|
cm_fh.write(
|
||||||
@ -3914,12 +3937,13 @@ def write_example(
|
|||||||
if scope.get_files("FORMS"):
|
if scope.get_files("FORMS"):
|
||||||
cm_fh.write("set(CMAKE_AUTOUIC ON)\n")
|
cm_fh.write("set(CMAKE_AUTOUIC ON)\n")
|
||||||
cm_fh.write("\n")
|
cm_fh.write("\n")
|
||||||
cm_fh.write(
|
if not is_user_project:
|
||||||
"if(NOT DEFINED INSTALL_EXAMPLESDIR)\n"
|
cm_fh.write(
|
||||||
' set(INSTALL_EXAMPLESDIR "examples")\n'
|
"if(NOT DEFINED INSTALL_EXAMPLESDIR)\n"
|
||||||
"endif()\n\n"
|
' set(INSTALL_EXAMPLESDIR "examples")\n'
|
||||||
f'set(INSTALL_EXAMPLEDIR "{example_install_dir}")\n\n'
|
"endif()\n\n"
|
||||||
)
|
f'set(INSTALL_EXAMPLEDIR "{example_install_dir}")\n\n'
|
||||||
|
)
|
||||||
|
|
||||||
recursive_evaluate_scope(scope)
|
recursive_evaluate_scope(scope)
|
||||||
|
|
||||||
@ -4108,13 +4132,14 @@ def write_example(
|
|||||||
|
|
||||||
handling_first_scope = False
|
handling_first_scope = False
|
||||||
|
|
||||||
cm_fh.write(
|
if not is_user_project:
|
||||||
f"\ninstall(TARGETS {binary_name}\n"
|
cm_fh.write(
|
||||||
f' RUNTIME DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n'
|
f"\ninstall(TARGETS {binary_name}\n"
|
||||||
f' BUNDLE DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n'
|
f' RUNTIME DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n'
|
||||||
f' LIBRARY DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n'
|
f' BUNDLE DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n'
|
||||||
f")\n"
|
f' LIBRARY DESTINATION "${{INSTALL_EXAMPLEDIR}}"\n'
|
||||||
)
|
f")\n"
|
||||||
|
)
|
||||||
|
|
||||||
return binary_name
|
return binary_name
|
||||||
|
|
||||||
@ -4505,7 +4530,12 @@ def write_qml_plugin_epilogue(
|
|||||||
|
|
||||||
|
|
||||||
def handle_app_or_lib(
|
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:
|
) -> None:
|
||||||
assert scope.TEMPLATE in ("app", "lib")
|
assert scope.TEMPLATE in ("app", "lib")
|
||||||
|
|
||||||
@ -4527,7 +4557,9 @@ def handle_app_or_lib(
|
|||||||
assert not is_example
|
assert not is_example
|
||||||
target = write_3rdparty_library(cm_fh, scope, indent=indent)
|
target = write_3rdparty_library(cm_fh, scope, indent=indent)
|
||||||
elif is_example:
|
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:
|
elif is_qt_plugin:
|
||||||
assert not is_example
|
assert not is_example
|
||||||
target = write_plugin(cm_fh, scope, indent=indent)
|
target = write_plugin(cm_fh, scope, indent=indent)
|
||||||
@ -4806,40 +4838,53 @@ endif()
|
|||||||
|
|
||||||
|
|
||||||
def cmakeify_scope(
|
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:
|
) -> None:
|
||||||
template = scope.TEMPLATE
|
template = scope.TEMPLATE
|
||||||
|
|
||||||
temp_buffer = io.StringIO()
|
if is_user_project:
|
||||||
|
if template == "subdirs":
|
||||||
# Handle top level repo project in a special way.
|
handle_subdir(scope, cm_fh, indent=indent, is_example=True, is_user_project=True)
|
||||||
if is_top_level_repo_project(scope.file_absolute_path):
|
elif template in ("app", "lib"):
|
||||||
create_top_level_cmake_conf()
|
handle_app_or_lib(scope, cm_fh, indent=indent, is_example=True, is_user_project=True)
|
||||||
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:
|
else:
|
||||||
print(f" XXXX: {scope.file}: Template type {template} not yet supported.")
|
temp_buffer = io.StringIO()
|
||||||
|
|
||||||
buffer_value = temp_buffer.getvalue()
|
# 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.")
|
||||||
|
|
||||||
if is_top_level_repo_examples_project(scope.file_absolute_path):
|
buffer_value = temp_buffer.getvalue()
|
||||||
# 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)
|
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)
|
||||||
|
|
||||||
|
|
||||||
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:
|
if debug:
|
||||||
print("Generating CMakeLists.gen.txt")
|
print("Generating CMakeLists.gen.txt")
|
||||||
with open(scope.generated_cmake_lists_path, "w") as cm_fh:
|
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)
|
is_example_heuristic = is_example_project(scope.file_absolute_path)
|
||||||
final_is_example_decision = is_example or is_example_heuristic
|
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:
|
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}"')
|
print(f'Skipping conversion of project: "{project_file_absolute_path}"')
|
||||||
continue
|
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
|
copy_generated_file = True
|
||||||
|
|
||||||
|
4
util/cmake/qmake2cmake
Executable file
4
util/cmake/qmake2cmake
Executable file
@ -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 $@
|
2
util/cmake/qmake2cmake.bat
Normal file
2
util/cmake/qmake2cmake.bat
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@echo off
|
||||||
|
python %~dp0\pro2cmake.py --is-user-project %*
|
Loading…
x
Reference in New Issue
Block a user