QtResources: Difference between revisions
(Fixed link. Qt4 comment) |
(clean-up) |
||
Line 1: | Line 1: | ||
Written By : Girish Ramakrishnan, ForwardBias Technologies | Written By : Girish Ramakrishnan, ForwardBias Technologies | ||
Revision as of 13:01, 24 March 2016
Written By : Girish Ramakrishnan, ForwardBias Technologies
Overview
Qt Resources provide a platform-independent mechanism for embedding arbitrary binary data, including images and sounds, as part of an application executable. See Documentation for more details.
Implementation-wise, Qt resources have nothing to do with RES files on Windows or resource forks on Mac OS X.
How it works
Resource files (i.e .qrc files) are XML files that specify the files that should be packaged into the final binary. The rcc resource compiler parses the XML and generates C/C++ code. This generated code contains a C struct that contains the raw bytes of the files listed in the .qrc. These C-structs are then collated in another C-struct to form a tree-like structure as files can be arranged in hierarchies. The details of the C-struct itself is not very interesting, so it's not discussed here. With the -compressed option to rcc, the data in the structs are compressed using zlib (by default, compression is off).
The C-structs need to be registered with Qt for Qt to know about them. The trick is that at the end of every rcc-generated C++ file, rcc places a call to qRegisterResourceData() which registers the C struct with the Qt resource system. By using the constructor function pattern, the qRegisterResourceData() gets invoked before main(). The constructor function pattern is the usage of a global static variable that initializes itself by calling a function.
#ifndef Q_CONSTRUCTOR_FUNCTION
# define Q_CONSTRUCTOR_FUNCTION0(AFUNC) static const int AFUNC ## ''init_variable'' = AFUNC ();
# define Q_CONSTRUCTOR_FUNCTION(AFUNC) Q_CONSTRUCTOR_FUNCTION0(AFUNC)
#endif
The tail end of a rcc generated C++ file contains something like:
int qInitResources_images()
{
qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data);
return 1;
}
Q_CONSTRUCTOR_FUNCTION(qInitResources_images)
Since static variables are initialized before main() is called, all resources are automatically registered before the actual program starts.
Q_INIT_RESOURCE
The constructor function trick works only if the generated C++ file is compiled and linked to the main application directly. If the resources are used in a static library and the library is then linked to the main application, the constructor function will never get called. This is the by nature of C/C++ linking- functions and variables in libraries that are unused/uncalled from the final program are removed from the final binary (optimized out). If the resources are in a shared library, then the constructor function does get invoked. However, most platforms load shared libraries on demand and the constructor function gets called only when the shared library gets loaded. The consequence is that any resources in plugins used by the main program will not be found by Qt until the plugin itself gets loaded - it's not a problem if the resources in the shared library are used only in the shared library. Note that accessing the resource inside a shared object in the main application does not trigger loading of the shared object since no symbol is exported by QRC system to trigger loading of the shared object.
A solution to the above problems is to use the Q_INIT_RESOURCE macro, placed at the beginning of main(), which ensures that the resources are linked into the application in the case of static linking, or forces the loading of the library in the case of dynamic linking.
Accessing resources
QFile, QDir, QPixmap etc can all access qrc files. In Qt4 all file access goes through QAbstractFileEngine. QResource registers a QAbstractFileSystemEngine derivative on startup that provides a valid file system engine (through QAbstractFileEngine::create) when a file name has the ":" prefix.