QtResources: Difference between revisions
No edit summary |
(Remove Qt 4 specific parts, modernize.) |
||
(8 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
Written By : Girish Ramakrishnan, ForwardBias Technologies | Written By : Girish Ramakrishnan, ForwardBias Technologies | ||
= Overview = | = Overview = | ||
Qt Resources provide a platform-independent mechanism for embedding arbitrary binary data, including images and sounds, as part of an application executable. See | Qt Resources provide a platform-independent mechanism for embedding arbitrary binary data, including images and sounds, as part of an application executable. See [http://doc.qt.io/qt-6/resources.html Documentation] for more details. | ||
Implementation-wise, Qt resources have nothing to do with | Implementation-wise, Qt resources have nothing to do with [http://msdn.microsoft.com/en-us/library/ms648007.aspx RES files] on Windows or [http://en.wikipedia.org/wiki/Resource_fork resource forks] on macOS. | ||
= How it works = | = How it works = | ||
Line 17: | Line 12: | ||
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. | 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. | ||
< | <syntaxhighlight lang="C++"> | ||
#ifndef Q_CONSTRUCTOR_FUNCTION | #ifndef Q_CONSTRUCTOR_FUNCTION | ||
# define Q_CONSTRUCTOR_FUNCTION0(AFUNC) static const int AFUNC ## ''init_variable'' = AFUNC (); | # define Q_CONSTRUCTOR_FUNCTION0(AFUNC) static const int AFUNC ## ''init_variable'' = AFUNC (); | ||
# define Q_CONSTRUCTOR_FUNCTION(AFUNC) Q_CONSTRUCTOR_FUNCTION0(AFUNC) | # define Q_CONSTRUCTOR_FUNCTION(AFUNC) Q_CONSTRUCTOR_FUNCTION0(AFUNC) | ||
#endif | #endif | ||
</ | </syntaxhighlight> | ||
The tail end of a rcc generated C++ file contains something like: | The tail end of a rcc generated C++ file contains something like: | ||
< | <syntaxhighlight lang="C++"> | ||
int qInitResources_images() | int qInitResources_images() | ||
{ | { | ||
Line 33: | Line 28: | ||
Q_CONSTRUCTOR_FUNCTION(qInitResources_images) | Q_CONSTRUCTOR_FUNCTION(qInitResources_images) | ||
</ | </syntaxhighlight> | ||
Since static variables are initialized before main() is called, all resources are automatically registered before the actual program starts. | 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. | 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. | ||
Line 45: | Line 39: | ||
= Accessing resources = | = Accessing resources = | ||
QFile, QDir, QPixmap etc can all access | QFile, QDir, QPixmap etc can all access files in the resource system, though the access is read-only. File paths (QString) starting with a ":" are looked up in the resources. If URL's / QUrl are used, the scheme is "qrc". | ||
Latest revision as of 10:58, 24 May 2023
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 macOS.
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 files in the resource system, though the access is read-only. File paths (QString) starting with a ":" are looked up in the resources. If URL's / QUrl are used, the scheme is "qrc".