QMetaType: don't use global relocations to the lambdas and structures

The way the Qt 6.0 QMetaTypeInterface was designed, using a static
inline variable in a template, would normally require the linker and
dynamic linker to merge all copies and choose a single copy as the
official one. But because of hidden visibility and of Windows DLLs,
QMetaType already copes with multiple copies NOT getting merged. So we
may as well ask the linkers not to bother and use simpler, local
relocations to find those symbols.

They are all supposed to still be equivalent and it's an ODR violation
if they're not.

The Apple ld64 linker complains if you use this type of global
relocation:

 ld: warning: direct access in function
  [...]
   to global weak symbol
   'QtPrivate::QMetaTypeInterfaceWrapper<int>::metaType'

Fixes: QTBUG-93471
Change-Id: Id0fb9ab0089845ee8843fffd16f98a10aa719434
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 6234182d82b5f645a61c89219d71ab6a4ac03609)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2022-06-17 15:49:02 -07:00 committed by Qt Cherry-pick Bot
parent e9e5e549eb
commit 660014156d
2 changed files with 25 additions and 0 deletions

View File

@ -2268,6 +2268,20 @@ struct QDataStreamOperatorForType <T, false>
static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr; static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
}; };
// Performance optimization:
//
// Don't add all these symbols to the dynamic symbol tables on ELF systems and
// on Darwin. Each library is going to have a copy anyway and QMetaType already
// copes with some of these being "hidden" (see QMetaType::idHelper()). We may
// as well let the linker know it can always use the local copy.
//
// This is currently not enabled for GCC due to
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106023
#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
# pragma GCC visibility push(hidden)
#endif
template<typename S> template<typename S>
class QMetaTypeForType class QMetaTypeForType
{ {
@ -2358,6 +2372,9 @@ struct QMetaTypeInterfaceWrapper
}; };
}; };
#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
# pragma GCC visibility pop
#endif
template<> template<>
class QMetaTypeInterfaceWrapper<void> class QMetaTypeInterfaceWrapper<void>

View File

@ -522,6 +522,14 @@ void tst_QMetaType::operatorEqAcrossLibs()
QCOMPARE(QByteArray(lib2Type.name()), QByteArray(localType.name())); QCOMPARE(QByteArray(lib2Type.name()), QByteArray(localType.name()));
QCOMPARE(lib1Type, localType); QCOMPARE(lib1Type, localType);
QCOMPARE(lib2Type, localType); QCOMPARE(lib2Type, localType);
#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
if (actualTypeId < QMetaType::FirstGuiType && actualTypeId != QMetaType::Void) {
// for built-in QtCore types, we expect the interfaces to be the same too
QCOMPARE(lib1Iface, localIface);
QCOMPARE(lib2Iface, localIface);
}
#endif
} }
class WithPrivateDTor { class WithPrivateDTor {