Make it easier to use resources in plugins when using static linking
RCC generates code that registers resources automatically on program startup via global constructors. When linking statically and nothing references the symbols in the .o file compiled from the RCC generated code, then the linker will discard the embedded resources and they will not get initialized. That is why for static linking it is necessary to explicitly initialize resources using the Q_INIT_RESOURCE macro. We can avoid the need for the explicit initialization in the context of plugins that are statically linked into the application. resources.prf can generate a .cpp file with a helper function that contains all the Q_INIT_RESOURCE calls for all resources in the plugin. That helper function in turn is injected into the plugin entry point, which in turn is guaranteed to be included in the final binary. Change-Id: If1abf9c85ef92935020af073b989c58c1ae6ca63 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>bb10
parent
72bb1d95fd
commit
be9a56e5e3
|
|
@ -72,6 +72,38 @@ for(resource, RESOURCES) {
|
|||
RESOURCES += $$resource_file
|
||||
}
|
||||
|
||||
!isEmpty(RESOURCES):contains(TEMPLATE, .*lib):plugin:static {
|
||||
resource_init_function = $$lower($$basename(TARGET))_plugin_resource_init
|
||||
DEFINES += "QT_PLUGIN_RESOURCE_INIT_FUNCTION=$$resource_init_function"
|
||||
|
||||
RESOURCE_INIT_CPP = $$OUT_PWD/$$lower($$basename(TARGET))_plugin_resources.cpp
|
||||
|
||||
GENERATED_SOURCES += $$RESOURCE_INIT_CPP
|
||||
QMAKE_DISTCLEAN += $$RESOURCE_INIT_CPP
|
||||
|
||||
!build_pass {
|
||||
RESOURCE_INIT_CONT = \
|
||||
"// This file is autogenerated by qmake. It contains a function that" \
|
||||
"// references all resources the plugin includes and the function is" \
|
||||
"// referenced by Qt_(MOC_)EXPORT_PLUGIN to ensure the inclusion in" \
|
||||
"// the statically linked plugin." \
|
||||
"$${LITERAL_HASH}include <QtCore/qglobal.h>" \
|
||||
"void $${resource_init_function}() " \
|
||||
"{" \
|
||||
|
||||
for (resource, RESOURCES) {
|
||||
resource_name = $$section($$list($$basename(resource)), ., 0, 0)
|
||||
resource_name = $$replace(resource_name, [^a-zA-Z0-9_], _)
|
||||
RESOURCE_INIT_CONT += " Q_INIT_RESOURCE($$resource_name);"
|
||||
}
|
||||
|
||||
RESOURCE_INIT_CONT += \
|
||||
"}"
|
||||
|
||||
write_file($$RESOURCE_INIT_CPP, RESOURCE_INIT_CONT)|error()
|
||||
}
|
||||
}
|
||||
|
||||
rcc.input = RESOURCES
|
||||
rcc.name = RCC ${QMAKE_FILE_IN}
|
||||
rcc.depend_command = $$QMAKE_RCC_DEP -list $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN}
|
||||
|
|
|
|||
|
|
@ -105,11 +105,21 @@ void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin);
|
|||
}; \
|
||||
static Static##PLUGIN##PluginInstance static##PLUGIN##Instance;
|
||||
|
||||
#if defined(QT_PLUGIN_RESOURCE_INIT_FUNCTION)
|
||||
# define QT_PLUGIN_RESOURCE_INIT \
|
||||
extern void QT_PLUGIN_RESOURCE_INIT_FUNCTION(); \
|
||||
QT_PLUGIN_RESOURCE_INIT_FUNCTION();
|
||||
#else
|
||||
# define QT_PLUGIN_RESOURCE_INIT
|
||||
#endif
|
||||
|
||||
#define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \
|
||||
{ \
|
||||
static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \
|
||||
if (!_instance) \
|
||||
if (!_instance) { \
|
||||
QT_PLUGIN_RESOURCE_INIT \
|
||||
_instance = new IMPLEMENTATION; \
|
||||
} \
|
||||
return _instance; \
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,2 @@
|
|||
CONFIG += testcase
|
||||
TARGET = tst_qresourceengine
|
||||
|
||||
QT = core testlib
|
||||
SOURCES = tst_qresourceengine.cpp
|
||||
RESOURCES += testqrc/test.qrc
|
||||
|
||||
qtPrepareTool(QMAKE_RCC, rcc, _DEP)
|
||||
runtime_resource.target = runtime_resource.rcc
|
||||
runtime_resource.depends = $$PWD/testqrc/test.qrc $$QMAKE_RCC_EXE
|
||||
runtime_resource.commands = $$QMAKE_RCC -root /runtime_resource/ -binary $$PWD/testqrc/test.qrc -o $${runtime_resource.target}
|
||||
QMAKE_EXTRA_TARGETS = runtime_resource
|
||||
PRE_TARGETDEPS += $${runtime_resource.target}
|
||||
QMAKE_DISTCLEAN += $${runtime_resource.target}
|
||||
|
||||
TESTDATA += \
|
||||
parentdir.txt \
|
||||
testqrc/*
|
||||
GENERATED_TESTDATA = $${runtime_resource.target}
|
||||
|
||||
android:!android-embedded {
|
||||
RESOURCES += android_testdata.qrc
|
||||
}
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = staticplugin qresourceengine_test.pro
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
CONFIG += testcase
|
||||
TARGET = tst_qresourceengine
|
||||
|
||||
QT = core testlib
|
||||
SOURCES = tst_qresourceengine.cpp
|
||||
RESOURCES += testqrc/test.qrc
|
||||
|
||||
qtPrepareTool(QMAKE_RCC, rcc, _DEP)
|
||||
runtime_resource.target = runtime_resource.rcc
|
||||
runtime_resource.depends = $$PWD/testqrc/test.qrc $$QMAKE_RCC_EXE
|
||||
runtime_resource.commands = $$QMAKE_RCC -root /runtime_resource/ -binary $$PWD/testqrc/test.qrc -o $${runtime_resource.target}
|
||||
QMAKE_EXTRA_TARGETS = runtime_resource
|
||||
PRE_TARGETDEPS += $${runtime_resource.target}
|
||||
QMAKE_DISTCLEAN += $${runtime_resource.target}
|
||||
|
||||
TESTDATA += \
|
||||
parentdir.txt \
|
||||
testqrc/*
|
||||
GENERATED_TESTDATA = $${runtime_resource.target}
|
||||
|
||||
android:!android-embedded {
|
||||
RESOURCES += android_testdata.qrc
|
||||
}
|
||||
|
||||
win32 {
|
||||
CONFIG(debug, debug|release): LIBS += -Lstaticplugin/debug
|
||||
else: LIBS += -Lstaticplugin/release
|
||||
} else {
|
||||
LIBS += -Lstaticplugin
|
||||
}
|
||||
LIBS += -lmoctestplugin
|
||||
|
|
@ -0,0 +1 @@
|
|||
moctestplugin_plugin_resources.cpp
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include <QObject>
|
||||
|
||||
class PluginClass : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.tests.moc" FILE "staticplugin.json")
|
||||
};
|
||||
|
||||
#include "main.moc"
|
||||
|
|
@ -0,0 +1 @@
|
|||
{ "Keys": [ "staticplugin" ] }
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
TEMPLATE = lib
|
||||
TARGET = moctestplugin
|
||||
CONFIG += plugin static
|
||||
SOURCES = main.cpp
|
||||
plugin_resource.files = main.cpp
|
||||
plugin_resource.prefix = /staticplugin
|
||||
RESOURCES += plugin_resource
|
||||
QT = core
|
||||
|
|
@ -56,6 +56,7 @@ private slots:
|
|||
void doubleSlashInRoot();
|
||||
void setLocale();
|
||||
void lastModified();
|
||||
void resourcesInStaticPlugins();
|
||||
|
||||
private:
|
||||
const QString m_runtimeResourceRcc;
|
||||
|
|
@ -118,6 +119,7 @@ void tst_QResourceEngine::checkStructure_data()
|
|||
<< QLatin1String("searchpath1")
|
||||
<< QLatin1String("searchpath2")
|
||||
<< QLatin1String("secondary_root")
|
||||
<< QLatin1String("staticplugin")
|
||||
<< QLatin1String("test")
|
||||
<< QLatin1String("withoutslashes");
|
||||
|
||||
|
|
@ -504,6 +506,16 @@ void tst_QResourceEngine::lastModified()
|
|||
}
|
||||
}
|
||||
|
||||
Q_IMPORT_PLUGIN(PluginClass)
|
||||
void tst_QResourceEngine::resourcesInStaticPlugins()
|
||||
{
|
||||
// We built a separate static plugin and attempted linking against
|
||||
// it. That should successfully register the resources linked into
|
||||
// the plugin via moc generated Q_INIT_RESOURCE calls in a
|
||||
// Q_CONSTRUCTOR_FUNCTION.
|
||||
QVERIFY(QFile::exists(":/staticplugin/main.cpp"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QResourceEngine)
|
||||
|
||||
#include "tst_qresourceengine.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue