pro2cmake: Handle generation of config.tests

Handle conversion of config.tests that are used as out-of-line tests
in configure.json.

The script should able to handle conversion of simple config tests
including nested scopes.
One thing that will probably be needed in the future is handling of
pkconfig which is used in qtwebengine config.tests.

There is also a hardcoded list of config tests which should not be
automatically converted by pro2cmake, either because they were hand
written, or because it doesn't make sense to convert them for now.

Incidentally, we should fix example conversion to also handle nested
scopes, similarly to how it's done for config.tests.

Change-Id: I862e67c4d19d5ed8cb7fc7c9f9aaf6e3d503aa03
Reviewed-by: Qt CMake Build Bot
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
bb10
Alexandru Croitor 2019-09-21 18:02:54 +02:00
parent f35cc5090a
commit d71609610a
1 changed files with 122 additions and 1 deletions

View File

@ -50,6 +50,7 @@ import xml.etree.ElementTree as ET
from argparse import ArgumentParser
from textwrap import dedent
from itertools import chain
from functools import lru_cache
from shutil import copyfile
from sympy.logic import simplify_logic, And, Or, Not
from sympy.core.sympify import SympifyError
@ -194,6 +195,20 @@ def is_example_project(project_file_path: str = "") -> bool:
return project_relative_path.startswith("examples") and "3rdparty" not in project_relative_path
def is_config_test_project(project_file_path: str = "") -> bool:
qmake_conf_path = find_qmake_conf(project_file_path)
qmake_conf_dir_path = os.path.dirname(qmake_conf_path)
dir_name_with_qmake_confg = os.path.basename(qmake_conf_dir_path)
project_relative_path = os.path.relpath(project_file_path, qmake_conf_dir_path)
# If the project file is found in a subdir called 'config.tests'
# relative to the repo source dir, then it's probably a config test.
# Also if the .qmake.conf is found within config.tests dir (like in qtbase)
# then the project is probably a config .test
return project_relative_path.startswith("config.tests") or dir_name_with_qmake_confg == "config.tests"
@lru_cache(maxsize=None)
def find_qmake_conf(project_file_path: str = "") -> Optional[str]:
if not os.path.isabs(project_file_path):
print(
@ -1073,7 +1088,7 @@ class Scope(object):
return list(self._evalOps(key, transformer, []))
@staticmethod
def _replace_env_var_value(value: Any) -> str:
def _replace_env_var_value(value: Any) -> Any:
if not isinstance(value, str):
return value
@ -3098,6 +3113,95 @@ def handle_top_level_repo_tests_project(scope: Scope, cm_fh: IO[str]):
cm_fh.write(f"{content}")
def write_regular_cmake_target_scope_section(scope: Scope,
cm_fh: IO[str],
indent: int = 0,
skip_sources: bool = False):
if not skip_sources:
target_sources = "target_sources(${PROJECT_NAME} PUBLIC"
write_all_source_file_lists(cm_fh, scope, target_sources, indent=indent, footer=")")
write_include_paths(
cm_fh, scope, f"target_include_directories(${{PROJECT_NAME}} PUBLIC", indent=indent, footer=")"
)
write_defines(
cm_fh, scope, f"target_compile_definitions(${{PROJECT_NAME}} PUBLIC", indent=indent, footer=")"
)
(public_libs, private_libs) = extract_cmake_libraries(scope)
write_list(
cm_fh,
private_libs,
"",
indent=indent,
header=f"target_link_libraries(${{PROJECT_NAME}} PRIVATE\n",
footer=")",
)
write_list(
cm_fh,
public_libs,
"",
indent=indent,
header=f"target_link_libraries(${{PROJECT_NAME}} PUBLIC\n",
footer=")",
)
write_compile_options(
cm_fh, scope, f"target_compile_options(${{PROJECT_NAME}}", indent=indent, footer=")"
)
def handle_config_test_project(scope: Scope, cm_fh: IO[str]):
project_name = os.path.splitext(os.path.basename(scope.file_absolute_path))[0]
content = (
f"cmake_minimum_required(VERSION 3.14.0)\n"
f"project(config_test_{project_name} LANGUAGES CXX)\n"
)
cm_fh.write(f"{content}\n")
# Remove default QT libs.
scope._append_operation("QT", RemoveOperation(["core", "gui"]))
config = scope.get("CONFIG")
gui = all(val not in config for val in ["console", "cmdline"])
add_target = f'add_executable(${{PROJECT_NAME}}'
if gui:
add_target += " WIN32 MACOSX_BUNDLE"
temp_buffer = io.StringIO()
write_all_source_file_lists(temp_buffer, scope, add_target, indent=0)
buffer_value = temp_buffer.getvalue()
if buffer_value:
cm_fh.write(buffer_value)
else:
cm_fh.write(add_target)
cm_fh.write(")\n")
indent = 0
write_regular_cmake_target_scope_section(scope, cm_fh, indent, skip_sources=True)
recursive_evaluate_scope(scope)
scopes = flatten_scopes(scope)
scopes = merge_scopes(scopes)
assert len(scopes)
assert scopes[0].total_condition == "ON"
for c in scopes[1:]:
extend_scope_io_string = io.StringIO()
write_regular_cmake_target_scope_section(c, extend_scope_io_string, indent=indent+1)
extend_string = extend_scope_io_string.getvalue()
if extend_string:
extend_scope = (
f"\nif({map_to_cmake_condition(c.total_condition)})\n"
f"{extend_string}"
f"endif()\n"
)
cm_fh.write(extend_scope)
def cmakeify_scope(
scope: Scope, cm_fh: IO[str], *, indent: int = 0, is_example: bool = False
) -> None:
@ -3111,6 +3215,8 @@ def cmakeify_scope(
# 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"):
@ -3184,6 +3290,21 @@ def should_convert_project(project_file_path: str = "") -> bool:
if project_relative_path.startswith("tests/auto/tools/qmake/testdata"):
return False
# Skip certain config tests.
config_tests = [
# Relative to qtbase/config.tests
"arch/arch.pro",
"avx512/avx512.pro",
"stl/stl.pro",
"verifyspec/verifyspec.pro",
"x86_simd/x86_simd.pro",
# Relative to repo src dir
"config.tests/hostcompiler/hostcompiler.pro",
]
skip_certain_tests = any(project_relative_path.startswith(c) for c in config_tests)
if skip_certain_tests:
return False
return True