From 8d0b487437e731ff3f5f97779002a4ffb48d92ec Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 28 Aug 2009 15:19:24 +0200 Subject: Enable Q_OBJECT usage across DLL boundary on Symbian OS Symbian loader does not allow DLL import relocations in the data section. To workaround this, added an accessor function which can be used to get the class static metadata from the base class even if it is in another DLL. Changing the implementation for all platforms would cause a binary break, so it is only used for Symbian. The Q_NO_DATA_RELOCATION macro is used to configure this feature instead of Q_OS_SYMBIAN, because it is possible another platform may need the same fix and Symbian may eventually fix their DLL loader to support this feature. Task-number: 258893 Reviewed-by: Kent Hansen --- src/corelib/global/qglobal.h | 4 ++++ src/corelib/kernel/qmetaobject.cpp | 12 +++++++++++- src/corelib/kernel/qobjectdefs.h | 8 ++++++++ src/tools/moc/generator.cpp | 27 +++++++++++++++++++++------ 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 93cc30f..fbefe7a 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -2382,6 +2382,10 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); #endif #if defined(Q_OS_SYMBIAN) + +//Symbian does not support data imports from a DLL +#define Q_NO_DATA_RELOCATION + QT_END_NAMESPACE // forward declare std::exception #ifdef __cplusplus diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 3d26160..5771feb 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -613,16 +613,26 @@ static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, co if (strcmp(self->d.stringdata, name) == 0) return self; if (self->d.extradata) { +#ifdef Q_NO_DATA_RELOCATION + const QMetaObjectAccessor *e; + Q_ASSERT(priv(self->d.data)->revision >= 2); +#else const QMetaObject **e; if (priv(self->d.data)->revision < 2) { e = (const QMetaObject**)(self->d.extradata); - } else { + } else +#endif + { const QMetaObjectExtraData *extra = (const QMetaObjectExtraData*)(self->d.extradata); e = extra->objects; } if (e) { while (*e) { +#ifdef Q_NO_DATA_RELOCATION + if (const QMetaObject *m =QMetaObject_findMetaObject(&((*e)()), name)) +#else if (const QMetaObject *m =QMetaObject_findMetaObject((*e), name)) +#endif return m; ++e; } diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 421617a..3f990a3 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -150,6 +150,7 @@ inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {} public: \ Q_OBJECT_CHECK \ static const QMetaObject staticMetaObject; \ + static const QMetaObject &getStaticMetaObject(); \ virtual const QMetaObject *metaObject() const; \ virtual void *qt_metacast(const char *); \ QT_TR_FUNCTIONS \ @@ -161,6 +162,7 @@ private: #define Q_GADGET \ public: \ static const QMetaObject staticMetaObject; \ + static const QMetaObject &getStaticMetaObject(); \ private: #else // Q_MOC_RUN #define slots slots @@ -444,9 +446,15 @@ struct Q_CORE_EXPORT QMetaObject }; +typedef const QMetaObject& (*QMetaObjectAccessor)(); + struct QMetaObjectExtraData { +#ifdef Q_NO_DATA_RELOCATION + const QMetaObjectAccessor *objects; +#else const QMetaObject **objects; +#endif int (*static_metacall)(QMetaObject::Call, int, void **); }; diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index cc6fa88..95e8386 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -302,13 +302,18 @@ void Generator::generateCode() } } if (!extraList.isEmpty()) { + fprintf(out, "#ifdef Q_NO_DATA_RELOCATION\n"); + fprintf(out, "static const QMetaObjectAccessor qt_meta_extradata_%s[] = {\n ", qualifiedClassNameIdentifier.constData()); + for (int i = 0; i < extraList.count(); ++i) { + fprintf(out, " %s::getStaticMetaObject,\n", extraList.at(i).constData()); + } + fprintf(out, "#else\n"); fprintf(out, "static const QMetaObject *qt_meta_extradata_%s[] = {\n ", qualifiedClassNameIdentifier.constData()); for (int i = 0; i < extraList.count(); ++i) { - if (i) - fprintf(out, ",\n "); - fprintf(out, " &%s::staticMetaObject", extraList.at(i).constData()); + fprintf(out, " &%s::staticMetaObject,\n", extraList.at(i).constData()); } - fprintf(out, ",0\n};\n\n"); + fprintf(out, "#endif //Q_NO_DATA_RELOCATION\n"); + fprintf(out, " 0\n};\n\n"); } if (isConstructible || !extraList.isEmpty()) { @@ -328,7 +333,6 @@ void Generator::generateCode() // // Finally create and initialize the static meta object // - if (isQt) fprintf(out, "const QMetaObject QObject::staticQtMetaObject = {\n"); else @@ -348,11 +352,22 @@ void Generator::generateCode() fprintf(out, "&qt_meta_extradata2_%s }\n", qualifiedClassNameIdentifier.constData()); fprintf(out, "};\n"); - if (isQt || !cdef->hasQObject) + if(isQt) + return; + +// +// Generate static meta object accessor (needed for symbian, because DLLs do not support data imports. +// + fprintf(out, "\n#ifdef Q_NO_DATA_RELOCATION\n"); + fprintf(out, "const QMetaObject &%s::getStaticMetaObject() { return staticMetaObject; }\n", cdef->qualified.constData()); + fprintf(out, "#endif //Q_NO_DATA_RELOCATION\n"); + + if (!cdef->hasQObject) return; fprintf(out, "\nconst QMetaObject *%s::metaObject() const\n{\n return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;\n}\n", cdef->qualified.constData()); + // // Generate smart cast function // -- cgit v0.12