diff options
Diffstat (limited to 'util/cmake')
24 files changed, 1195 insertions, 1098 deletions
diff --git a/util/cmake/README.md b/util/cmake/README.md index f8a6e9f540..0d80fbcdce 100644 --- a/util/cmake/README.md +++ b/util/cmake/README.md @@ -2,6 +2,9 @@ This directory holds scripts to help the porting process from `qmake` to `cmake` for Qt6. +If you're looking to port your own Qt-based project from `qmake` to `cmake`, please use +[qmake2cmake](https://wiki.qt.io/Qmake2cmake). + # Requirements * [Python 3.7](https://www.python.org/downloads/), @@ -39,22 +42,16 @@ python3.7 -m pip install -r requirements.txt You can verify if the styling of a script is compliant with PEP8, with a couple of exceptions: Install [flake8](http://flake8.pycqa.org/en/latest/) (`pip install flake8`) and run it -on the script you want to test: +on all python source files: ``` -flake8 <file>.py --ignore=E501,E266,W503 +make flake8 ``` -* `E501`: Line too long (82>79 characters), -* `E266`: Too many leading '#' for block comment, -* `W503`: Line break occurred before a binary operator) - You can also modify the file with an automatic formatter, like [black](https://black.readthedocs.io/en/stable/) (`pip install black`), and execute it: ``` -black -l 100 <file>.py +make format ``` - -Using Qt's maximum line length, 100. diff --git a/util/cmake/cmakeconversionrate.py b/util/cmake/cmakeconversionrate.py index b87957df6c..012ef1ee2d 100755 --- a/util/cmake/cmakeconversionrate.py +++ b/util/cmake/cmakeconversionrate.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 from argparse import ArgumentParser @@ -46,7 +21,7 @@ def _parse_commandline(): ) parser.add_argument( "binary_directory", - metavar="<CMake build direcotry>", + metavar="<CMake build directory>", type=str, help="The CMake build directory (might be empty)", ) diff --git a/util/cmake/condition_simplifier.py b/util/cmake/condition_simplifier.py index e6588a7cc7..a540ee0519 100644..100755 --- a/util/cmake/condition_simplifier.py +++ b/util/cmake/condition_simplifier.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2019 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2021 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import re @@ -72,8 +47,8 @@ def _simplify_expressions(expr, op, matches, replacement): def _simplify_flavors_in_condition(base: str, flavors, expr): - """ Simplify conditions based on the knowledge of which flavors - belong to which OS. """ + """Simplify conditions based on the knowledge of which flavors + belong to which OS.""" base_expr = simplify_logic(base) false_expr = simplify_logic("false") for flavor in flavors: @@ -100,15 +75,15 @@ def _simplify_os_families(expr, family_members, other_family_members): def _recursive_simplify(expr): - """ Simplify the expression as much as possible based on - domain knowledge. """ + """Simplify the expression as much as possible based on + domain knowledge.""" input_expr = expr # Simplify even further, based on domain knowledge: # windowses = ('WIN32', 'WINRT') apples = ("MACOS", "UIKIT", "IOS", "TVOS", "WATCHOS") bsds = ("FREEBSD", "OPENBSD", "NETBSD") - androids = ("ANDROID", "ANDROID_EMBEDDED") + androids = ("ANDROID",) unixes = ( "APPLE", *apples, @@ -140,7 +115,6 @@ def _recursive_simplify(expr): expr = _simplify_flavors_in_condition("APPLE", apples, expr) expr = _simplify_flavors_in_condition("BSD", bsds, expr) expr = _simplify_flavors_in_condition("UNIX", unixes, expr) - expr = _simplify_flavors_in_condition("ANDROID", ("ANDROID_EMBEDDED",), expr) # Simplify families of OSes against other families: expr = _simplify_os_families(expr, ("WIN32", "WINRT"), unixes) diff --git a/util/cmake/condition_simplifier_cache.py b/util/cmake/condition_simplifier_cache.py index 58cd5b88c5..5995c5bb81 100644..100755 --- a/util/cmake/condition_simplifier_cache.py +++ b/util/cmake/condition_simplifier_cache.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import atexit @@ -105,11 +80,7 @@ def open_file_safe(file_path: str, mode: str = "r+"): try: import portalocker # type: ignore - file_open_func = portalocker.Lock - file_open_args = [file_path] - file_open_kwargs = {"mode": mode, "flags": portalocker.LOCK_EX} - file_handle = file_open_func(*file_open_args, **file_open_kwargs) - return file_handle + return portalocker.Lock(file_path, mode=mode, flags=portalocker.LOCK_EX) except ImportError: print( "The conversion script is missing a required package: portalocker. Please run " diff --git a/util/cmake/configurejson2cmake.py b/util/cmake/configurejson2cmake.py index b5e148f63c..50a40f6112 100755 --- a/util/cmake/configurejson2cmake.py +++ b/util/cmake/configurejson2cmake.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import json_parser import posixpath @@ -611,7 +586,7 @@ def write_compile_test( head = detail.get("head") if isinstance(head, list): head = "\n".join(head) - return head + '\n' if head else '' + return head + "\n" if head else "" head = "" if inherit_details: @@ -646,7 +621,7 @@ def write_compile_test( tail = detail.get("tail") if isinstance(tail, list): tail = "\n".join(tail) - return tail + '\n' if tail else '' + return tail + "\n" if tail else "" tail = "" if inherit_details: @@ -655,8 +630,8 @@ def write_compile_test( sourceCode += tail - if sourceCode: # blank line before main - sourceCode += '\n' + if sourceCode: # blank line before main + sourceCode += "\n" sourceCode += "int main(void)\n" sourceCode += "{\n" sourceCode += " /* BEGIN TEST: */\n" @@ -665,7 +640,7 @@ def write_compile_test( main = detail.get("main") if isinstance(main, list): main = "\n".join(main) - return main + '\n' if main else '' + return main + "\n" if main else "" main = "" if inherit_details: @@ -934,7 +909,7 @@ endif()""", "condition": "__qt_ltcg_detected", }, "msvc_mp": None, - "simulator_and_device": {"condition": "UIKIT AND NOT QT_UIKIT_SDK"}, + "simulator_and_device": {"condition": "UIKIT AND NOT QT_APPLE_SDK"}, "pkg-config": {"condition": "PKG_CONFIG_FOUND"}, "precompile_header": {"condition": "BUILD_WITH_PCH"}, "profile": None, @@ -943,7 +918,11 @@ endif()""", "qreal": { "condition": 'DEFINED QT_COORD_TYPE AND NOT QT_COORD_TYPE STREQUAL "double"', "output": [ - {"type": "define", "name": "QT_COORD_TYPE", "value": "${QT_COORD_TYPE}",}, + { + "type": "define", + "name": "QT_COORD_TYPE", + "value": "${QT_COORD_TYPE}", + }, { "type": "define", "name": "QT_COORD_TYPE_STRING", @@ -951,7 +930,9 @@ endif()""", }, ], }, - "reduce_exports": {"condition": "NOT MSVC",}, + "reduce_exports": { + "condition": "NOT MSVC", + }, "release": None, "release_tools": None, "rpath": { @@ -1407,11 +1388,6 @@ def parseCommandLinePrefixes(ctx, data, cm_fh): cm_fh.write(f"qt_commandline_prefix({key} {data[key]})\n") -def parseCommandLineAssignments(ctx, data, cm_fh): - for key in data: - cm_fh.write(f"qt_commandline_assignment({key} {data[key]})\n") - - def processCommandLine(ctx, data, cm_fh): print(" commandline:") @@ -1433,8 +1409,7 @@ def processCommandLine(ctx, data, cm_fh): print(" prefix:") parseCommandLinePrefixes(ctx, commandLine["prefix"], cm_fh) if "assignments" in commandLine: - print(" assignments:") - parseCommandLineAssignments(ctx, commandLine["assignments"], cm_fh) + print(" assignments are ignored") def processInputs(ctx, data, cm_fh): @@ -1524,6 +1499,7 @@ class special_cased_file: self.sc_handler.handle_special_cases() os.replace(self.gen_file_path, self.file_path) + def processJson(path, ctx, data, skip_special_case_preservation=False): ctx["project_dir"] = path ctx["module"] = data.get("module", "global") @@ -1571,7 +1547,7 @@ def main(): quit(1) directory = sys.argv[1] - skip_special_case_preservation = '-s' in sys.argv[2:] + skip_special_case_preservation = "-s" in sys.argv[2:] print(f"Processing: {directory}.") diff --git a/util/cmake/generate_module_map.sh b/util/cmake/generate_module_map.sh index 1ca0bfc43c..8cca1c0aa3 100755 --- a/util/cmake/generate_module_map.sh +++ b/util/cmake/generate_module_map.sh @@ -1,31 +1,6 @@ #!/usr/bin/bash -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 pro_files=$(find . -name \*.pro) diff --git a/util/cmake/helper.py b/util/cmake/helper.py index e0f4309a4f..3e9f4d73b2 100644 --- a/util/cmake/helper.py +++ b/util/cmake/helper.py @@ -1,30 +1,5 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2021 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import re import typing @@ -39,6 +14,7 @@ class LibraryMapping: *, resultVariable: typing.Optional[str] = None, extra: typing.List[str] = [], + components: typing.Optional[typing.List[str]] = None, appendFoundSuffix: bool = True, emit_if: str = "", is_bundled_with_qt: bool = False, @@ -52,6 +28,7 @@ class LibraryMapping: self.appendFoundSuffix = appendFoundSuffix # Allows passing addiitonal arguments to the generated find_package call. self.extra = extra + self.components = components self.targetName = targetName # True if qt bundles the library sources as part of Qt. @@ -77,327 +54,309 @@ class LibraryMapping: _qt_library_map = [ # Qt: - LibraryMapping( - "androidextras", "Qt6", "Qt::AndroidExtras", extra=["COMPONENTS", "AndroidExtras"] - ), - LibraryMapping("3danimation", "Qt6", "Qt::3DAnimation", extra=["COMPONENTS", "3DAnimation"]), - LibraryMapping("3dcore", "Qt6", "Qt::3DCore", extra=["COMPONENTS", "3DCore"]), - LibraryMapping("3dcoretest", "Qt6", "Qt::3DCoreTest", extra=["COMPONENTS", "3DCoreTest"]), - LibraryMapping("3dextras", "Qt6", "Qt::3DExtras", extra=["COMPONENTS", "3DExtras"]), - LibraryMapping("3dinput", "Qt6", "Qt::3DInput", extra=["COMPONENTS", "3DInput"]), - LibraryMapping("3dlogic", "Qt6", "Qt::3DLogic", extra=["COMPONENTS", "3DLogic"]), - LibraryMapping("3dquick", "Qt6", "Qt::3DQuick", extra=["COMPONENTS", "3DQuick"]), - LibraryMapping( - "3dquickextras", "Qt6", "Qt::3DQuickExtras", extra=["COMPONENTS", "3DQuickExtras"] - ), - LibraryMapping("3dquickinput", "Qt6", "Qt::3DQuickInput", extra=["COMPONENTS", "3DQuickInput"]), - LibraryMapping( - "3dquickrender", "Qt6", "Qt::3DQuickRender", extra=["COMPONENTS", "3DQuickRender"] - ), - LibraryMapping("3drender", "Qt6", "Qt::3DRender", extra=["COMPONENTS", "3DRender"]), - LibraryMapping( - "application-lib", "Qt6", "Qt::AppManApplication", extra=["COMPONENTS", "AppManApplication"] - ), - LibraryMapping("axbase", "Qt6", "Qt::AxBase", extra=["COMPONENTS", "AxBase"]), - LibraryMapping("axcontainer", "Qt6", "Qt::AxContainer", extra=["COMPONENTS", "AxContainer"]), - LibraryMapping("axserver", "Qt6", "Qt::AxServer", extra=["COMPONENTS", "AxServer"]), - LibraryMapping("bluetooth", "Qt6", "Qt::Bluetooth", extra=["COMPONENTS", "Bluetooth"]), - LibraryMapping("bootstrap", "Qt6", "Qt::Bootstrap", extra=["COMPONENTS", "Bootstrap"]), + LibraryMapping("androidextras", "Qt6", "Qt::AndroidExtras", components=["AndroidExtras"]), + LibraryMapping("3danimation", "Qt6", "Qt::3DAnimation", components=["3DAnimation"]), + LibraryMapping("3dcore", "Qt6", "Qt::3DCore", components=["3DCore"]), + LibraryMapping("3dcoretest", "Qt6", "Qt::3DCoreTest", components=["3DCoreTest"]), + LibraryMapping("3dextras", "Qt6", "Qt::3DExtras", components=["3DExtras"]), + LibraryMapping("3dinput", "Qt6", "Qt::3DInput", components=["3DInput"]), + LibraryMapping("3dlogic", "Qt6", "Qt::3DLogic", components=["3DLogic"]), + LibraryMapping("3dquick", "Qt6", "Qt::3DQuick", components=["3DQuick"]), + LibraryMapping("3dquickextras", "Qt6", "Qt::3DQuickExtras", components=["3DQuickExtras"]), + LibraryMapping("3dquickinput", "Qt6", "Qt::3DQuickInput", components=["3DQuickInput"]), + LibraryMapping("3dquickrender", "Qt6", "Qt::3DQuickRender", components=["3DQuickRender"]), + LibraryMapping("3drender", "Qt6", "Qt::3DRender", components=["3DRender"]), + LibraryMapping( + "application-lib", "Qt6", "Qt::AppManApplication", components=["AppManApplication"] + ), + LibraryMapping("axbase", "Qt6", "Qt::AxBasePrivate", components=["AxBasePrivate"]), + LibraryMapping("axcontainer", "Qt6", "Qt::AxContainer", components=["AxContainer"]), + LibraryMapping("axserver", "Qt6", "Qt::AxServer", components=["AxServer"]), + LibraryMapping("bluetooth", "Qt6", "Qt::Bluetooth", components=["Bluetooth"]), + LibraryMapping("bootstrap", "Qt6", "Qt::Bootstrap", components=["Bootstrap"]), # bootstrap-dbus: Not needed in Qt6! - LibraryMapping("client", "Qt6", "Qt::WaylandClient", extra=["COMPONENTS", "WaylandClient"]), - LibraryMapping("coap", "Qt6", "Qt::Coap", extra=["COMPONENTS", "Coap"]), - LibraryMapping("common-lib", "Qt6", "Qt::AppManCommon", extra=["COMPONENTS", "AppManCommon"]), - LibraryMapping( - "compositor", "Qt6", "Qt::WaylandCompositor", extra=["COMPONENTS", "WaylandCompositor"] - ), - LibraryMapping("concurrent", "Qt6", "Qt::Concurrent", extra=["COMPONENTS", "Concurrent"]), - LibraryMapping("container", "Qt6", "Qt::AxContainer", extra=["COMPONENTS", "AxContainer"]), - LibraryMapping("control", "Qt6", "Qt::AxServer", extra=["COMPONENTS", "AxServer"]), - LibraryMapping( - "core_headers", "Qt6", "Qt::WebEngineCore", extra=["COMPONENTS", "WebEngineCore"] - ), - LibraryMapping("core", "Qt6", "Qt::Core", extra=["COMPONENTS", "Core"]), - LibraryMapping("crypto-lib", "Qt6", "Qt::AppManCrypto", extra=["COMPONENTS", "AppManCrypto"]), - LibraryMapping("dbus", "Qt6", "Qt::DBus", extra=["COMPONENTS", "DBus"]), - LibraryMapping("designer", "Qt6", "Qt::Designer", extra=["COMPONENTS", "Designer"]), + LibraryMapping("client", "Qt6", "Qt::WaylandClient", components=["WaylandClient"]), + LibraryMapping("coap", "Qt6", "Qt::Coap", components=["Coap"]), + LibraryMapping("common-lib", "Qt6", "Qt::AppManCommon", components=["AppManCommon"]), + LibraryMapping("compositor", "Qt6", "Qt::WaylandCompositor", components=["WaylandCompositor"]), + LibraryMapping("concurrent", "Qt6", "Qt::Concurrent", components=["Concurrent"]), + LibraryMapping("container", "Qt6", "Qt::AxContainer", components=["AxContainer"]), + LibraryMapping("control", "Qt6", "Qt::AxServer", components=["AxServer"]), + LibraryMapping("core_headers", "Qt6", "Qt::WebEngineCore", components=["WebEngineCore"]), + LibraryMapping("core", "Qt6", "Qt::Core", components=["Core"]), + LibraryMapping("crypto-lib", "Qt6", "Qt::AppManCrypto", components=["AppManCrypto"]), + LibraryMapping("dbus", "Qt6", "Qt::DBus", components=["DBus"]), + LibraryMapping("designer", "Qt6", "Qt::Designer", components=["Designer"]), LibraryMapping( "designercomponents", "Qt6", - "Qt::DesignerComponents", - extra=["COMPONENTS", "DesignerComponents"], + "Qt::DesignerComponentsPrivate", + components=["DesignerComponentsPrivate"], ), LibraryMapping( "devicediscovery", "Qt6", - "Qt::DeviceDiscoverySupport", - extra=["COMPONENTS", "DeviceDiscoverySupport"], + "Qt::DeviceDiscoverySupportPrivate", + components=["DeviceDiscoverySupportPrivate"], ), LibraryMapping( "devicediscovery_support", "Qt6", - "Qt::DeviceDiscoverySupport", - extra=["COMPONENTS", "DeviceDiscoverySupport"], + "Qt::DeviceDiscoverySupportPrivate", + components=["DeviceDiscoverySupportPrivate"], ), - LibraryMapping("edid", "Qt6", "Qt::EdidSupport", extra=["COMPONENTS", "EdidSupport"]), - LibraryMapping("edid_support", "Qt6", "Qt::EdidSupport", extra=["COMPONENTS", "EdidSupport"]), - LibraryMapping("eglconvenience", "Qt6", "Qt::EglSupport", extra=["COMPONENTS", "EglSupport"]), + LibraryMapping("edid", "Qt6", "Qt::EdidSupport", components=["EdidSupport"]), + LibraryMapping("edid_support", "Qt6", "Qt::EdidSupport", components=["EdidSupport"]), + LibraryMapping("eglconvenience", "Qt6", "Qt::EglSupport", components=["EglSupport"]), LibraryMapping( "eglfsdeviceintegration", "Qt6", - "Qt::EglFSDeviceIntegration", - extra=["COMPONENTS", "EglFSDeviceIntegration"], + "Qt::EglFSDeviceIntegrationPrivate", + components=["EglFSDeviceIntegrationPrivate"], ), LibraryMapping( - "eglfs_kms_support", "Qt6", "Qt::EglFsKmsSupport", extra=["COMPONENTS", "EglFsKmsSupport"] + "eglfs_kms_support", + "Qt6", + "Qt::EglFsKmsSupportPrivate", + components=["EglFsKmsSupportPrivate"], ), LibraryMapping( "eglfs_kms_gbm_support", "Qt6", - "Qt::EglFsKmsGbmSupport", - extra=["COMPONENTS", "EglFsKmsGbmSupport"], + "Qt::EglFsKmsGbmSupportPrivate", + components=["EglFsKmsGbmSupportPrivate"], ), - LibraryMapping("egl_support", "Qt6", "Qt::EglSupport", extra=["COMPONENTS", "EglSupport"]), + LibraryMapping("egl_support", "Qt6", "Qt::EglSupport", components=["EglSupport"]), # enginio: Not needed in Qt6! LibraryMapping( "eventdispatchers", "Qt6", "Qt::EventDispatcherSupport", - extra=["COMPONENTS", "EventDispatcherSupport"], + components=["EventDispatcherSupport"], ), LibraryMapping( "eventdispatcher_support", "Qt6", "Qt::EventDispatcherSupport", - extra=["COMPONENTS", "EventDispatcherSupport"], + components=["EventDispatcherSupport"], ), - LibraryMapping("fbconvenience", "Qt6", "Qt::FbSupport", extra=["COMPONENTS", "FbSupport"]), - LibraryMapping("fb_support", "Qt6", "Qt::FbSupport", extra=["COMPONENTS", "FbSupport"]), + LibraryMapping("fbconvenience", "Qt6", "Qt::FbSupportPrivate", components=["FbSupportPrivate"]), + LibraryMapping("fb_support", "Qt6", "Qt::FbSupportPrivate", components=["FbSupportPrivate"]), LibraryMapping( "fontdatabase_support", "Qt6", "Qt::FontDatabaseSupport", - extra=["COMPONENTS", "FontDatabaseSupport"], + components=["FontDatabaseSupport"], ), - LibraryMapping("gamepad", "Qt6", "Qt::Gamepad", extra=["COMPONENTS", "Gamepad"]), - LibraryMapping( - "global", "Qt6", "Qt::Core", extra=["COMPONENTS", "Core"] - ), # manually added special case - LibraryMapping("glx_support", "Qt6", "Qt::GlxSupport", extra=["COMPONENTS", "GlxSupport"]), - LibraryMapping( - "gsttools", "Qt6", "Qt::MultimediaGstTools", extra=["COMPONENTS", "MultimediaGstTools"] - ), - LibraryMapping("gui", "Qt6", "Qt::Gui", extra=["COMPONENTS", "Gui"]), - LibraryMapping("help", "Qt6", "Qt::Help", extra=["COMPONENTS", "Help"]), + LibraryMapping("gamepad", "Qt6", "Qt::Gamepad", components=["Gamepad"]), + LibraryMapping("geniviextras", "Qt6", "Qt::GeniviExtras", components=["GeniviExtras"]), + LibraryMapping("global", "Qt6", "Qt::Core", components=["Core"]), # manually added special case + LibraryMapping("glx_support", "Qt6", "Qt::GlxSupport", components=["GlxSupport"]), + LibraryMapping("gsttools", "Qt6", "Qt::MultimediaGstTools", components=["MultimediaGstTools"]), + LibraryMapping("gui", "Qt6", "Qt::Gui", components=["Gui"]), + LibraryMapping("help", "Qt6", "Qt::Help", components=["Help"]), LibraryMapping( "hunspellinputmethod", "Qt6", - "Qt::HunspellInputMethod", - extra=["COMPONENTS", "HunspellInputMethod"], - ), - LibraryMapping("input", "Qt6", "Qt::InputSupport", extra=["COMPONENTS", "InputSupport"]), - LibraryMapping( - "input_support", "Qt6", "Qt::InputSupport", extra=["COMPONENTS", "InputSupport"] + "Qt::HunspellInputMethodPrivate", + components=["HunspellInputMethodPrivate"], ), + LibraryMapping("input", "Qt6", "Qt::InputSupportPrivate", components=["InputSupportPrivate"]), LibraryMapping( - "installer-lib", "Qt6", "Qt::AppManInstaller", extra=["COMPONENTS", "AppManInstaller"] + "input_support", + "Qt6", + "Qt::InputSupportPrivate", + components=["InputSupportPrivate"], ), - LibraryMapping("knx", "Qt6", "Qt::Knx", extra=["COMPONENTS", "Knx"]), - LibraryMapping("kmsconvenience", "Qt6", "Qt::KmsSupport", extra=["COMPONENTS", "KmsSupport"]), - LibraryMapping("kms_support", "Qt6", "Qt::KmsSupport", extra=["COMPONENTS", "KmsSupport"]), + LibraryMapping("installer-lib", "Qt6", "Qt::AppManInstaller", components=["AppManInstaller"]), + LibraryMapping("ivi", "Qt6", "Qt::Ivi", components=["Ivi"]), + LibraryMapping("ivicore", "Qt6", "Qt::IviCore", components=["IviCore"]), + LibraryMapping("ivimedia", "Qt6", "Qt::IviMedia", components=["IviMedia"]), + LibraryMapping("knx", "Qt6", "Qt::Knx", components=["Knx"]), LibraryMapping( - "launcher-lib", "Qt6", "Qt::AppManLauncher", extra=["COMPONENTS", "AppManLauncher"] + "kmsconvenience", "Qt6", "Qt::KmsSupportPrivate", components=["KmsSupportPrivate"] ), - LibraryMapping("lib", "Qt6", "Qt::Designer", extra=["COMPONENTS", "Designer"]), + LibraryMapping("kms_support", "Qt6", "Qt::KmsSupportPrivate", components=["KmsSupportPrivate"]), + LibraryMapping("launcher-lib", "Qt6", "Qt::AppManLauncher", components=["AppManLauncher"]), + LibraryMapping("lib", "Qt6", "Qt::Designer", components=["Designer"]), LibraryMapping( "linuxaccessibility_support", "Qt6", "Qt::LinuxAccessibilitySupport", - extra=["COMPONENTS", "LinuxAccessibilitySupport"], - ), - LibraryMapping("location", "Qt6", "Qt::Location", extra=["COMPONENTS", "Location"]), - LibraryMapping("macextras", "Qt6", "Qt::MacExtras", extra=["COMPONENTS", "MacExtras"]), - LibraryMapping("main-lib", "Qt6", "Qt::AppManMain", extra=["COMPONENTS", "AppManMain"]), - LibraryMapping( - "manager-lib", "Qt6", "Qt::AppManManager", extra=["COMPONENTS", "AppManManager"] - ), - LibraryMapping( - "monitor-lib", "Qt6", "Qt::AppManMonitor", extra=["COMPONENTS", "AppManMonitor"] + components=["LinuxAccessibilitySupport"], ), - LibraryMapping("mqtt", "Qt6", "Qt::Mqtt", extra=["COMPONENTS", "Mqtt"]), - LibraryMapping("multimedia", "Qt6", "Qt::Multimedia", extra=["COMPONENTS", "Multimedia"]), + LibraryMapping("location", "Qt6", "Qt::Location", components=["Location"]), + LibraryMapping("macextras", "Qt6", "Qt::MacExtras", components=["MacExtras"]), + LibraryMapping("main-lib", "Qt6", "Qt::AppManMain", components=["AppManMain"]), + LibraryMapping("manager-lib", "Qt6", "Qt::AppManManager", components=["AppManManager"]), + LibraryMapping("monitor-lib", "Qt6", "Qt::AppManMonitor", components=["AppManMonitor"]), + LibraryMapping("mqtt", "Qt6", "Qt::Mqtt", components=["Mqtt"]), + LibraryMapping("multimedia", "Qt6", "Qt::Multimedia", components=["Multimedia"]), LibraryMapping( "multimediawidgets", "Qt6", "Qt::MultimediaWidgets", - extra=["COMPONENTS", "MultimediaWidgets"], - ), - LibraryMapping("network", "Qt6", "Qt::Network", extra=["COMPONENTS", "Network"]), - LibraryMapping("networkauth", "Qt6", "Qt::NetworkAuth", extra=["COMPONENTS", "NetworkAuth"]), - LibraryMapping("nfc", "Qt6", "Qt::Nfc", extra=["COMPONENTS", "Nfc"]), - LibraryMapping("oauth", "Qt6", "Qt::NetworkAuth", extra=["COMPONENTS", "NetworkAuth"]), - LibraryMapping("opcua", "Qt6", "Qt::OpcUa", extra=["COMPONENTS", "OpcUa"]), - LibraryMapping( - "opcua_private", "Qt6", "Qt::OpcUaPrivate", extra=["COMPONENTS", "OpcUaPrivate"] - ), - LibraryMapping("opengl", "Qt6", "Qt::OpenGL", extra=["COMPONENTS", "OpenGL"]), - LibraryMapping( - "openglwidgets", "Qt6", "Qt::OpenGLWidgets", extra=["COMPONENTS", "OpenGLWidgets"] + components=["MultimediaWidgets"], + ), + LibraryMapping("network", "Qt6", "Qt::Network", components=["Network"]), + LibraryMapping("networkauth", "Qt6", "Qt::NetworkAuth", components=["NetworkAuth"]), + LibraryMapping("nfc", "Qt6", "Qt::Nfc", components=["Nfc"]), + LibraryMapping("oauth", "Qt6", "Qt::NetworkAuth", components=["NetworkAuth"]), + LibraryMapping("opcua", "Qt6", "Qt::OpcUa", components=["OpcUa"]), + LibraryMapping("opcua_private", "Qt6", "Qt::OpcUaPrivate", components=["OpcUaPrivate"]), + LibraryMapping("opengl", "Qt6", "Qt::OpenGL", components=["OpenGL"]), + LibraryMapping("openglwidgets", "Qt6", "Qt::OpenGLWidgets", components=["OpenGLWidgets"]), + LibraryMapping("package-lib", "Qt6", "Qt::AppManPackage", components=["AppManPackage"]), + LibraryMapping( + "packetprotocol", + "Qt6", + "Qt::PacketProtocolPrivate", + components=["PacketProtocolPrivate"], ), LibraryMapping( - "package-lib", "Qt6", "Qt::AppManPackage", extra=["COMPONENTS", "AppManPackage"] + "particles", + "Qt6", + "Qt::QuickParticlesPrivate", + components=["QuickParticlesPrivate"], ), LibraryMapping( - "packetprotocol", "Qt6", "Qt::PacketProtocol", extra=["COMPONENTS", "PacketProtocol"] + "plugin-interfaces", + "Qt6", + "Qt::AppManPluginInterfaces", + components=["AppManPluginInterfaces"], ), + LibraryMapping("positioning", "Qt6", "Qt::Positioning", components=["Positioning"]), LibraryMapping( - "particles", "Qt6", "Qt::QuickParticles", extra=["COMPONENTS", "QuickParticles"] + "positioningquick", "Qt6", "Qt::PositioningQuick", components=["PositioningQuick"] ), + LibraryMapping("printsupport", "Qt6", "Qt::PrintSupport", components=["PrintSupport"]), + LibraryMapping("purchasing", "Qt6", "Qt::Purchasing", components=["Purchasing"]), + LibraryMapping("qmldebug", "Qt6", "Qt::QmlDebugPrivate", components=["QmlDebugPrivate"]), LibraryMapping( - "plugin-interfaces", - "Qt6", - "Qt::AppManPluginInterfaces", - extra=["COMPONENTS", "AppManPluginInterfaces"], + "qmldevtools", "Qt6", "Qt::QmlDevToolsPrivate", components=["QmlDevToolsPrivate"] ), - LibraryMapping("positioning", "Qt6", "Qt::Positioning", extra=["COMPONENTS", "Positioning"]), LibraryMapping( - "positioningquick", "Qt6", "Qt::PositioningQuick", extra=["COMPONENTS", "PositioningQuick"] + "qmlcompiler", "Qt6", "Qt::QmlCompilerPrivate", components=["QmlCompilerPrivate"] ), - LibraryMapping("printsupport", "Qt6", "Qt::PrintSupport", extra=["COMPONENTS", "PrintSupport"]), - LibraryMapping("purchasing", "Qt6", "Qt::Purchasing", extra=["COMPONENTS", "Purchasing"]), - LibraryMapping("qmldebug", "Qt6", "Qt::QmlDebug", extra=["COMPONENTS", "QmlDebug"]), - LibraryMapping("qmldevtools", "Qt6", "Qt::QmlDevTools", extra=["COMPONENTS", "QmlDevTools"]), - LibraryMapping("qmlcompiler", "Qt6", "Qt::QmlCompiler", extra=["COMPONENTS", "QmlCompiler"]), - LibraryMapping("qml", "Qt6", "Qt::Qml", extra=["COMPONENTS", "Qml"]), - LibraryMapping("qmldom", "Qt6", "Qt::QmlDom", extra=["COMPONENTS", "QmlDom"]), - LibraryMapping("qmlmodels", "Qt6", "Qt::QmlModels", extra=["COMPONENTS", "QmlModels"]), - LibraryMapping("qmltest", "Qt6", "Qt::QuickTest", extra=["COMPONENTS", "QuickTest"]), + LibraryMapping("qml", "Qt6", "Qt::Qml", components=["Qml"]), + LibraryMapping("qmldom", "Qt6", "Qt::QmlDomPrivate", components=["QmlDomPrivate"]), + LibraryMapping("qmlmodels", "Qt6", "Qt::QmlModels", components=["QmlModels"]), + LibraryMapping("qmltest", "Qt6", "Qt::QuickTest", components=["QuickTest"]), LibraryMapping( "qtmultimediaquicktools", "Qt6", - "Qt::MultimediaQuick", - extra=["COMPONENTS", "MultimediaQuick"], + "Qt::MultimediaQuickPrivate", + components=["MultimediaQuickPrivate"], ), LibraryMapping( "quick3dassetimport", "Qt6", "Qt::Quick3DAssetImport", - extra=["COMPONENTS", "Quick3DAssetImport"], - ), - LibraryMapping("core5compat", "Qt6", "Qt::Core5Compat", extra=["COMPONENTS", "Core5Compat"]), - LibraryMapping("quick3d", "Qt6", "Qt::Quick3D", extra=["COMPONENTS", "Quick3D"]), - LibraryMapping( - "quick3drender", "Qt6", "Qt::Quick3DRender", extra=["COMPONENTS", "Quick3DRender"] + components=["Quick3DAssetImport"], ), + LibraryMapping("core5compat", "Qt6", "Qt::Core5Compat", components=["Core5Compat"]), + LibraryMapping("quick3d", "Qt6", "Qt::Quick3D", components=["Quick3D"]), + LibraryMapping("quick3drender", "Qt6", "Qt::Quick3DRender", components=["Quick3DRender"]), LibraryMapping( "quick3druntimerender", "Qt6", "Qt::Quick3DRuntimeRender", - extra=["COMPONENTS", "Quick3DRuntimeRender"], - ), - LibraryMapping("quick3dutils", "Qt6", "Qt::Quick3DUtils", extra=["COMPONENTS", "Quick3DUtils"]), - LibraryMapping( - "quickcontrols2", "Qt6", "Qt::QuickControls2", extra=["COMPONENTS", "QuickControls2"] + components=["Quick3DRuntimeRender"], ), + LibraryMapping("quick3dutils", "Qt6", "Qt::Quick3DUtils", components=["Quick3DUtils"]), + LibraryMapping("quickcontrols2", "Qt6", "Qt::QuickControls2", components=["QuickControls2"]), LibraryMapping( "quickcontrols2impl", "Qt6", "Qt::QuickControls2Impl", - extra=["COMPONENTS", "QuickControls2Impl"], - ), - LibraryMapping("quick", "Qt6", "Qt::Quick", extra=["COMPONENTS", "Quick"]), - LibraryMapping("quickshapes", "Qt6", "Qt::QuickShapes", extra=["COMPONENTS", "QuickShapes"]), - LibraryMapping( - "quicktemplates2", "Qt6", "Qt::QuickTemplates2", extra=["COMPONENTS", "QuickTemplates2"] - ), - LibraryMapping("quickwidgets", "Qt6", "Qt::QuickWidgets", extra=["COMPONENTS", "QuickWidgets"]), - LibraryMapping( - "remoteobjects", "Qt6", "Qt::RemoteObjects", extra=["COMPONENTS", "RemoteObjects"] - ), - LibraryMapping("script", "Qt6", "Qt::Script", extra=["COMPONENTS", "Script"]), - LibraryMapping("scripttools", "Qt6", "Qt::ScriptTools", extra=["COMPONENTS", "ScriptTools"]), - LibraryMapping("scxml", "Qt6", "Qt::Scxml", extra=["COMPONENTS", "Scxml"]), - LibraryMapping("sensors", "Qt6", "Qt::Sensors", extra=["COMPONENTS", "Sensors"]), - LibraryMapping("serialport", "Qt6", "Qt::SerialPort", extra=["COMPONENTS", "SerialPort"]), - LibraryMapping("serialbus", "Qt6", "Qt::SerialBus", extra=["COMPONENTS", "SerialBus"]), - LibraryMapping("services", "Qt6", "Qt::ServiceSupport", extra=["COMPONENTS", "ServiceSupport"]), - LibraryMapping( - "service_support", "Qt6", "Qt::ServiceSupport", extra=["COMPONENTS", "ServiceSupport"] - ), - LibraryMapping("shadertools", "Qt6", "Qt::ShaderTools", extra=["COMPONENTS", "ShaderTools"]), - LibraryMapping("statemachine", "Qt6", "Qt::StateMachine", extra=["COMPONENTS", "StateMachine"]), - LibraryMapping("sql", "Qt6", "Qt::Sql", extra=["COMPONENTS", "Sql"]), - LibraryMapping("svg", "Qt6", "Qt::Svg", extra=["COMPONENTS", "Svg"]), - LibraryMapping("svgwidgets", "Qt6", "Qt::SvgWidgets", extra=["COMPONENTS", "SvgWidgets"]), - LibraryMapping("charts", "Qt6", "Qt::Charts", extra=["COMPONENTS", "Charts"]), - LibraryMapping("testlib", "Qt6", "Qt::Test", extra=["COMPONENTS", "Test"]), - LibraryMapping("texttospeech", "Qt6", "Qt::TextToSpeech", extra=["COMPONENTS", "TextToSpeech"]), - LibraryMapping( - "theme_support", "Qt6", "Qt::ThemeSupport", extra=["COMPONENTS", "ThemeSupport"] - ), - LibraryMapping("tts", "Qt6", "Qt::TextToSpeech", extra=["COMPONENTS", "TextToSpeech"]), - LibraryMapping("uiplugin", "Qt6", "Qt::UiPlugin", extra=["COMPONENTS", "UiPlugin"]), - LibraryMapping("uitools", "Qt6", "Qt::UiTools", extra=["COMPONENTS", "UiTools"]), - LibraryMapping( - "virtualkeyboard", "Qt6", "Qt::VirtualKeyboard", extra=["COMPONENTS", "VirtualKeyboard"] - ), - LibraryMapping( - "waylandclient", "Qt6", "Qt::WaylandClient", extra=["COMPONENTS", "WaylandClient"] - ), + components=["QuickControls2Impl"], + ), + LibraryMapping("quick", "Qt6", "Qt::Quick", components=["Quick"]), + LibraryMapping( + "quickshapes", "Qt6", "Qt::QuickShapesPrivate", components=["QuickShapesPrivate"] + ), + LibraryMapping("quicktemplates2", "Qt6", "Qt::QuickTemplates2", components=["QuickTemplates2"]), + LibraryMapping("quickwidgets", "Qt6", "Qt::QuickWidgets", components=["QuickWidgets"]), + LibraryMapping("remoteobjects", "Qt6", "Qt::RemoteObjects", components=["RemoteObjects"]), + LibraryMapping("script", "Qt6", "Qt::Script", components=["Script"]), + LibraryMapping("scripttools", "Qt6", "Qt::ScriptTools", components=["ScriptTools"]), + LibraryMapping("scxml", "Qt6", "Qt::Scxml", components=["Scxml"]), + LibraryMapping("sensors", "Qt6", "Qt::Sensors", components=["Sensors"]), + LibraryMapping("serialport", "Qt6", "Qt::SerialPort", components=["SerialPort"]), + LibraryMapping("serialbus", "Qt6", "Qt::SerialBus", components=["SerialBus"]), + LibraryMapping("services", "Qt6", "Qt::ServiceSupport", components=["ServiceSupport"]), + LibraryMapping("service_support", "Qt6", "Qt::ServiceSupport", components=["ServiceSupport"]), + LibraryMapping("shadertools", "Qt6", "Qt::ShaderTools", components=["ShaderTools"]), + LibraryMapping("statemachine", "Qt6", "Qt::StateMachine", components=["StateMachine"]), + LibraryMapping("sql", "Qt6", "Qt::Sql", components=["Sql"]), + LibraryMapping("svg", "Qt6", "Qt::Svg", components=["Svg"]), + LibraryMapping("svgwidgets", "Qt6", "Qt::SvgWidgets", components=["SvgWidgets"]), + LibraryMapping("charts", "Qt6", "Qt::Charts", components=["Charts"]), + LibraryMapping("testlib", "Qt6", "Qt::Test", components=["Test"]), + LibraryMapping("texttospeech", "Qt6", "Qt::TextToSpeech", components=["TextToSpeech"]), + LibraryMapping("theme_support", "Qt6", "Qt::ThemeSupport", components=["ThemeSupport"]), + LibraryMapping("tts", "Qt6", "Qt::TextToSpeech", components=["TextToSpeech"]), + LibraryMapping("uiplugin", "Qt6", "Qt::UiPlugin", components=["UiPlugin"]), + LibraryMapping("uitools", "Qt6", "Qt::UiTools", components=["UiTools"]), + LibraryMapping("virtualkeyboard", "Qt6", "Qt::VirtualKeyboard", components=["VirtualKeyboard"]), + LibraryMapping("waylandclient", "Qt6", "Qt::WaylandClient", components=["WaylandClient"]), LibraryMapping( "waylandcompositor", "Qt6", "Qt::WaylandCompositor", - extra=["COMPONENTS", "WaylandCompositor"], + components=["WaylandCompositor"], ), - LibraryMapping("webchannel", "Qt6", "Qt::WebChannel", extra=["COMPONENTS", "WebChannel"]), - LibraryMapping("webengine", "Qt6", "Qt::WebEngine", extra=["COMPONENTS", "WebEngine"]), + LibraryMapping("webchannel", "Qt6", "Qt::WebChannel", components=["WebChannel"]), + LibraryMapping("webengine", "Qt6", "Qt::WebEngine", components=["WebEngine"]), LibraryMapping( - "webenginewidgets", "Qt6", "Qt::WebEngineWidgets", extra=["COMPONENTS", "WebEngineWidgets"] + "webenginewidgets", "Qt6", "Qt::WebEngineWidgets", components=["WebEngineWidgets"] ), - LibraryMapping("websockets", "Qt6", "Qt::WebSockets", extra=["COMPONENTS", "WebSockets"]), - LibraryMapping("webview", "Qt6", "Qt::WebView", extra=["COMPONENTS", "WebView"]), - LibraryMapping("widgets", "Qt6", "Qt::Widgets", extra=["COMPONENTS", "Widgets"]), - LibraryMapping("window-lib", "Qt6", "Qt::AppManWindow", extra=["COMPONENTS", "AppManWindow"]), - LibraryMapping("winextras", "Qt6", "Qt::WinExtras", extra=["COMPONENTS", "WinExtras"]), - LibraryMapping("x11extras", "Qt6", "Qt::X11Extras", extra=["COMPONENTS", "X11Extras"]), - LibraryMapping("xcb_qpa_lib", "Qt6", "Qt::XcbQpa", extra=["COMPONENTS", "XcbQpa"]), + LibraryMapping("websockets", "Qt6", "Qt::WebSockets", components=["WebSockets"]), + LibraryMapping("webview", "Qt6", "Qt::WebView", components=["WebView"]), + LibraryMapping("widgets", "Qt6", "Qt::Widgets", components=["Widgets"]), + LibraryMapping("window-lib", "Qt6", "Qt::AppManWindow", components=["AppManWindow"]), + LibraryMapping("winextras", "Qt6", "Qt::WinExtras", components=["WinExtras"]), + LibraryMapping("x11extras", "Qt6", "Qt::X11Extras", components=["X11Extras"]), + LibraryMapping("xcb_qpa_lib", "Qt6", "Qt::XcbQpaPrivate", components=["XcbQpaPrivate"]), LibraryMapping( - "xkbcommon_support", "Qt6", "Qt::XkbCommonSupport", extra=["COMPONENTS", "XkbCommonSupport"] + "xkbcommon_support", "Qt6", "Qt::XkbCommonSupport", components=["XkbCommonSupport"] ), - LibraryMapping("xmlpatterns", "Qt6", "Qt::XmlPatterns", extra=["COMPONENTS", "XmlPatterns"]), - LibraryMapping("xml", "Qt6", "Qt::Xml", extra=["COMPONENTS", "Xml"]), + LibraryMapping("xmlpatterns", "Qt6", "Qt::XmlPatterns", components=["XmlPatterns"]), + LibraryMapping("xml", "Qt6", "Qt::Xml", components=["Xml"]), + LibraryMapping("qmlworkerscript", "Qt6", "Qt::QmlWorkerScript", components=["QmlWorkerScript"]), LibraryMapping( - "qmlworkerscript", "Qt6", "Qt::QmlWorkerScript", extra=["COMPONENTS", "QmlWorkerScript"] - ), - LibraryMapping( - "quickparticles", "Qt6", "Qt::QuickParticles", extra=["COMPONENTS", "QuickParticles"] + "quickparticles", + "Qt6", + "Qt::QuickParticlesPrivate", + components=["QuickParticlesPrivate"], ), LibraryMapping( "linuxofono_support", "Qt6", "Qt::LinuxOfonoSupport", - extra=["COMPONENTS", "LinuxOfonoSupport"], + components=["LinuxOfonoSupport"], ), LibraryMapping( "linuxofono_support_private", "Qt6", "Qt::LinuxOfonoSupportPrivate", - extra=["COMPONENTS", "LinuxOfonoSupportPrivate"], - ), - LibraryMapping("tools", "Qt6", "Qt::Tools", extra=["COMPONENTS", "Tools"]), - LibraryMapping("axcontainer", "Qt6", "Qt::AxContainer", extra=["COMPONENTS", "AxContainer"]), - LibraryMapping( - "webkitwidgets", "Qt6", "Qt::WebKitWidgets", extra=["COMPONENTS", "WebKitWidgets"] - ), - LibraryMapping("zlib", "Qt6", "Qt::Zlib", extra=["COMPONENTS", "Zlib"]), - LibraryMapping("httpserver", "Qt6", "Qt::HttpServer", extra=["COMPONENTS", "HttpServer"]), - LibraryMapping("sslserver", "Qt6", "Qt::SslServer", extra=["COMPONENTS", "HttpServer"]), + components=["LinuxOfonoSupportPrivate"], + ), + LibraryMapping("tools", "Qt6", "Qt::Tools", components=["Tools"]), + LibraryMapping("axcontainer", "Qt6", "Qt::AxContainer", components=["AxContainer"]), + LibraryMapping("webkitwidgets", "Qt6", "Qt::WebKitWidgets", components=["WebKitWidgets"]), + LibraryMapping("zlib", "Qt6", "Qt::Zlib", components=["Zlib"]), + LibraryMapping("httpserver", "Qt6", "Qt::HttpServer", components=["HttpServer"]), + LibraryMapping("sslserver", "Qt6", "Qt::SslServer", components=["HttpServer"]), ] # Note that the library map is adjusted dynamically further down. _library_map = [ # 3rd party: LibraryMapping("atspi", "ATSPI2", "PkgConfig::ATSPI2"), + LibraryMapping( + "backtrace", "WrapBacktrace", "WrapBacktrace::WrapBacktrace", emit_if="config.unix" + ), LibraryMapping("bluez", "BlueZ", "PkgConfig::BlueZ"), LibraryMapping("brotli", "WrapBrotli", "WrapBrotli::WrapBrotliDec"), LibraryMapping("corewlan", None, None), @@ -406,8 +365,10 @@ _library_map = [ LibraryMapping("db2", "DB2", "DB2::DB2"), LibraryMapping("dbus", "WrapDBus1", "dbus-1", resultVariable="DBus1", extra=["1.2"]), LibraryMapping( - "doubleconversion", "WrapDoubleConversion", "WrapDoubleConversion::WrapDoubleConversion" + "doubleconversion", "WrapSystemDoubleConversion", + "WrapSystemDoubleConversion::WrapSystemDoubleConversion" ), + LibraryMapping("dlt", "DLT", "DLT::DLT"), LibraryMapping("drm", "Libdrm", "Libdrm::Libdrm"), LibraryMapping("egl", "EGL", "EGL::EGL"), LibraryMapping("flite", "Flite", "Flite::Flite"), @@ -435,9 +396,7 @@ _library_map = [ extra=["2.6.0"], ), LibraryMapping("host_dbus", None, None), - LibraryMapping( - "icu", "ICU", "ICU::i18n ICU::uc ICU::data", extra=["COMPONENTS", "i18n", "uc", "data"] - ), + LibraryMapping("icu", "ICU", "ICU::i18n ICU::uc ICU::data", components=["i18n", "uc", "data"]), LibraryMapping("journald", "Libsystemd", "PkgConfig::Libsystemd"), LibraryMapping("jpeg", "JPEG", "JPEG::JPEG"), # see also libjpeg LibraryMapping("libatomic", "WrapAtomic", "WrapAtomic::WrapAtomic"), @@ -451,6 +410,7 @@ _library_map = [ LibraryMapping("librt", "WrapRt", "WrapRt::WrapRt"), LibraryMapping("libudev", "Libudev", "PkgConfig::Libudev"), LibraryMapping("lttng-ust", "LTTngUST", "LTTng::UST", resultVariable="LTTNGUST"), + LibraryMapping("libmd4c", "WrapMd4c", "WrapMd4c::WrapMd4c", is_bundled_with_qt=True), LibraryMapping("mtdev", "Mtdev", "PkgConfig::Mtdev"), LibraryMapping("mysql", "MySQL", "MySQL::MySQL"), LibraryMapping("odbc", "ODBC", "ODBC::ODBC"), @@ -489,10 +449,13 @@ _library_map = [ LibraryMapping("sqlite2", None, None), # No more sqlite2 support in Qt6! LibraryMapping("sqlite3", "SQLite3", "SQLite::SQLite3"), LibraryMapping("sqlite", "SQLite3", "SQLite::SQLite3"), + LibraryMapping( + "taglib", "WrapTagLib", "WrapTagLib::WrapTagLib", is_bundled_with_qt=True + ), # used in qtivi LibraryMapping("tslib", "Tslib", "PkgConfig::Tslib"), LibraryMapping("udev", "Libudev", "PkgConfig::Libudev"), LibraryMapping("udev", "Libudev", "PkgConfig::Libudev"), # see also libudev! - LibraryMapping("vulkan", "Vulkan", "Vulkan::Vulkan"), + LibraryMapping("vulkan", "WrapVulkanHeaders", "WrapVulkanHeaders::WrapVulkanHeaders"), LibraryMapping("wayland_server", "Wayland", "Wayland::Server"), # used in qtbase/src/gui LibraryMapping("wayland-server", "Wayland", "Wayland::Server"), # used in qtwayland LibraryMapping("wayland-client", "Wayland", "Wayland::Client"), @@ -511,61 +474,66 @@ _library_map = [ resultVariable="TARGET XCB::XCB", appendFoundSuffix=False, ), + LibraryMapping("xcb_glx", "XCB", "XCB::GLX", components=["GLX"], resultVariable="XCB_GLX"), LibraryMapping( - "xcb_glx", "XCB", "XCB::GLX", extra=["COMPONENTS", "GLX"], resultVariable="XCB_GLX" + "xcb_cursor", + "XCB", + "XCB::CURSOR", + extra=["0.1.1", "COMPONENTS", "CURSOR"], + resultVariable="XCB_CURSOR", ), LibraryMapping( "xcb_icccm", "XCB", "XCB::ICCCM", - extra=["0.3.9", "COMPONENTS", "ICCCM"], + extra=["0.3.9"], + components=["ICCCM"], resultVariable="XCB_ICCCM", ), LibraryMapping( "xcb_image", "XCB", "XCB::IMAGE", - extra=["0.3.9", "COMPONENTS", "IMAGE"], + extra=["0.3.9"], + components=["IMAGE"], resultVariable="XCB_IMAGE", ), LibraryMapping( "xcb_keysyms", "XCB", "XCB::KEYSYMS", - extra=["0.3.9", "COMPONENTS", "KEYSYMS"], + extra=["0.3.9"], + components=["KEYSYMS"], resultVariable="XCB_KEYSYMS", ), LibraryMapping( - "xcb_randr", "XCB", "XCB::RANDR", extra=["COMPONENTS", "RANDR"], resultVariable="XCB_RANDR" + "xcb_randr", "XCB", "XCB::RANDR", components=["RANDR"], resultVariable="XCB_RANDR" ), LibraryMapping( "xcb_render", "XCB", "XCB::RENDER", - extra=["COMPONENTS", "RENDER"], + components=["RENDER"], resultVariable="XCB_RENDER", ), LibraryMapping( "xcb_renderutil", "XCB", "XCB::RENDERUTIL", - extra=["0.3.9", "COMPONENTS", "RENDERUTIL"], + extra=["0.3.9"], + components=["RENDERUTIL"], resultVariable="XCB_RENDERUTIL", ), LibraryMapping( - "xcb_shape", "XCB", "XCB::SHAPE", extra=["COMPONENTS", "SHAPE"], resultVariable="XCB_SHAPE" - ), - LibraryMapping( - "xcb_shm", "XCB", "XCB::SHM", extra=["COMPONENTS", "SHM"], resultVariable="XCB_SHM" - ), - LibraryMapping( - "xcb_sync", "XCB", "XCB::SYNC", extra=["COMPONENTS", "SYNC"], resultVariable="XCB_SYNC" + "xcb_shape", "XCB", "XCB::SHAPE", components=["SHAPE"], resultVariable="XCB_SHAPE" ), + LibraryMapping("xcb_shm", "XCB", "XCB::SHM", components=["SHM"], resultVariable="XCB_SHM"), + LibraryMapping("xcb_sync", "XCB", "XCB::SYNC", components=["SYNC"], resultVariable="XCB_SYNC"), LibraryMapping( "xcb_xfixes", "XCB", "XCB::XFIXES", - extra=["COMPONENTS", "XFIXES"], + components=["XFIXES"], resultVariable="TARGET XCB::XFIXES", appendFoundSuffix=False, ), @@ -573,7 +541,7 @@ _library_map = [ "xcb-xfixes", "XCB", "XCB::XFIXES", - extra=["COMPONENTS", "XFIXES"], + components=["XFIXES"], resultVariable="TARGET XCB::XFIXES", appendFoundSuffix=False, ), @@ -581,12 +549,11 @@ _library_map = [ "xcb_xinput", "XCB", "XCB::XINPUT", - extra=["1.12", "COMPONENTS", "XINPUT"], + extra=["1.12"], + components=["XINPUT"], resultVariable="XCB_XINPUT", ), - LibraryMapping( - "xcb_xkb", "XCB", "XCB::XKB", extra=["COMPONENTS", "XKB"], resultVariable="XCB_XKB" - ), + LibraryMapping("xcb_xkb", "XCB", "XCB::XKB", components=["XKB"], resultVariable="XCB_XKB"), LibraryMapping("xcb_xlib", "X11_XCB", "X11::XCB"), LibraryMapping("xcomposite", "XComposite", "PkgConfig::XComposite"), LibraryMapping("xkbcommon_evdev", "XKB", "XKB::XKB", extra=["0.5.0"]), # see also xkbcommon @@ -594,8 +561,8 @@ _library_map = [ LibraryMapping("xkbcommon", "XKB", "XKB::XKB", extra=["0.5.0"]), LibraryMapping("xlib", "X11", "X11::X11"), LibraryMapping("xrender", "XRender", "PkgConfig::XRender", extra=["0.6"]), - LibraryMapping("zlib", "ZLIB", "ZLIB::ZLIB", extra=["1.0.8"]), - LibraryMapping("zstd", "ZSTD", "ZSTD::ZSTD", extra=["1.3"]), + LibraryMapping("zlib", "WrapZLIB", "WrapZLIB::WrapZLIB", extra=["1.0.8"]), + LibraryMapping("zstd", "WrapZSTD", "WrapZSTD::WrapZSTD", extra=["1.3"]), LibraryMapping("tiff", "TIFF", "TIFF::TIFF"), LibraryMapping("webp", "WrapWebP", "WrapWebP::WrapWebP"), LibraryMapping("jasper", "WrapJasper", "WrapJasper::WrapJasper"), @@ -624,14 +591,18 @@ _library_map = [ def _adjust_library_map(): - # Assign a Linux condition on all x and wayland related packages. + # Assign a Linux condition on all wayland related packages. + # Assign platforms that have X11 condition on all X11 related packages. # We don't want to get pages of package not found messages on # Windows and macOS, and this also improves configure time on # those platforms. - linux_package_prefixes = ["xcb", "x11", "xkb", "xrender", "xlib", "wayland"] + linux_package_prefixes = ["wayland"] + x11_package_prefixes = ["xcb", "x11", "xkb", "xrender", "xlib"] for i, _ in enumerate(_library_map): if any([_library_map[i].soName.startswith(p) for p in linux_package_prefixes]): _library_map[i].emit_if = "config.linux" + if any([_library_map[i].soName.startswith(p) for p in x11_package_prefixes]): + _library_map[i].emit_if = "X11_SUPPORTED" _adjust_library_map() @@ -669,7 +640,7 @@ def find_library_info_for_target(targetName: str) -> typing.Optional[LibraryMapp # For a given qmake library (e.g. 'openssl_headers'), check whether this is a fake library used # for the /nolink annotation, and return the actual annotated qmake library ('openssl/nolink'). -def find_annotated_qmake_lib_name(lib : str) -> str: +def find_annotated_qmake_lib_name(lib: str) -> str: for entry in _library_map: if entry.no_link_so_name == lib: return entry.soName + "/nolink" @@ -708,9 +679,7 @@ platform_mapping = { "qnx": "QNX", "vxworks": "VXWORKS", "hpux": "HPUX", - "nacl": "NACL", "android": "ANDROID", - "android-embedded": "ANDROID_EMBEDDED", "uikit": "UIKIT", "tvos": "TVOS", "watchos": "WATCHOS", @@ -737,7 +706,7 @@ platform_mapping = { def map_platform(platform: str) -> str: - """ Return the qmake platform as cmake platform or the unchanged string. """ + """Return the qmake platform as cmake platform or the unchanged string.""" return platform_mapping.get(platform, platform) @@ -799,15 +768,21 @@ def generate_find_package_info( indent: int = 0, emit_if: str = "", use_system_package_name: bool = False, + remove_REQUIRED_from_extra: bool = True, + components_required: bool = True, module: str = "", ) -> str: isRequired = False extra = lib.extra.copy() + if lib.components: + extra.append("COMPONENTS" if components_required else "OPTIONAL_COMPONENTS") + extra += lib.components if "REQUIRED" in extra and use_qt_find_package: isRequired = True - extra.remove("REQUIRED") + if remove_REQUIRED_from_extra: + extra.remove("REQUIRED") cmake_target_name = lib.targetName assert cmake_target_name @@ -879,6 +854,15 @@ def _set_up_py_parsing_nicer_debug_output(pp): return wrapper_function - pp._defaultStartDebugAction = increase_indent(pp._defaultStartDebugAction) - pp._defaultSuccessDebugAction = decrease_indent(pp._defaultSuccessDebugAction) - pp._defaultExceptionDebugAction = decrease_indent(pp._defaultExceptionDebugAction) + if hasattr(pp, "_defaultStartDebugAction"): + pp._defaultStartDebugAction = increase_indent(pp._defaultStartDebugAction) + pp._defaultSuccessDebugAction = decrease_indent(pp._defaultSuccessDebugAction) + pp._defaultExceptionDebugAction = decrease_indent(pp._defaultExceptionDebugAction) + elif hasattr(pp.core, "_default_start_debug_action"): + pp.core._default_start_debug_action = increase_indent(pp.core._default_start_debug_action) + pp.core._default_success_debug_action = decrease_indent( + pp.core._default_success_debug_action + ) + pp.core._default_exception_debug_action = decrease_indent( + pp.core._default_exception_debug_action + ) diff --git a/util/cmake/json_parser.py b/util/cmake/json_parser.py index a0aaecab9d..f8e0fa6017 100644 --- a/util/cmake/json_parser.py +++ b/util/cmake/json_parser.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2019 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2019 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import pyparsing as pp # type: ignore import json diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py index 601947285b..0ef35410ce 100755 --- a/util/cmake/pro2cmake.py +++ b/util/cmake/pro2cmake.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 # Requires Python 3.7. The import statement needs to be the first line of code @@ -39,6 +14,7 @@ import posixpath import sys import re import io +import itertools import glob import fnmatch @@ -81,9 +57,8 @@ from helper import ( LibraryMapping, ) - cmake_version_string = "3.16" -cmake_api_version = 2 +cmake_api_version = 3 def _parse_commandline(): @@ -135,7 +110,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", @@ -179,7 +160,7 @@ def _parse_commandline(): "--api-version", dest="api_version", type=int, - help="Specify which cmake api version should be generated. 1 or 2, 2 is latest.", + help="Specify which cmake api version should be generated. 1, 2 or 3, 3 is latest.", ) parser.add_argument( @@ -202,102 +183,128 @@ def _parse_commandline(): def get_top_level_repo_project_path(project_file_path: str = "") -> str: - qmake_conf_path = find_qmake_conf(project_file_path) - qmake_conf_dir_path = os.path.dirname(qmake_conf_path) - return qmake_conf_dir_path + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) + return qmake_or_cmake_conf_dir_path def is_top_level_repo_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) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) project_dir_path = os.path.dirname(project_file_path) - return qmake_conf_dir_path == project_dir_path + return qmake_or_cmake_conf_dir_path == project_dir_path def is_top_level_repo_tests_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) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) project_dir_path = os.path.dirname(project_file_path) project_dir_name = os.path.basename(project_dir_path) maybe_same_level_dir_path = os.path.join(project_dir_path, "..") normalized_maybe_same_level_dir_path = os.path.normpath(maybe_same_level_dir_path) return ( - qmake_conf_dir_path == normalized_maybe_same_level_dir_path and project_dir_name == "tests" + qmake_or_cmake_conf_dir_path == normalized_maybe_same_level_dir_path + and project_dir_name == "tests" ) def is_top_level_repo_examples_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) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) project_dir_path = os.path.dirname(project_file_path) project_dir_name = os.path.basename(project_dir_path) maybe_same_level_dir_path = os.path.join(project_dir_path, "..") normalized_maybe_same_level_dir_path = os.path.normpath(maybe_same_level_dir_path) return ( - qmake_conf_dir_path == normalized_maybe_same_level_dir_path + qmake_or_cmake_conf_dir_path == normalized_maybe_same_level_dir_path and project_dir_name == "examples" ) def is_example_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) + # If there's a .qmake.conf or .cmake.conf file in the parent + # directories of the given project path, it is likely that the + # project is an internal Qt project that uses private Qt CMake + # API. + found_qt_repo_version = False + qmake_conf = find_qmake_conf(project_file_path) + if qmake_conf: + repo_version = parse_qt_repo_module_version_from_qmake_conf(qmake_conf) + if repo_version: + found_qt_repo_version = True + + cmake_conf = find_cmake_conf(project_file_path) + if cmake_conf: + repo_version = parse_qt_repo_module_version_from_cmake_conf(cmake_conf) + if repo_version: + found_qt_repo_version = True + + # If we haven't found a conf file, we assume this is an example + # project and not a project under a qt source repository. + if not found_qt_repo_version: + return True - project_relative_path = os.path.relpath(project_file_path, qmake_conf_dir_path) # If the project file is found in a subdir called 'examples' # relative to the repo source dir, then it must be an example, but # some examples contain 3rdparty libraries that do not need to be # built as examples. - return project_relative_path.startswith("examples") and "3rdparty" not in project_relative_path + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) + project_relative_path = os.path.relpath(project_file_path, qmake_or_cmake_conf_dir_path) + + is_example_under_repo_sources = ( + project_relative_path.startswith("examples") and "3rdparty" not in project_relative_path + ) + return is_example_under_repo_sources 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) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) + dir_name_with_qmake_or_cmake_conf = os.path.basename(qmake_or_cmake_conf_dir_path) - project_relative_path = os.path.relpath(project_file_path, qmake_conf_dir_path) + project_relative_path = os.path.relpath(project_file_path, qmake_or_cmake_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" + or dir_name_with_qmake_or_cmake_conf == "config.tests" ) def is_benchmark_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) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) - project_relative_path = os.path.relpath(project_file_path, qmake_conf_dir_path) + project_relative_path = os.path.relpath(project_file_path, qmake_or_cmake_conf_dir_path) # If the project file is found in a subdir called 'tests/benchmarks' # relative to the repo source dir, then it must be a benchmark return project_relative_path.startswith("tests/benchmarks") def is_manual_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) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) - project_relative_path = os.path.relpath(project_file_path, qmake_conf_dir_path) + project_relative_path = os.path.relpath(project_file_path, qmake_or_cmake_conf_dir_path) # If the project file is found in a subdir called 'tests/manual' # relative to the repo source dir, then it must be a manual test return project_relative_path.startswith("tests/manual") @lru_cache(maxsize=None) -def find_qmake_conf(project_file_path: str = "") -> str: +def find_file_walking_parent_dirs(file_name: str, project_file_path: str = "") -> str: + assert file_name if not os.path.isabs(project_file_path): print( - f"Warning: could not find .qmake.conf file, given path is not an " + f"Warning: could not find {file_name} file, given path is not an " f"absolute path: {project_file_path}" ) return "" cwd = os.path.dirname(project_file_path) - file_name = ".qmake.conf" while os.path.isdir(cwd): maybe_file = posixpath.join(cwd, file_name) @@ -310,10 +317,39 @@ def find_qmake_conf(project_file_path: str = "") -> str: # reached the top level directory, stop looking break - print(f"Warning: could not find .qmake.conf file") return "" +def find_qmake_conf(project_file_path: str = "") -> str: + return find_file_walking_parent_dirs(".qmake.conf", project_file_path) + + +def find_cmake_conf(project_file_path: str = "") -> str: + return find_file_walking_parent_dirs(".cmake.conf", project_file_path) + + +def find_qmake_or_cmake_conf(project_file_path: str = "") -> str: + qmake_conf = find_qmake_conf(project_file_path) + if qmake_conf: + return qmake_conf + cmake_conf = find_cmake_conf(project_file_path) + return cmake_conf + + +def parse_qt_repo_module_version_from_qmake_conf(qmake_conf_path: str = "") -> str: + with open(qmake_conf_path) as f: + file_contents = f.read() + m = re.search(r"MODULE_VERSION\s*=\s*([0-9.]+)", file_contents) + return m.group(1) if m else "" + + +def parse_qt_repo_module_version_from_cmake_conf(cmake_conf_path: str = "") -> str: + with open(cmake_conf_path) as f: + file_contents = f.read() + m = re.search(r'set\(QT_REPO_MODULE_VERSION\s*"([0-9.]+)"\)', file_contents) + return m.group(1) if m else "" + + def set_up_cmake_api_calls(): def nested_dict(): return defaultdict(nested_dict) @@ -423,25 +459,40 @@ def get_cmake_api_call(api_name: str, api_version: Optional[int] = None) -> str: return cmake_api_calls[api_version][api_name] -def process_qrc_file( - target: str, - scope: Scope, +class QtResource: + def __init__( + self, + name: str = "", + prefix: str = "", + base_dir: str = "", + files: Dict[str, str] = {}, + lang: str = None, + generated: bool = False, + skip_qtquick_compiler: bool = False, + ) -> None: + self.name = name + self.prefix = prefix + self.base_dir = base_dir + self.files = files + self.lang = lang + self.generated = generated + self.skip_qtquick_compiler = skip_qtquick_compiler + + +def read_qrc_file( filepath: str, base_dir: str = "", project_file_path: str = "", skip_qtquick_compiler: bool = False, - is_example: bool = False, -) -> str: - assert target - +) -> List[QtResource]: # Hack to handle QT_SOURCE_TREE. Assume currently that it's the same # as the qtbase source path. qt_source_tree_literal = "${QT_SOURCE_TREE}" if qt_source_tree_literal in filepath: - qmake_conf = find_qmake_conf(project_file_path) + qmake_or_cmake_conf = find_qmake_or_cmake_conf(project_file_path) - if qmake_conf: - qt_source_tree = os.path.dirname(qmake_conf) + if qmake_or_cmake_conf: + qt_source_tree = os.path.dirname(qmake_or_cmake_conf) filepath = filepath.replace(qt_source_tree_literal, qt_source_tree) else: print( @@ -455,7 +506,6 @@ def process_qrc_file( # Small not very thorough check to see if this a shared qrc resource # pattern is mostly used by the tests. - is_parent_path = dir_name.startswith("..") if not os.path.isfile(filepath): raise RuntimeError(f"Invalid file path given to process_qrc_file: {filepath}") @@ -463,81 +513,50 @@ def process_qrc_file( root = tree.getroot() assert root.tag == "RCC" - output = "" - - resource_count = 0 + result: List[QtResource] = [] for resource in root: assert resource.tag == "qresource" - lang = resource.get("lang", "") - prefix = resource.get("prefix", "/") - if not prefix.startswith("/"): - prefix = f"/{prefix}" + r = QtResource( + name=resource_name, + prefix=resource.get("prefix", "/"), + base_dir=base_dir, + lang=resource.get("lang", ""), + skip_qtquick_compiler=skip_qtquick_compiler, + ) + + if len(result) > 0: + r.name += str(len(result)) - full_resource_name = resource_name + (str(resource_count) if resource_count > 0 else "") + if not r.prefix.startswith("/"): + r.prefix = f"/{r.prefix}" - files: Dict[str, str] = {} for file in resource: path = file.text assert path # Get alias: alias = file.get("alias", "") - # In cases where examples use shared resources, we set the alias - # too the same name of the file, or the applications won't be - # be able to locate the resource - if not alias and is_parent_path: - alias = path - files[path] = alias - - output += write_add_qt_resource_call( - target, - scope, - full_resource_name, - prefix, - base_dir, - lang, - files, - skip_qtquick_compiler, - is_example, - ) - resource_count += 1 + r.files[path] = alias - return output + result.append(r) + return result -def write_add_qt_resource_call( - target: str, - scope: Scope, - resource_name: str, - prefix: Optional[str], - base_dir: str, - lang: Optional[str], - files: Dict[str, str], - skip_qtquick_compiler: bool, - is_example: bool, + +def write_resource_source_file_properties( + sorted_files: List[str], files: Dict[str, str], base_dir: str, skip_qtquick_compiler: bool ) -> str: output = "" - - sorted_files = sorted(files.keys()) - - assert sorted_files - - if base_dir: - base_dir_expanded = scope.expandString(base_dir) - if base_dir_expanded: - base_dir = base_dir_expanded - source_file_properties = defaultdict(list) for source in sorted_files: - full_source = posixpath.join(base_dir, source) alias = files[source] if alias: - source_file_properties[full_source].append(f'QT_RESOURCE_ALIAS "{alias}"') + source_file_properties[source].append(f'QT_RESOURCE_ALIAS "{alias}"') # If a base dir is given, we have to write the source file property # assignments that disable the quick compiler per file. if base_dir and skip_qtquick_compiler: - source_file_properties[full_source].append("QT_SKIP_QUICKCOMPILER 1") + source_file_properties[source].append("QT_SKIP_QUICKCOMPILER 1") for full_source in source_file_properties: per_file_props = source_file_properties[full_source] @@ -552,6 +571,39 @@ def write_add_qt_resource_call( """ ) + return output + + +def write_add_qt_resource_call( + target: str, + scope: Scope, + resource_name: str, + prefix: Optional[str], + base_dir: str, + lang: Optional[str], + files: Dict[str, str], + skip_qtquick_compiler: bool, + is_example: bool, +) -> str: + output = "" + + if base_dir: + base_dir_expanded = scope.expandString(base_dir) + if base_dir_expanded: + base_dir = base_dir_expanded + new_files = {} + for file_path, alias in files.items(): + full_file_path = posixpath.join(base_dir, file_path) + new_files[full_file_path] = alias + files = new_files + + sorted_files = sorted(files.keys()) + assert sorted_files + + output += write_resource_source_file_properties( + sorted_files, files, base_dir, skip_qtquick_compiler + ) + # Quote file paths in case there are spaces. sorted_files_backup = sorted_files sorted_files = [] @@ -1349,9 +1401,9 @@ class Scope(object): relative_path = posixpath.relpath(self.currentdir, self.basedir) if key == "QQC2_SOURCE_TREE": - qmake_conf_path = find_qmake_conf(os.path.abspath(self.currentdir)) - qmake_conf_dir_path = os.path.dirname(qmake_conf_path) - project_relative_path = os.path.relpath(qmake_conf_dir_path, self.currentdir) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(os.path.abspath(self.currentdir)) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) + project_relative_path = os.path.relpath(qmake_or_cmake_conf_dir_path, self.currentdir) return ["${CMAKE_CURRENT_SOURCE_DIR}/" + project_relative_path] if key == "QT_ARCH": @@ -1597,6 +1649,28 @@ def map_condition(condition: str) -> str: pattern = r"(equals|greaterThan|lessThan)\(WINDOWS_SDK_VERSION,[ ]*([0-9]+)\)" condition = re.sub(pattern, windows_sdk_version_handler, condition) + def qt_version_handler(match_obj: Match): + operator = match_obj.group(1) + if operator == "equals": + operator = "EQUAL" + elif operator == "greaterThan": + operator = "GREATER" + elif operator == "lessThan": + operator = "LESS" + + operator_prefix = "VERSION_" + version_variable = "QT_VERSION" + version_flavor = match_obj.group(2) + if version_flavor: + version_variable += "_" + version_flavor[:-1] + operator_prefix = "" + + version = match_obj.group(3) + return f"({version_variable} {operator_prefix}{operator} {version})" + + pattern = r"(equals|greaterThan|lessThan)\(QT_(MAJOR_|MINOR_|PATCH_)?VERSION,[ ]*([0-9.]+)\)" + condition = re.sub(pattern, qt_version_handler, condition) + # Generic lessThan|equals|lessThan() def generic_version_handler(match_obj: Match): @@ -1720,7 +1794,7 @@ _path_replacements = { def replace_path_constants(path: str, scope: Scope) -> str: - """ Clean up DESTDIR and target.path """ + """Clean up DESTDIR and target.path""" if path.startswith("./"): path = f"${{CMAKE_CURRENT_BINARY_DIR}}/{path[2:]}" elif path.startswith("../"): @@ -1732,7 +1806,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. @@ -1797,7 +1876,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.") @@ -2399,48 +2484,44 @@ def expand_resource_glob(cm_fh: IO[str], expression: str) -> str: return expanded_var -def write_resources( - cm_fh: IO[str], +def extract_resources( target: str, scope: Scope, - indent: int = 0, - is_example=False, - target_ref: str = None, -): - if target_ref is None: - target_ref = target - # vpath = scope.expand('VPATH') +) -> Tuple[List[QtResource], List[str]]: + """Read the resources of the given scope. + Return a tuple: + - list of QtResource objects + - list of standalone sources files that are marked as QTQUICK_COMPILER_SKIPPED_RESOURCES""" + + resource_infos: List[QtResource] = [] + skipped_standalone_files: List[str] = [] - # Handle QRC files by turning them into qt_add_resource: resources = scope.get_files("RESOURCES") qtquickcompiler_skipped = scope.get_files("QTQUICK_COMPILER_SKIPPED_RESOURCES") - qrc_output = "" if resources: standalone_files: List[str] = [] for r in resources: skip_qtquick_compiler = r in qtquickcompiler_skipped if r.endswith(".qrc"): if "${CMAKE_CURRENT_BINARY_DIR}" in r: - cm_fh.write(f"#### Ignored generated resource: {r}") + resource_infos.append( + QtResource( + name=r, generated=True, skip_qtquick_compiler=skip_qtquick_compiler + ) + ) continue - qrc_output += process_qrc_file( - target_ref, - scope, + resource_infos += read_qrc_file( r, scope.basedir, scope.file_absolute_path, - skip_qtquick_compiler, - is_example, + skip_qtquick_compiler=skip_qtquick_compiler, ) else: immediate_files = {f: "" for f in scope.get_files(f"{r}.files")} if immediate_files: immediate_files_filtered = [] for f in immediate_files: - if "*" in f: - immediate_files_filtered.append(expand_resource_glob(cm_fh, f)) - else: - immediate_files_filtered.append(f) + immediate_files_filtered.append(f) immediate_files = {f: "" for f in immediate_files_filtered} scope_prefix = scope.get(f"{r}.prefix") if scope_prefix: @@ -2450,50 +2531,74 @@ def write_resources( immediate_base_list = scope.get(f"{r}.base") assert ( len(immediate_base_list) < 2 - ), f"immediate base directory must be at most one entry" + ), "immediate base directory must be at most one entry" immediate_base = replace_path_constants("".join(immediate_base_list), scope) immediate_lang = None immediate_name = f"qmake_{r}" - qrc_output += write_add_qt_resource_call( - target=target_ref, - scope=scope, - resource_name=immediate_name, - prefix=immediate_prefix, - base_dir=immediate_base, - lang=immediate_lang, - files=immediate_files, - skip_qtquick_compiler=skip_qtquick_compiler, - is_example=is_example, + resource_infos.append( + QtResource( + name=immediate_name, + prefix=immediate_prefix, + base_dir=immediate_base, + lang=immediate_lang, + files=immediate_files, + skip_qtquick_compiler=skip_qtquick_compiler, + ) ) else: - if "*" in r: - standalone_files.append(expand_resource_glob(cm_fh, r)) - else: - # stadalone source file properties need to be set as they - # are parsed. - if skip_qtquick_compiler: - qrc_output += ( - f'set_source_files_properties("{r}" PROPERTIES ' - f"QT_SKIP_QUICKCOMPILER 1)\n\n" - ) - standalone_files.append(r) + standalone_files.append(r) + if not ("*" in r) and skip_qtquick_compiler: + skipped_standalone_files.append(r) if standalone_files: - name = "qmake_immediate" - prefix = "/" - base = "" - lang = None - files = {f: "" for f in standalone_files} - qrc_output += write_add_qt_resource_call( - target=target_ref, - scope=scope, - resource_name=name, - prefix=prefix, - base_dir=base, - lang=lang, - files=files, - skip_qtquick_compiler=False, - is_example=is_example, + resource_infos.append( + QtResource( + name="qmake_immediate", + prefix="/", + base_dir="", + files={f: "" for f in standalone_files}, + ) + ) + + return (resource_infos, skipped_standalone_files) + + +def write_resources( + cm_fh: IO[str], + target: str, + scope: Scope, + indent: int = 0, + is_example=False, + target_ref: str = None, + resources: List[QtResource] = None, + skipped_standalone_files: List[str] = None, +): + if resources is None: + (resources, skipped_standalone_files) = extract_resources(target, scope) + if target_ref is None: + target_ref = target + + qrc_output = "" + for r in resources: + name = r.name + if "*" in name: + name = expand_resource_glob(cm_fh, name) + qrc_output += write_add_qt_resource_call( + target=target_ref, + scope=scope, + resource_name=name, + prefix=r.prefix, + base_dir=r.base_dir, + lang=r.lang, + files=r.files, + skip_qtquick_compiler=r.skip_qtquick_compiler, + is_example=is_example, + ) + + if skipped_standalone_files: + for f in skipped_standalone_files: + qrc_output += ( + f'set_source_files_properties("{f}" PROPERTIES ' f"QT_SKIP_QUICKCOMPILER 1)\n\n" ) if qrc_output: @@ -2527,7 +2632,7 @@ def write_qlalrsources(cm_fh: IO[str], target: str, scope: Scope, indent: int = if not sources: return cm_fh.write("\n# QLALR Grammars:\n") - cm_fh.write(f"qt_process_qlalr(\n") + cm_fh.write("qt_process_qlalr(\n") indent += 1 cm_fh.write(f"{spaces(indent)}{target}\n") cm_fh.write(f"{spaces(indent)}{';'.join(sources)}\n") @@ -2598,7 +2703,7 @@ def write_target_sources( ): command_name = "target_sources" header = f"{command_name}({target} {visibility}\n" - write_list(cm_fh, sources, "", indent, footer=f")", header=header) + write_list(cm_fh, sources, "", indent, footer=")", header=header) def expand_project_requirements(scope: Scope, skip_message: bool = False) -> str: @@ -3193,6 +3298,14 @@ def write_main_part( # collect all testdata and insert globbing commands has_test_data = False if typename == "Test": + cm_fh.write(f"{spaces(indent)}if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)\n") + cm_fh.write(f"{spaces(indent+1)}cmake_minimum_required(VERSION 3.16)\n") + cm_fh.write(f"{spaces(indent+1)}project({name} LANGUAGES C CXX ASM)\n") + cm_fh.write( + f"{spaces(indent+1)}find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)\n" + ) + cm_fh.write(f"{spaces(indent)}endif()\n\n") + test_data = scope.expand("TESTDATA") if test_data: has_test_data = True @@ -3241,6 +3354,9 @@ def write_main_part( # Footer: cm_fh.write(f"{spaces(indent)})\n") + if typename == "Tool": + cm_fh.write(f"{spaces(indent)}qt_internal_return_unless_building_tools()\n") + write_resources(cm_fh, name, scope, indent, target_ref=target_ref) write_statecharts(cm_fh, name, scope, indent) @@ -3441,6 +3557,7 @@ def write_module(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str: extra.append("STATIC") if "internal_module" in scope.get("CONFIG"): is_public_module = False + cmake_target_name += "Private" # Assume all internal modules have the 'Private' suffix extra.append("INTERNAL_MODULE") if "no_module_headers" in scope.get("CONFIG"): extra.append("NO_MODULE_HEADERS") @@ -3452,8 +3569,8 @@ def write_module(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str: scope._has_private_module = True if "header_module" in scope.get("CONFIG"): extra.append("HEADER_MODULE") - if "metatypes" in scope.get("CONFIG") or "qmltypes" in scope.get("CONFIG"): - extra.append("GENERATE_METATYPES") + if not("metatypes" in scope.get("CONFIG") or "qmltypes" in scope.get("CONFIG")): + extra.append("NO_GENERATE_METATYPES") module_config = scope.get("MODULE_CONFIG") if len(module_config): @@ -3627,7 +3744,14 @@ def write_binary(cm_fh: IO[str], scope: Scope, gui: bool = False, *, indent: int def write_find_package_section( - cm_fh: IO[str], public_libs: List[str], private_libs: List[str], *, indent: int = 0 + cm_fh: IO[str], + public_libs: List[str], + private_libs: List[str], + *, + indent: int = 0, + is_required: bool = True, + end_with_extra_newline: bool = True, + qt_package_name: str = "Qt6", ): packages = [] # type: List[LibraryMapping] all_libs = public_libs + private_libs @@ -3637,12 +3761,31 @@ def write_find_package_section( if info and info not in packages: packages.append(info) - # ind = spaces(indent) + qt_components: List[str] = [] + for p in filter(LibraryMapping.is_qt, packages): + if p.components is not None: + qt_components += p.components + if qt_components: + if "Core" in qt_components: + qt_components.remove("Core") + qt_components = sorted(qt_components) + qt_package = LibraryMapping("unknown", qt_package_name, "unknown", components=qt_components) + if is_required: + qt_package.extra = ["REQUIRED"] + cm_fh.write( + generate_find_package_info( + qt_package, + use_qt_find_package=False, + remove_REQUIRED_from_extra=False, + components_required=is_required, + indent=indent, + ) + ) - for p in packages: + for p in itertools.filterfalse(LibraryMapping.is_qt, packages): cm_fh.write(generate_find_package_info(p, use_qt_find_package=False, indent=indent)) - if packages: + if packages and end_with_extra_newline: cm_fh.write("\n") @@ -3664,7 +3807,7 @@ def write_jar(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str: android_sdk_jar = "${android_sdk}" write_source_file_list( - cm_fh, scope, "", ["JAVASOURCES"], indent=indent, header=f"set(java_sources\n", footer=")\n" + cm_fh, scope, "", ["JAVASOURCES"], indent=indent, header="set(java_sources\n", footer=")\n" ) cm_fh.write(f"{spaces(indent)}qt_internal_add_jar({target}\n") @@ -3681,13 +3824,19 @@ def write_jar(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str: return target -def write_win32_and_mac_bundle_properties( - cm_fh: IO[str], scope: Scope, target: str, *, handling_first_scope=False, indent: int = 0 -): +def get_win32_and_mac_bundle_properties(scope: Scope) -> tuple: config = scope.get("CONFIG") win32 = all(val not in config for val in ["cmdline", "console"]) mac_bundle = all(val not in config for val in ["cmdline", "-app_bundle"]) + return win32, mac_bundle + + +def write_win32_and_mac_bundle_properties( + cm_fh: IO[str], scope: Scope, target: str, *, handling_first_scope=False, indent: int = 0 +): + win32, mac_bundle = get_win32_and_mac_bundle_properties(scope) + true_value = "TRUE" false_value = "FALSE" @@ -3705,38 +3854,71 @@ def write_win32_and_mac_bundle_properties( # without creating excess noise of setting the properties in every # single scope. for name, value in properties_mapping.items(): - if handling_first_scope or (not handling_first_scope and value != true_value): + if not handling_first_scope and value != true_value: properties.extend([name, value]) if properties: write_set_target_properties(cm_fh, [target], properties, indent=indent) +def is_qtquick_source_file(filename: str): + return filename.endswith(".qml") or filename.endswith(".js") or filename.endswith(".mjs") + + +def looks_like_qml_resource(resource: QtResource): + if resource.generated or "*" in resource.name: + return False + for f in resource.files: + if is_qtquick_source_file(f): + return True + return False + + +def find_qml_resource(resources: List[QtResource]): + """Return the resource object that's most likely the one that should be used for + qt_add_qml_module. Return None if there's no such resource.""" + return next(filter(looks_like_qml_resource, resources), None) + + 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 + + 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}" + ) - 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( - "cmake_minimum_required(VERSION 3.14)\n" - f"project({binary_name} LANGUAGES CXX)\n\n" + f"cmake_minimum_required(VERSION {cmake_version_string})\n" + f"project({binary_name} VERSION {project_version} 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" - "if(NOT DEFINED INSTALL_EXAMPLESDIR)\n" - ' set(INSTALL_EXAMPLESDIR "examples")\n' - "endif()\n\n" - f'set(INSTALL_EXAMPLEDIR "{example_install_dir}")\n\n' ) + if scope.get_files("FORMS"): + cm_fh.write("set(CMAKE_AUTOUIC ON)\n") + cm_fh.write("\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) @@ -3750,110 +3932,86 @@ def write_example( handle_source_subtractions(scopes) scopes = merge_scopes(scopes) + # Write find_package call for Qt5/Qt6 and make it available as package QT. + cm_fh.write("find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core)\n") + + # Write find_package calls for required packages. + # We consider packages as required if they appear at the top-level scope. (public_libs, private_libs) = extract_cmake_libraries(scope, is_example=True) - write_find_package_section(cm_fh, public_libs, private_libs, indent=indent) + write_find_package_section( + cm_fh, + public_libs, + private_libs, + indent=indent, + end_with_extra_newline=False, + qt_package_name="Qt${QT_VERSION_MAJOR}", + ) - add_target = "" + # Write find_package calls for optional packages. + # We consider packages inside scopes other than the top-level one as optional. + optional_public_libs: List[str] = [] + optional_private_libs: List[str] = [] + handling_first_scope = True + for inner_scope in scopes: + if handling_first_scope: + handling_first_scope = False + continue + (public_libs, private_libs) = extract_cmake_libraries(inner_scope, is_example=True) + optional_public_libs += public_libs + optional_private_libs += private_libs + write_find_package_section( + cm_fh, + optional_public_libs, + optional_private_libs, + indent=indent, + is_required=False, + end_with_extra_newline=False, + qt_package_name="Qt${QT_VERSION_MAJOR}", + ) - if is_plugin: - if "qml" in scope.get("QT"): - # Get the uri from the destination directory - dest_dir = scope.expandString("DESTDIR") - if not dest_dir: - dest_dir = "${CMAKE_CURRENT_BINARY_DIR}" - else: - uri = os.path.basename(dest_dir) - dest_dir = f"${{CMAKE_CURRENT_BINARY_DIR}}/{dest_dir}" - - add_target = "" - - qml_dir = None - qml_dir_dynamic_imports = False - - qmldir_file_path_list = scope.get_files("qmldir.files") - assert len(qmldir_file_path_list) < 2, "File path must only contain one path" - qmldir_file_path = qmldir_file_path_list[0] if qmldir_file_path_list else "qmldir" - qmldir_file_path = os.path.join(os.getcwd(), qmldir_file_path[0]) - - dynamic_qmldir = scope.get("DYNAMIC_QMLDIR") - if os.path.exists(qmldir_file_path): - qml_dir = QmlDir() - qml_dir.from_file(qmldir_file_path) - elif dynamic_qmldir: - qml_dir = QmlDir() - qml_dir.from_lines(dynamic_qmldir) - qml_dir_dynamic_imports = True - - add_target += "set(module_dynamic_qml_imports\n " - if len(qml_dir.imports) != 0: - add_target += "\n ".join(qml_dir.imports) - add_target += "\n)\n\n" - - for sc in scopes[1:]: - import_list = [] - qml_imports = sc.get("DYNAMIC_QMLDIR") - for qml_import in qml_imports: - if not qml_import.startswith("import "): - raise RuntimeError( - "Only qmldir import statements expected in conditional scope!" - ) - import_list.append(qml_import[len("import ") :].replace(" ", "/")) - if len(import_list) == 0: - continue + cm_fh.write("\n") - assert sc.condition + (resources, standalone_qtquick_compiler_skipped_files) = extract_resources(binary_name, scope) + qml_resource = find_qml_resource(resources) if is_qml_plugin else None - add_target += f"if ({sc.condition})\n" - add_target += f" list(APPEND module_dynamic_qml_imports\n " - add_target += "\n ".join(import_list) - add_target += f"\n )\nendif()\n\n" + add_target = "" - add_target += dedent( - f"""\ - qt6_add_qml_module({binary_name} - OUTPUT_DIRECTORY "{dest_dir}" - VERSION 1.0 - URI "{uri}" - """ + if is_plugin: + if is_qml_plugin: + extra_args = [f"PLUGIN_TARGET {binary_name}"] + io_string = io.StringIO() + write_qml_module( + io_string, + binary_name, + scope, + scopes, + indent=indent, + resource=qml_resource, + extra_add_qml_module_args=extra_args, ) - - if qml_dir is not None: - if qml_dir.designer_supported: - add_target += " DESIGNER_SUPPORTED\n" - if len(qml_dir.classname) != 0: - add_target += f" CLASSNAME {qml_dir.classname}\n" - if len(qml_dir.depends) != 0: - add_target += " DEPENDENCIES\n" - for dep in qml_dir.depends: - add_target += f" {dep[0]}/{dep[1]}\n" - if len(qml_dir.type_names) == 0: - add_target += " SKIP_TYPE_REGISTRATION\n" - if len(qml_dir.imports) != 0 and not qml_dir_dynamic_imports: - qml_dir_imports_line = " \n".join(qml_dir.imports) - add_target += f" IMPORTS\n{qml_dir_imports_line}" - if qml_dir_dynamic_imports: - add_target += " IMPORTS ${module_dynamic_qml_imports}\n" - if len(qml_dir.optional_imports) != 0: - qml_dir_optional_imports_line = " \n".join(qml_dir.optional_imports) - add_target += f" OPTIONAL_IMPORTS\n{qml_dir_optional_imports_line}" - if qml_dir.plugin_optional: - add_target += " PLUGIN_OPTIONAL\n" - - add_target += " INSTALL_LOCATION ${INSTALL_EXAMPLEDIR}\n)\n\n" - add_target += f"target_sources({binary_name} PRIVATE" + add_target += io_string.getvalue() else: add_target = f"qt_add_plugin({binary_name}" if "static" in scope.get("CONFIG"): add_target += " STATIC" add_target += ")\n" - add_target += f"target_sources({binary_name} PRIVATE" - + add_target += f"target_sources({binary_name} PRIVATE" else: add_target = f"qt_add_executable({binary_name}" + property_win32, property_mac_bundle = get_win32_and_mac_bundle_properties(scope) + + if property_win32: + add_target += " " + "WIN32" + if property_mac_bundle: + add_target += " " + "MACOSX_BUNDLE" + write_all_source_file_lists(cm_fh, scope, add_target, indent=0) cm_fh.write(")\n") + if is_qml_plugin and not is_plugin: + write_qml_module(cm_fh, binary_name, scope, scopes, indent=indent, resource=qml_resource) + handling_first_scope = True for scope in scopes: @@ -3918,7 +4076,23 @@ def write_example( io_string, scope, f"target_compile_options({binary_name}", indent=indent, footer=")\n" ) - write_resources(io_string, binary_name, scope, indent=indent, is_example=True) + (resources, standalone_qtquick_compiler_skipped_files) = extract_resources( + binary_name, scope + ) + + # Remove the QML resource, because we've handled it in write_qml_module. + if qml_resource is not None: + resources = list(filter(lambda r: r.name != qml_resource.name, resources)) + + write_resources( + io_string, + binary_name, + scope, + indent=indent, + is_example=True, + resources=resources, + skipped_standalone_files=standalone_qtquick_compiler_skipped_files, + ) write_statecharts(io_string, binary_name, scope, indent=indent, is_example=True) write_repc_files(io_string, binary_name, scope, indent=indent) @@ -3933,13 +4107,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 @@ -4041,14 +4216,145 @@ def get_qml_import_version(scope: Scope, target: str) -> str: if import_version: replacements = [ - ("$$QT_MINOR_VERSION", "${CMAKE_PROJECT_VERSION_MINOR}"), - ("$$QT_VERSION", "${CMAKE_PROJECT_VERSION}"), + ("$$QT_MINOR_VERSION", "${PROJECT_VERSION_MINOR}"), + ("$$QT_VERSION", "${PROJECT_VERSION}"), ] for needle, replacement in replacements: import_version = import_version.replace(needle, replacement) return import_version +def write_qml_module( + cm_fh: IO[str], + target: str, + scope: Scope, + scopes: List[Scope], + resource: QtResource, + extra_add_qml_module_args: List[str] = [], + indent: int = 0, +): + uri = scope.get_string("QML_IMPORT_NAME") + if not uri: + uri = target + + try: + version = get_qml_import_version(scope, target) + except RuntimeError: + version = "${PROJECT_VERSION}" + + dest_dir = scope.expandString("DESTDIR") + if dest_dir: + dest_dir = f"${{CMAKE_CURRENT_BINARY_DIR}}/{dest_dir}" + + content = "" + + qml_dir = None + qml_dir_dynamic_imports = False + + qmldir_file_path_list = scope.get_files("qmldir.files") + assert len(qmldir_file_path_list) < 2, "File path must only contain one path" + qmldir_file_path = qmldir_file_path_list[0] if qmldir_file_path_list else "qmldir" + qmldir_file_path = os.path.join(os.getcwd(), qmldir_file_path[0]) + + dynamic_qmldir = scope.get("DYNAMIC_QMLDIR") + if os.path.exists(qmldir_file_path): + qml_dir = QmlDir() + qml_dir.from_file(qmldir_file_path) + elif dynamic_qmldir: + qml_dir = QmlDir() + qml_dir.from_lines(dynamic_qmldir) + qml_dir_dynamic_imports = True + + content += "set(module_dynamic_qml_imports\n " + if len(qml_dir.imports) != 0: + content += "\n ".join(qml_dir.imports) + content += "\n)\n\n" + + for sc in scopes[1:]: + import_list = [] + qml_imports = sc.get("DYNAMIC_QMLDIR") + for qml_import in qml_imports: + if not qml_import.startswith("import "): + raise RuntimeError( + "Only qmldir import statements expected in conditional scope!" + ) + import_list.append(qml_import[len("import ") :].replace(" ", "/")) + if len(import_list) == 0: + continue + + assert sc.condition + + content += f"if ({sc.condition})\n" + content += " list(APPEND module_dynamic_qml_imports\n " + content += "\n ".join(import_list) + content += "\n )\nendif()\n\n" + + content += dedent( + f"""\ + qt_add_qml_module({target} + URI {uri} + VERSION {version} + """ + ) + + if resource is not None: + qml_files = list(filter(is_qtquick_source_file, resource.files.keys())) + if qml_files: + content += " QML_FILES\n" + for file in qml_files: + content += f" {file}\n" + other_files = list(itertools.filterfalse(is_qtquick_source_file, resource.files.keys())) + if other_files: + content += " RESOURCES\n" + for file in other_files: + content += f" {file}\n" + if resource.prefix != "/": + content += f" RESOURCE_PREFIX {resource.prefix}\n" + if scope.TEMPLATE == "app": + content += " NO_RESOURCE_TARGET_PATH\n" + if dest_dir: + content += f" OUTPUT_DIRECTORY {dest_dir}\n" + + if qml_dir is not None: + if qml_dir.designer_supported: + content += " DESIGNER_SUPPORTED\n" + if len(qml_dir.classname) != 0: + content += f" CLASSNAME {qml_dir.classname}\n" + if len(qml_dir.depends) != 0: + content += " DEPENDENCIES\n" + for dep in qml_dir.depends: + content += f" {dep[0]}/{dep[1]}\n" + if len(qml_dir.type_names) == 0: + content += " SKIP_TYPE_REGISTRATION\n" + if len(qml_dir.imports) != 0 and not qml_dir_dynamic_imports: + qml_dir_imports_line = " \n".join(qml_dir.imports) + content += f" IMPORTS\n{qml_dir_imports_line}" + if qml_dir_dynamic_imports: + content += " IMPORTS ${module_dynamic_qml_imports}\n" + if len(qml_dir.optional_imports) != 0: + qml_dir_optional_imports_line = " \n".join(qml_dir.optional_imports) + content += f" OPTIONAL_IMPORTS\n{qml_dir_optional_imports_line}" + if qml_dir.plugin_optional: + content += " PLUGIN_OPTIONAL\n" + + for arg in extra_add_qml_module_args: + content += " " + content += arg + content += "\n" + content += ")\n" + + if resource: + content += write_resource_source_file_properties( + sorted(resource.files.keys()), + resource.files, + resource.base_dir, + resource.skip_qtquick_compiler, + ) + + content += "\n" + cm_fh.write(content) + + def write_qml_plugin( cm_fh: IO[str], target: str, @@ -4124,9 +4430,9 @@ def write_qml_plugin( assert sc.condition cm_fh.write(f"if ({sc.condition})\n") - cm_fh.write(f" list(APPEND module_dynamic_qml_imports\n ") + cm_fh.write(" list(APPEND module_dynamic_qml_imports\n ") cm_fh.write("\n ".join(import_list)) - cm_fh.write(f"\n )\nendif()\n\n") + cm_fh.write("\n )\nendif()\n\n") if qml_dir is not None: if qml_dir.designer_supported: @@ -4199,7 +4505,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") @@ -4221,7 +4532,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) @@ -4262,7 +4575,11 @@ def handle_app_or_lib( # Generate qmltypes instruction for anything that may have CONFIG += qmltypes # that is not a qml plugin - if "qmltypes" in scope.get("CONFIG") and "qml_plugin" not in scope.get("_LOADED"): + if ( + not is_example + and "qmltypes" in scope.get("CONFIG") + and "qml_plugin" not in scope.get("_LOADED") + ): cm_fh.write(f"\n{spaces(indent)}set_target_properties({target_ref} PROPERTIES\n") install_dir = scope.expandString("QMLTYPES_INSTALL_DIR") @@ -4337,7 +4654,7 @@ def handle_top_level_repo_project(scope: Scope, cm_fh: IO[str]): ) build_repo = dedent( - f"""\ + """\ qt_build_repo() """ ) @@ -4349,18 +4666,18 @@ def create_top_level_cmake_conf(): conf_file_name = ".cmake.conf" try: with open(conf_file_name, "x") as file: - file.write('set(QT_REPO_MODULE_VERSION "6.1.0")\n') + file.write('set(QT_REPO_MODULE_VERSION "6.8.0")\n') except FileExistsError: pass def find_top_level_repo_project_file(project_file_path: str = "") -> Optional[str]: - qmake_conf_path = find_qmake_conf(project_file_path) - qmake_dir = os.path.dirname(qmake_conf_path) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_dir = os.path.dirname(qmake_or_cmake_conf_path) # Hope to a programming god that there's only one .pro file at the # top level directory of repository. - glob_result = glob.glob(os.path.join(qmake_dir, "*.pro")) + glob_result = glob.glob(os.path.join(qmake_or_cmake_dir, "*.pro")) if len(glob_result) > 0: return glob_result[0] return None @@ -4369,7 +4686,7 @@ def find_top_level_repo_project_file(project_file_path: str = "") -> Optional[st def handle_top_level_repo_tests_project(scope: Scope, cm_fh: IO[str]): content = dedent( - f"""\ + """\ if(QT_BUILD_STANDALONE_TESTS) # Add qt_find_package calls for extra dependencies that need to be found when building # the standalone tests here. @@ -4391,14 +4708,14 @@ def write_regular_cmake_target_scope_section( write_include_paths( cm_fh, scope, - f"target_include_directories(${{PROJECT_NAME}} PUBLIC", + "target_include_directories(${{PROJECT_NAME}} PUBLIC", indent=indent, footer=")", ) write_defines( cm_fh, scope, - f"target_compile_definitions(${{PROJECT_NAME}} PUBLIC", + "target_compile_definitions(${{PROJECT_NAME}} PUBLIC", indent=indent, footer=")", ) @@ -4408,7 +4725,7 @@ def write_regular_cmake_target_scope_section( private_libs, "", indent=indent, - header=f"target_link_libraries(${{PROJECT_NAME}} PRIVATE\n", + header="target_link_libraries(${{PROJECT_NAME}} PRIVATE\n", footer=")", ) write_list( @@ -4416,20 +4733,27 @@ def write_regular_cmake_target_scope_section( public_libs, "", indent=indent, - header=f"target_link_libraries(${{PROJECT_NAME}} PUBLIC\n", + header="target_link_libraries(${{PROJECT_NAME}} PUBLIC\n", footer=")", ) write_compile_options( - cm_fh, scope, f"target_compile_options(${{PROJECT_NAME}}", indent=indent, footer=")" + cm_fh, scope, "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"cmake_minimum_required(VERSION 3.16)\n" f"project(config_test_{project_name} LANGUAGES C CXX)\n" """ +if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH) + set(CMAKE_SYSTEM_PREFIX_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH}") +endif() +if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH) + set(CMAKE_SYSTEM_FRAMEWORK_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH}") +endif() + foreach(p ${QT_CONFIG_COMPILE_TEST_PACKAGES}) find_package(${p}) endforeach() @@ -4451,7 +4775,7 @@ endif() # Remove default QT libs. scope._append_operation("QT", RemoveOperation(["core", "gui"])) - add_target = f"add_executable(${{PROJECT_NAME}}" + add_target = "add_executable(${{PROJECT_NAME}}" temp_buffer = io.StringIO() write_all_source_file_lists(temp_buffer, scope, add_target, indent=0) @@ -4489,40 +4813,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: @@ -4531,7 +4868,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: @@ -4605,10 +4944,10 @@ def cmake_project_has_skip_marker(project_file_path: str = "") -> bool: def should_convert_project(project_file_path: str = "", ignore_skip_marker: bool = False) -> bool: - qmake_conf_path = find_qmake_conf(project_file_path) - qmake_conf_dir_path = os.path.dirname(qmake_conf_path) + qmake_or_cmake_conf_path = find_qmake_or_cmake_conf(project_file_path) + qmake_or_cmake_conf_dir_path = os.path.dirname(qmake_or_cmake_conf_path) - project_relative_path = os.path.relpath(project_file_path, qmake_conf_dir_path) + project_relative_path = os.path.relpath(project_file_path, qmake_or_cmake_conf_dir_path) # Skip cmake auto tests, they should not be converted. if project_relative_path.startswith("tests/auto/cmake"): @@ -4688,7 +5027,7 @@ def main() -> None: cmake_api_version = args.api_version else: # Otherwise detect the api version in the old CMakeLists.txt - # if it exsists. + # if it exists. detected_cmake_api_version = detect_cmake_api_version_used_in_file_content( file_relative_path ) @@ -4727,7 +5066,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/pro_conversion_rate.py b/util/cmake/pro_conversion_rate.py index 3c0c7e3070..30aae95b06 100755 --- a/util/cmake/pro_conversion_rate.py +++ b/util/cmake/pro_conversion_rate.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2019 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2019 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 from __future__ import annotations @@ -57,7 +32,7 @@ def _parse_commandline(): class Blacklist: - """ Class to check if a certain dir_name / dir_path is blacklisted """ + """Class to check if a certain dir_name / dir_path is blacklisted""" def __init__(self, names: typing.List[str], path_parts: typing.List[str]): self.names = names @@ -99,7 +74,7 @@ class Blacklist: def recursive_scan(path: str, extension: str, result_paths: typing.List[str], blacklist: Blacklist): - """ Find files ending with a certain extension, filtering out blacklisted entries """ + """Find files ending with a certain extension, filtering out blacklisted entries""" try: for entry in os.scandir(path): if entry.is_file() and entry.path.endswith(extension): diff --git a/util/cmake/qmake_parser.py b/util/cmake/qmake_parser.py index 357a529e5a..8cf7b1c46e 100644..100755 --- a/util/cmake/qmake_parser.py +++ b/util/cmake/qmake_parser.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import collections import os @@ -73,7 +48,7 @@ def fixup_comments(contents: str) -> str: def flatten_list(input_list): - """ Flattens an irregular nested list into a simple list.""" + """Flattens an irregular nested list into a simple list.""" for el in input_list: if isinstance(el, collections.abc.Iterable) and not isinstance(el, (str, bytes)): yield from flatten_list(el) @@ -333,12 +308,61 @@ class QmakeParser: "ConditionWhiteSpace", pp.Suppress(pp.Optional(pp.White(" "))) ) + # Unfortunately qmake condition operators have no precedence, + # and are simply evaluated left to right. To emulate that, wrap + # each condition sub-expression in parentheses. + # So c1|c2:c3 is evaluated by qmake as (c1|c2):c3. + # The following variable keeps count on how many parentheses + # should be added to the beginning of the condition. Each + # condition sub-expression always gets an ")", and in the + # end the whole condition gets many "(". Note that instead + # inserting the actual parentheses, we insert special markers + # which get replaced in the end. + condition_parts_count = 0 + # Whitespace in the markers is important. Assumes the markers + # never appear in .pro files. + l_paren_marker = "_(_ " + r_paren_marker = " _)_" + + def handle_condition_part(condition_part_parse_result: pp.ParseResults) -> str: + condition_part_list = [*condition_part_parse_result] + nonlocal condition_parts_count + condition_parts_count += 1 + condition_part_joined = "".join(condition_part_list) + # Add ending parenthesis marker. The counterpart is added + # in handle_condition. + return f"{condition_part_joined}{r_paren_marker}" + + ConditionPart.setParseAction(handle_condition_part) ConditionRepeated = add_element( "ConditionRepeated", pp.ZeroOrMore(ConditionOp + ConditionWhiteSpace + ConditionPart) ) + def handle_condition(condition_parse_results: pp.ParseResults) -> str: + nonlocal condition_parts_count + prepended_parentheses = l_paren_marker * condition_parts_count + result = prepended_parentheses + " ".join(condition_parse_results).strip().replace( + ":", " && " + ).strip(" && ") + # If there are only 2 condition sub-expressions, there is no + # need for parentheses. + if condition_parts_count < 3: + result = result.replace(l_paren_marker, "") + result = result.replace(r_paren_marker, "") + result = result.strip(" ") + else: + result = result.replace(l_paren_marker, "( ") + result = result.replace(r_paren_marker, " )") + # Strip parentheses and spaces around the final + # condition. + result = result[1:-1] + result = result.strip(" ") + # Reset the parenthesis count for the next condition. + condition_parts_count = 0 + return result + Condition = add_element("Condition", pp.Combine(ConditionPart + ConditionRepeated)) - Condition.setParseAction(lambda x: " ".join(x).strip().replace(":", " && ").strip(" && ")) + Condition.setParseAction(handle_condition) # Weird thing like write_file(a)|error() where error() is the alternative condition # which happens to be a function call. In this case there is no scope, but our code expects diff --git a/util/cmake/run_pro2cmake.py b/util/cmake/run_pro2cmake.py index 4a12c57b83..3e860e90b2 100755 --- a/util/cmake/run_pro2cmake.py +++ b/util/cmake/run_pro2cmake.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import glob import os @@ -100,7 +75,7 @@ def parse_command_line() -> argparse.Namespace: def find_all_pro_files(base_path: str, args: argparse.Namespace): def sorter(pro_file: str) -> str: - """ Sorter that tries to prioritize main pro files in a directory. """ + """Sorter that tries to prioritize main pro files in a directory.""" pro_file_without_suffix = pro_file.rsplit("/", 1)[-1][:-4] dir_name = os.path.dirname(pro_file) if dir_name == ".": diff --git a/util/cmake/special_case_helper.py b/util/cmake/special_case_helper.py index 28295b3143..a7343d32c3 100644 --- a/util/cmake/special_case_helper.py +++ b/util/cmake/special_case_helper.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2019 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2019 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 """ This is a helper script that takes care of reapplying special case diff --git a/util/cmake/tests/data/condition_operator_precedence.pro b/util/cmake/tests/data/condition_operator_precedence.pro new file mode 100644 index 0000000000..8af628404d --- /dev/null +++ b/util/cmake/tests/data/condition_operator_precedence.pro @@ -0,0 +1,11 @@ +a1|a2 { + DEFINES += d +} + +b1|b2:b3 { + DEFINES += d +} + +c1|c2:c3|c4 { + DEFINES += d +} diff --git a/util/cmake/tests/data/conversion/optional_qt_modules.pro b/util/cmake/tests/data/conversion/optional_qt_modules.pro new file mode 100644 index 0000000000..b9522169fc --- /dev/null +++ b/util/cmake/tests/data/conversion/optional_qt_modules.pro @@ -0,0 +1,4 @@ +TARGET = myapp +QT = core network widgets +win32: QT += opengl +SOURCES = main.cpp diff --git a/util/cmake/tests/data/conversion/qt_version_check.pro b/util/cmake/tests/data/conversion/qt_version_check.pro new file mode 100644 index 0000000000..cf3697bb64 --- /dev/null +++ b/util/cmake/tests/data/conversion/qt_version_check.pro @@ -0,0 +1,8 @@ +QT += core gui +SOURCES += main.cpp +greaterThan(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 1):equals(QT_PATCH_VERSION, 0) { + DEFINES += SUPER_FRESH_MAJOR_QT_RELEASE +} +greaterThan(QT_VERSION, 6.6.5):lessThan(QT_VERSION, 6.6.7):equals(QT_VERSION, 6.6.6): { + DEFINES += QT_VERSION_OF_THE_BEAST +} diff --git a/util/cmake/tests/data/conversion/required_qt_modules.pro b/util/cmake/tests/data/conversion/required_qt_modules.pro new file mode 100644 index 0000000000..287bb46831 --- /dev/null +++ b/util/cmake/tests/data/conversion/required_qt_modules.pro @@ -0,0 +1,3 @@ +TARGET = myapp +QT = core network widgets +SOURCES = main.cpp diff --git a/util/cmake/tests/data/standardpaths.pro b/util/cmake/tests/data/standardpaths.pro index 4b45788e4f..b9896b8e29 100644 --- a/util/cmake/tests/data/standardpaths.pro +++ b/util/cmake/tests/data/standardpaths.pro @@ -7,7 +7,7 @@ win32 { } else:unix { mac { OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm - } else:android:!android-embedded { + } else:android { SOURCES += io/qstandardpaths_android.cpp } else:haiku { SOURCES += io/qstandardpaths_haiku.cpp diff --git a/util/cmake/tests/test_conversion.py b/util/cmake/tests/test_conversion.py new file mode 100755 index 0000000000..0cdfb51976 --- /dev/null +++ b/util/cmake/tests/test_conversion.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +from pro2cmake import Scope, SetOperation, merge_scopes, recursive_evaluate_scope +from tempfile import TemporaryDirectory + +import os +import pathlib +import pytest +import re +import shutil +import subprocess +import tempfile +import typing + +debug_mode = bool(os.environ.get("DEBUG_PRO2CMAKE_TEST_CONVERSION")) +test_script_dir = pathlib.Path(__file__).parent.resolve() +pro2cmake_dir = test_script_dir.parent.resolve() +pro2cmake_py = pro2cmake_dir.joinpath("pro2cmake.py") +test_data_dir = test_script_dir.joinpath("data", "conversion") + + +def convert(base_name: str): + pro_file_name = str(base_name) + ".pro" + pro_file_path = test_data_dir.joinpath(pro_file_name) + assert(pro_file_path.exists()) + with TemporaryDirectory(prefix="testqmake2cmake") as tmp_dir_str: + tmp_dir = pathlib.Path(tmp_dir_str) + output_file_path = tmp_dir.joinpath("CMakeLists.txt") + exit_code = subprocess.call([pro2cmake_py, "--is-example", "-o", output_file_path, pro_file_path]) + assert(exit_code == 0) + if debug_mode: + shutil.copyfile(output_file_path, tempfile.gettempdir() + "/pro2cmake/CMakeLists.txt") + f = open(output_file_path, "r") + assert(f) + content = f.read() + assert(content) + return content + + +def test_qt_modules(): + output = convert("required_qt_modules") + find_package_lines = [] + for line in output.split("\n"): + if "find_package(" in line: + find_package_lines.append(line.strip()) + assert(["find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core)", + "find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Network Widgets)"] == find_package_lines) + + output = convert("optional_qt_modules") + find_package_lines = [] + for line in output.split("\n"): + if "find_package(" in line: + find_package_lines.append(line.strip()) + assert(["find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core)", + "find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Network Widgets)", + "find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS OpenGL)"] == find_package_lines) + +def test_qt_version_check(): + output = convert("qt_version_check") + interesting_lines = [] + for line in output.split("\n"): + if line.startswith("if(") and "QT_VERSION" in line: + interesting_lines.append(line.strip()) + assert(["if(( ( (QT_VERSION_MAJOR GREATER 5) ) AND (QT_VERSION_MINOR LESS 1) ) AND (QT_VERSION_PATCH EQUAL 0))", "if(( ( (QT_VERSION VERSION_GREATER 6.6.5) ) AND (QT_VERSION VERSION_LESS 6.6.7) ) AND (QT_VERSION VERSION_EQUAL 6.6.6))"] == interesting_lines) diff --git a/util/cmake/tests/test_lc_fixup.py b/util/cmake/tests/test_lc_fixup.py index 42094a5288..aa63e02fe1 100755 --- a/util/cmake/tests/test_lc_fixup.py +++ b/util/cmake/tests/test_lc_fixup.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 from qmake_parser import fixup_linecontinuation diff --git a/util/cmake/tests/test_logic_mapping.py b/util/cmake/tests/test_logic_mapping.py index 6e4fd20590..cc7d5a3636 100755 --- a/util/cmake/tests/test_logic_mapping.py +++ b/util/cmake/tests/test_logic_mapping.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 from condition_simplifier import simplify_condition @@ -182,5 +157,4 @@ def test_simplify_complex_false(): def test_simplify_android_not_apple(): - validate_simplify('ANDROID AND NOT ANDROID_EMBEDDED AND NOT MACOS', - 'ANDROID AND NOT ANDROID_EMBEDDED') + validate_simplify('ANDROID AND NOT MACOS', 'ANDROID') diff --git a/util/cmake/tests/test_operations.py b/util/cmake/tests/test_operations.py index c1e5f1b250..95f894dae4 100755 --- a/util/cmake/tests/test_operations.py +++ b/util/cmake/tests/test_operations.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 from pro2cmake import AddOperation, SetOperation, UniqueAddOperation, RemoveOperation diff --git a/util/cmake/tests/test_parsing.py b/util/cmake/tests/test_parsing.py index 9acee46007..ceda348f53 100755 --- a/util/cmake/tests/test_parsing.py +++ b/util/cmake/tests/test_parsing.py @@ -1,34 +1,11 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import os +from pro2cmake import map_condition from qmake_parser import QmakeParser +from condition_simplifier import simplify_condition _tests_path = os.path.dirname(os.path.abspath(__file__)) @@ -239,7 +216,7 @@ def test_realworld_standardpaths(): # android / else: (cond4, if_branch4, else_branch4) = evaluate_condition(else_branch3[0]) - assert cond4 == 'android && !android-embedded' + assert cond4 == 'android' assert len(if_branch4) == 1 validate_op('SOURCES', '+=', ['io/qstandardpaths_android.cpp'], if_branch4[0]) assert len(else_branch4) == 1 @@ -259,7 +236,7 @@ def test_realworld_comment_scope(): (cond, if_branch, else_branch) = evaluate_condition(result[0]) assert cond == 'freebsd|openbsd' assert len(if_branch) == 1 - validate_op('QMAKE_LFLAGS_NOUNDEF', '=', None, if_branch[0]) + validate_op('QMAKE_LFLAGS_NOUNDEF', '=', [], if_branch[0]) assert 'included' in result[1] assert result[1]['included'].get('value', '') == 'animation/animation.pri' @@ -352,3 +329,15 @@ def test_value_function(): assert target == 'Dummy' value = result[1]['value'] assert value[0] == '$$TARGET' + + +def test_condition_operator_precedence(): + result = parse_file(_tests_path + '/data/condition_operator_precedence.pro') + + def validate_simplify(input_str: str, expected: str) -> None: + output = simplify_condition(map_condition(input_str)) + assert output == expected + + validate_simplify(result[0]["condition"], "a1 OR a2") + validate_simplify(result[1]["condition"], "b3 AND (b1 OR b2)") + validate_simplify(result[2]["condition"], "c4 OR (c1 AND c3) OR (c2 AND c3)") diff --git a/util/cmake/tests/test_scope_handling.py b/util/cmake/tests/test_scope_handling.py index 51e569fb09..b36c5d5bcd 100755 --- a/util/cmake/tests/test_scope_handling.py +++ b/util/cmake/tests/test_scope_handling.py @@ -1,31 +1,6 @@ #!/usr/bin/env python3 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the plugins of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2021 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 from pro2cmake import Scope, SetOperation, merge_scopes, recursive_evaluate_scope @@ -306,12 +281,10 @@ def test_qstandardpaths_scopes(): # mac { # OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm scope7 = _new_scope(parent_scope=scope6, condition='MACOS', SOURCES='qsp_mac.mm') - # } else:android:!android-embedded { + # } else:android { # SOURCES += io/qstandardpaths_android.cpp scope8 = _new_scope(parent_scope=scope6, condition='else') - scope9 = _new_scope(parent_scope=scope8, - condition='ANDROID AND NOT ANDROID_EMBEDDED', - SOURCES='qsp_android.cpp') + scope9 = _new_scope(parent_scope=scope8, condition='ANDROID AND NOT UNKNOWN_PLATFORM', SOURCES='qsp_android.cpp') # } else:haiku { # SOURCES += io/qstandardpaths_haiku.cpp scope10 = _new_scope(parent_scope=scope8, condition='else') @@ -332,10 +305,10 @@ def test_qstandardpaths_scopes(): assert scope6.total_condition == 'UNIX' assert scope7.total_condition == 'MACOS' assert scope8.total_condition == 'UNIX AND NOT MACOS' - assert scope9.total_condition == 'ANDROID AND NOT ANDROID_EMBEDDED' - assert scope10.total_condition == 'UNIX AND NOT MACOS AND (ANDROID_EMBEDDED OR NOT ANDROID)' - assert scope11.total_condition == 'HAIKU AND (ANDROID_EMBEDDED OR NOT ANDROID)' - assert scope12.total_condition == 'UNIX AND NOT MACOS AND NOT HAIKU AND (ANDROID_EMBEDDED OR NOT ANDROID)' + assert scope9.total_condition == 'ANDROID AND NOT UNKNOWN_PLATFORM' + assert scope10.total_condition == 'UNIX AND NOT MACOS AND (UNKNOWN_PLATFORM OR NOT ANDROID)' + assert scope11.total_condition == 'HAIKU AND (UNKNOWN_PLATFORM OR NOT ANDROID)' + assert scope12.total_condition == 'UNIX AND NOT HAIKU AND NOT MACOS AND (UNKNOWN_PLATFORM OR NOT ANDROID)' def test_recursive_expansion(): scope = _new_scope(A='Foo',B='$$A/Bar') @@ -343,4 +316,3 @@ def test_recursive_expansion(): assert scope.get_string('B') == '$$A/Bar' assert scope._expand_value('$$B/Source.cpp') == ['Foo/Bar/Source.cpp'] assert scope._expand_value('$$B') == ['Foo/Bar'] - |