qt6_wrap_cpp: Add .moc generation

When a `.moc` file is included in a source file and that source passed
to `qt_wrap_cpp`, Users should add the generated `.moc`s path to the
target's  include path. Since we don't share anything about the output
path of generated files by `qt_wrap_cpp`, it makes sense to add in
inside `qt_wrap_cpp`. And also, the generated `.moc` file is added
to target's source to complete the dependency graph. Otherwise, Users
need to get output variable and pass it to target's sources.

* Update docs
* Add test

[ChangeLog][Build System] qt_wrap_cpp will accept .cpp files from now
on. When .cpp a file is passed to qt_wrap_cpp, TARGET parameter
becomes required. Generated .moc files are added to target's sources
inside qt_wrap_cpp. That's why the output parameter will not contain
generated .moc files.

Fixes: QTBUG-113402
Change-Id: I54dd2b1ff8e5c9ba457b1eb4f73b0a8190d9c659
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Orkun Tokdemir 2023-07-21 16:41:48 +02:00
parent bcdd51cfae
commit dc4159286b
7 changed files with 123 additions and 3 deletions

View File

@ -200,7 +200,49 @@ function(qt6_wrap_cpp outfiles )
foreach(it ${moc_files})
get_filename_component(it ${it} ABSOLUTE)
_qt_internal_make_output_file(${it} moc_ cpp outfile)
get_filename_component(it_ext ${it} EXT)
# remove the dot
string(SUBSTRING ${it_ext} 1 -1 it_ext)
set(HEADER_REGEX "(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$")
if(it_ext MATCHES "${HEADER_REGEX}")
_qt_internal_make_output_file("${it}" moc_ cpp outfile)
set(is_header_file TRUE)
else()
set(found_source_extension FALSE)
foreach(LANG C CXX OBJC OBJCXX CUDA)
list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${it_ext}"
index)
if(${index} GREATER -1)
set(found_extension TRUE)
break()
endif()
endforeach()
if(found_extension)
if(TARGET ${moc_target})
_qt_internal_make_output_file(${it} "" moc outfile)
target_sources(${moc_target} PRIVATE "${outfile}")
target_include_directories("${moc_target}" PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}")
else()
if("${moc_target}" STREQUAL "")
string(JOIN "" err_msg
"qt6_wrap_cpp: TARGET parameter is empty. "
"Since the file ${it} is a source file, "
"the TARGET option must be specified.")
else()
string(JOIN "" err_msg
"qt6_wrap_cpp: TARGET \"${moc_target}\" "
"not found.")
endif()
message(FATAL_ERROR "${err_msg}")
endif()
else()
string(JOIN "" err_msg "qt6_wrap_cpp: Unknown file extension: "
"\"\.${it_ext}\".")
message(FATAL_ERROR "${err_msg}")
endif()
endif()
set(out_json_file_var "")
if(_WRAP_CPP___QT_INTERNAL_OUTPUT_MOC_JSON_FILES)
@ -215,7 +257,10 @@ function(qt6_wrap_cpp outfiles )
list(APPEND metatypes_json_list "${${out_json_file_var}}")
endif()
endforeach()
set(${outfiles} ${${outfiles}} PARENT_SCOPE)
if(is_header_file)
set(${outfiles} "${${outfiles}}" PARENT_SCOPE)
endif()
if(metatypes_json_list)
set(${_WRAP_CPP___QT_INTERNAL_OUTPUT_MOC_JSON_FILES}

View File

@ -28,6 +28,11 @@ target_compile_definitions(myapp PRIVATE "$<$<CONFIG:Debug>:MY_OPTION_FOR_DEBUG>
"$<$<BOOL:TRUE>:DEFINE_CMDLINE_SIGNAL_IN_GENEX=void cmdlineSignal(const QMap<int$<COMMA> int$<ANGLE-R> &i)>")
#! [qt_wrap_cpp_3]
#! [qt_wrap_cpp_4]
qt_add_executable(myapp myapp.cpp main.cpp)
qt_wrap_cpp("" myapp.cpp TARGET myapp)
#! [qt_wrap_cpp_4]
#! [qt_add_resources]
set(SOURCES main.cpp)
qt_add_resources(SOURCES example.qrc)

View File

@ -0,0 +1,16 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [qt_wrap_cpp_4]
// myapp.cpp
#include "myapp.h"
#include <QObject>
class MyApp : public QObject {
Q_OBJECT
public:
MyApp() = default;
};
#include "myapp.moc"
//! [qt_wrap_cpp_4]

View File

@ -40,6 +40,12 @@ You can set an explicit \c{TARGET}. This will make sure that the target
properties \c{INCLUDE_DIRECTORIES} and \c{COMPILE_DEFINITIONS} are also used
when scanning the source files with \c{moc}.
Since Qt 6.8, when a source file is passed to \c{qt_wrap_cpp} instead of a
header file to generate a \c{.moc} file for a target, the \c{TARGET} parameter
is needed to set the correct include path for the generated \c{.moc} file in
the source file. As generated \c{.moc} files are added to the target's
sources by \c{qt_wrap_cpp}, they are not added to \c{<VAR>}.
You can set additional \c{OPTIONS} that should be added to the \c{moc} calls.
You can find possible options in the \l{moc}{moc documentation}.
@ -69,5 +75,16 @@ avoid syntax errors in the generator expressions.
The following example uses \l{https://cmake.org/cmake/help/latest/command/target_compile_definitions.html}{target_compile_definitions}
to set \l{https://cmake.org/cmake/help/latest/prop_tgt/COMPILE_DEFINITIONS.html}{COMPILE_DEFINITIONS} which will be added to
\c{OPTIONS}.
\snippet cmake-macros/examples.cmake qt_wrap_cpp_3
\snippet cmake-macros/examples.cmake qt_wrap_cpp_4
\snippet cmake-macros/examples.cpp qt_wrap_cpp_4
In the above file, \c{myapp.moc} is included in \c{myapp.cpp}.
To generate the \c{myapp.moc} file, the \c{qt_wrap_cpp} macro is used with the
\c{TARGET} parameter. The first parameter is empty because the \c{.moc} file
and its path will be added to the target's sources and include directories by
the \c{qt_wrap_cpp} macro.
\snippet cmake-macros/examples.cmake qt_wrap_cpp_4
*/

View File

@ -197,6 +197,7 @@ endif()
_qt_internal_test_expect_pass(test_add_resource_prefix BINARY test_add_resource_prefix)
_qt_internal_test_expect_build_fail(test_add_resource_options)
_qt_internal_test_expect_build_fail(test_wrap_cpp_options)
_qt_internal_test_expect_pass(test_wrap_cpp_moc)
_qt_internal_test_expect_pass(test_platform_defs_include)
_qt_internal_test_expect_pass(test_qtmainwin_library)

View File

@ -0,0 +1,19 @@
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(test_wrap_cpp_and_resources)
find_package(Qt6Core REQUIRED)
add_executable(example main.cpp)
qt_wrap_cpp(moc_files main.cpp TARGET example)
# expect the generated moc files to be empty when a source file is passed
if (NOT moc_files STREQUAL "")
message(FATAL_ERROR "test_qt_wrap_cpp_moc: moc_files should be empty")
endif()
target_link_libraries(example PRIVATE Qt::Core)

View File

@ -0,0 +1,17 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: BSD-3-Clause
#include <QObject>
class MyObject2 : public QObject {
Q_OBJECT
public:
MyObject2() = default;
};
#include "main.moc"
int main()
{
return 0;
}