diff --git a/cmake/QtAutogenHelpers.cmake b/cmake/QtAutogenHelpers.cmake index 66c46b8d81..029a709e90 100644 --- a/cmake/QtAutogenHelpers.cmake +++ b/cmake/QtAutogenHelpers.cmake @@ -78,14 +78,23 @@ endfunction() # Complete manual moc invocation with full control. # Use AUTOMOC whenever possible. -# INCLUDE_DIRECTORIES specifies a list of include directories used by 'moc'. -# INCLUDE_DIRECTORY_TARGETS specifies a list of targets to extract the INTERFACE_INCLUDE_DIRECTORIES -# property and use it as the 'moc' include directories. +# Multi-value Arguments: +# INCLUDE_DIRECTORIES +# Specifies a list of include directories used by 'moc'. +# INCLUDE_DIRECTORY_TARGETS +# Specifies a list of targets to extract the INTERFACE_INCLUDE_DIRECTORIES +# property and use it as the 'moc' include directories.(Deprecated use TARGETS instead) +# DEFINITIONS +# List of the definitions that should be added to the moc command line arguments. +# Supports the syntax both with and without the prepending '-D'. +# TARGETS +# The list of targets that will be used to collect the INTERFACE_INCLUDE_DIRECTORIES, +# INCLUDE_DIRECTORIES, and COMPILE_DEFINITIONS properties. function(qt_manual_moc result) cmake_parse_arguments(arg "" "OUTPUT_MOC_JSON_FILES" - "FLAGS;INCLUDE_DIRECTORIES;INCLUDE_DIRECTORY_TARGETS" + "FLAGS;INCLUDE_DIRECTORIES;INCLUDE_DIRECTORY_TARGETS;DEFINITIONS;TARGETS" ${ARGN}) set(moc_files) set(metatypes_json_list) @@ -102,7 +111,7 @@ function(qt_manual_moc result) "-I\n${dir}") endforeach() - foreach(dep IN ITEMS ${arg_INCLUDE_DIRECTORY_TARGETS}) + foreach(dep IN LISTS arg_INCLUDE_DIRECTORY_TARGETS arg_TARGETS) set(include_expr "$") list(APPEND moc_parameters "$<$:-I\n$>") @@ -128,6 +137,30 @@ function(qt_manual_moc result) endif() endforeach() + foreach(dep IN LISTS arg_TARGETS) + set(include_property_expr + "$>") + list(APPEND moc_parameters + "$<$:-I\n$>") + + set(defines_property_expr + "$>") + set(defines_with_d "$") + set(defines_without_d "$") + list(APPEND moc_parameters + "$<$:$>") + list(APPEND moc_parameters + "$<$:-D\n$>") + endforeach() + + foreach(def IN LISTS arg_DEFINITIONS) + if(NOT def MATCHES "^-D") + list(APPEND moc_parameters "-D\n${def}") + else() + list(APPEND moc_parameters "${def}") + endif() + endforeach() + set(metatypes_byproducts) if (arg_OUTPUT_MOC_JSON_FILES) set(moc_json_file "${outfile}.json") diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 25151ddbb1..3331ad260d 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -402,3 +402,5 @@ _qt_internal_test_expect_pass(test_QTP0003) if(NOT NO_GUI) _qt_internal_test_expect_pass(test_collecting_plugins) endif() + +_qt_internal_test_expect_pass(test_qt_manual_moc) diff --git a/tests/auto/cmake/test_qt_manual_moc/CMakeLists.txt b/tests/auto/cmake/test_qt_manual_moc/CMakeLists.txt new file mode 100644 index 0000000000..513995c4cf --- /dev/null +++ b/tests/auto/cmake/test_qt_manual_moc/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) + +find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core) + +set(CMAKE_AUTOMOC FALSE) + +qt_manual_moc(moc_files testclass.h + DEFINITIONS + -DMY_FIRST_DEF + MY_SECOND_DEF + -DMY_THIRD_DEF=1 + MY_FOURTH_DEF=1 +) + +add_custom_target(verify_testclass ALL COMMAND ${CMAKE_COMMAND} + "-DMOC_ARGS=moc_testclass.cpp_parameters$<$>:_$>" + "-DDEFINITIONS=MY_FIRST_DEF;MY_SECOND_DEF;MY_THIRD_DEF=1;MY_FOURTH_DEF=1" + -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyDefines.cmake" + VERBATIM +) + +add_library(MyInterfaceLib INTERFACE) +target_compile_definitions(MyInterfaceLib INTERFACE -DMY_TRANSITIVE_DEF=1) + +add_library(MyLib SHARED testclass1.h testclass.cpp) +target_link_libraries(MyLib PRIVATE Qt6::Core MyInterfaceLib) +target_compile_definitions(MyLib PRIVATE + -DMY_FIRST_DEF + MY_SECOND_DEF + -DMY_THIRD_DEF=1 + MY_FOURTH_DEF=1 +) + +add_library(MyLib2 SHARED testclass1.h testclass.cpp) +target_link_libraries(MyLib2 PRIVATE Qt6::Core) +target_compile_definitions(MyLib2 PRIVATE + -DMY_FOREIGN_DEF +) + +qt_manual_moc(moc_files testclass1.h TARGETS MyLib MyLib2) +target_sources(MyLib PRIVATE ${moc_files}) +target_sources(MyLib2 PRIVATE ${moc_files}) + +string(JOIN ";" expected + "MY_FIRST_DEF" + "MY_SECOND_DEF" + "MY_THIRD_DEF=1" + "MY_FOURTH_DEF=1" + "MY_TRANSITIVE_DEF=1" + "MY_FOREIGN_DEF" +) + +add_custom_target(verify_testclass1 ALL COMMAND ${CMAKE_COMMAND} + "-DMOC_ARGS=moc_testclass1.cpp_parameters$<$>:_$>" + "-DDEFINITIONS=${expected}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyDefines.cmake" + VERBATIM +) diff --git a/tests/auto/cmake/test_qt_manual_moc/VerifyDefines.cmake b/tests/auto/cmake/test_qt_manual_moc/VerifyDefines.cmake new file mode 100644 index 0000000000..b3acedb014 --- /dev/null +++ b/tests/auto/cmake/test_qt_manual_moc/VerifyDefines.cmake @@ -0,0 +1,30 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) + +if(NOT DEFINITIONS) + message(FATAL_ERROR "No definitions are provided to test") +endif() + +if(NOT MOC_ARGS) + message(FATAL_ERROR "The moc RSP file is not specified") +endif() + +file(READ "${MOC_ARGS}" moc_args_data) + +string(REPLACE "\n" ";" moc_args_data "${moc_args_data}") + +foreach(def IN LISTS DEFINITIONS) + set(found FALSE) + foreach(data IN LISTS moc_args_data) + if(data MATCHES "^(-D)?${def}") + set(found TRUE) + break() + endif() + endforeach() + if(NOT found) + message(FATAL_ERROR "The ${def} is missing in the moc argument list:\n${moc_args_data}") + endif() +endforeach() + diff --git a/tests/auto/cmake/test_qt_manual_moc/testclass.cpp b/tests/auto/cmake/test_qt_manual_moc/testclass.cpp new file mode 100644 index 0000000000..5323e18136 --- /dev/null +++ b/tests/auto/cmake/test_qt_manual_moc/testclass.cpp @@ -0,0 +1,8 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include "testclass.h" + +TestClass::TestClass(QObject *parent) : QObject(parent) +{ + +} diff --git a/tests/auto/cmake/test_qt_manual_moc/testclass.h b/tests/auto/cmake/test_qt_manual_moc/testclass.h new file mode 100644 index 0000000000..84fc656f1a --- /dev/null +++ b/tests/auto/cmake/test_qt_manual_moc/testclass.h @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef TESTCLASS_H +#define TESTCLASS_H + +#include + +class TestClass : public QObject +{ + Q_OBJECT + +public: + TestClass(QObject *parent = nullptr); +}; + +#endif // TESTCLASS_H diff --git a/tests/auto/cmake/test_qt_manual_moc/testclass1.h b/tests/auto/cmake/test_qt_manual_moc/testclass1.h new file mode 100644 index 0000000000..84fc656f1a --- /dev/null +++ b/tests/auto/cmake/test_qt_manual_moc/testclass1.h @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef TESTCLASS_H +#define TESTCLASS_H + +#include + +class TestClass : public QObject +{ + Q_OBJECT + +public: + TestClass(QObject *parent = nullptr); +}; + +#endif // TESTCLASS_H