CMake: Mitigate moc not finding correct headers in framework builds

When CMake generates compilation rules, it extracts the values from
INTERFACE_INCLUDE_DIRECTORIES and checks if any of the values
are framework paths.
If they are, instead of adding an -I ./lib/My.framework to the
compilation rules, it adds -iframework ./lib or -F ./lib.

The same transformation does not happen when AUTOMOC passes include
paths to moc, nor during a headersclean check. The values there
are passed verbatim, with an -I prepended.

This causes issues when the include file name is the same as the
framework name.
E.g. #include <QtQml> + -I ./lib/QtQml.framework because moc
then ends up silently including the shared library
 ./lib/QtQml.framework/QtQml
instead of the header
 ./lib/QtQml.framework/Headers/QtQml

This can lead to a variety of silent issues during moc generation,
because all the definitions of QtQml will be missing.

Unfortunately, there does not seem to be a clean way to fix this in
the build system due to CMake semantics.
See https://gitlab.kitware.com/cmake/cmake/-/issues/23337 for details.

We can mitigate the issue by ensuring that
 -I ./lib/QtQml.framework/Headers
comes before
 -I ./lib/QtQml.framework

by manipulating the order of values in INTERFACE_INCLUDE_DIRECTORIES.

We might want to consider implementing an additional mitigation in
AUTOMOC, so that it filters out include paths like
 -I ./lib/QtQml.framework, thus ensuring that a newer CMake version
will not exhibit the same issue when used with an older Qt.

We could consider doing the same in moc. The advantage of doing it
in moc is that that moc will consider fewer invalid include paths
when searching for headers.

Amends 4b2de41b13
Amends d7efb2a419

Pick-to: 6.2 6.3
Fixes: QTBUG-89545
Fixes: QTBUG-101718
Fixes: QTBUG-101775
Change-Id: Ib2c25b5744bd2b5c9c83813bb04ad88c0179f6ec
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
bb10
Alexandru Croitor 2022-03-17 13:23:48 +01:00
parent 71edd2e4d8
commit b858704e1f
1 changed files with 8 additions and 4 deletions

View File

@ -454,16 +454,20 @@ function(qt_internal_add_module target)
set(fw_install_header_dir "${INSTALL_LIBDIR}/${fw_header_dir}")
set(fw_output_header_dir "${QT_BUILD_DIR}/${fw_install_header_dir}")
list(APPEND public_includes
# Add the lib/Foo.framework dir as include path to let CMake generate
# the -F compiler flag for framework-style includes to work.
"$<INSTALL_INTERFACE:${fw_install_dir}>"
# Add the framework Headers subdir, so that non-framework-style includes work. The
# BUILD_INTERFACE Headers symlink was previously claimed not to exist at the relevant
# time, and a fully specified Header path was used instead. This doesn't seem to be a
# problem anymore.
"$<BUILD_INTERFACE:${fw_output_header_dir}>"
"$<INSTALL_INTERFACE:${fw_install_header_dir}>"
# Add the lib/Foo.framework dir as an include path to let CMake generate
# the -F compiler flag for framework-style includes to work.
# Make sure it is added AFTER the lib/Foo.framework/Headers include path,
# to mitigate issues like QTBUG-101718 and QTBUG-101775 where an include like
# #include <QtCore> might cause moc to include the QtCore framework shared library
# instead of the actual header.
"$<INSTALL_INTERFACE:${fw_install_dir}>"
)
endif()