In the source code of the MetaDataQt plug-in, you can see a xxx. json file, which usually contains only one sentence: {& #160; & #160; & #160; Keys: [yyy]} we can guess that the Keys in this file should specify the key words related to the plug-in. How does this. json file work? First, let's get to know
<<<
MetaData of JSON and Qt plug-ins MetaData
In the source code of the Qt plug-in, you can see a xxx. json file, which usually contains only one sentence:
{
"Keys": ["yyy"]
}
We can guess that the "Keys" in this file should be a keyword related to the plug-in. How does this. json file work?
Let's first get to know about JSON.
JSON is a format for storing structured data. It has six basic data types:
Boolean bool, which can be true or false
Double numeric type
String type
Array type
Object Type
Null type
For more information, see Introduction to "JSON Support in Qt" in Qt Assistant.
A simple JSON document encoding a person, his/her age, address and phone numbers cocould look like:
{"FirstName": "John", # FirstName is the name of the variable (field), and John is the value of the variable "LastName": "Doe", "Age": 43, "Address": {"Street": "Downing Street 10", "City": "London", "Country": "Great Britain"}, "Phone numbers ": ["+ 44 1234567", "+ 44 2345678"]}
It is worth mentioning that when assigning values to fields of the array type in the. json file, brackets '[' and ']' should be used. when assigning values to fields of the object type
Enclose the braces '{' and '}'. common data is not required. Each. json file describes a JSON object, while a JSON object
Object type fields can be viewed as subjson objects (nesting of JSON objects ).
Looking back at the xxx. json file in the plug-in source code, we can find that the variable Keys is actually an array variable (because it is enclosed in square brackets when assigned values.
), But this array usually only has one element, that is, a plug-in generally only has one keyword. of course, you can also set multiple
Keyword.
. Json is mainly used to store metaData of the Qt plug-in. in Qt, there is a special class QJsonObject to describe a JSON.
QLibraryPrivate: metaData () returns a pointer to the QJsonObject class. this pointer can be used to access the metaData of the library corresponding to the QLibraryPrivate object;
QFactoryLoader: metaData () returns a QList List, which stores all libraries related to the QFactoryLoader object in sequence
(The metadata of the dynamic library is in front, and the metadata of the static library is in the back ).
In addition, the QJsonObject returned by QLibraryPrivate: metaData () usually contains a MetaData field, which is object-type data,
It can be seen as a sub-JSON object of the library metadata, and it corresponds to the content in the. json file. (The content in the. json file is only part of the metadata of a library)
Each QFactoryLoader object has a d-> iid member (d is the QFactoryLoaderPrivate instance associated with the QFactoryLoader object), which can be used to describe the plug-in type,
Each type of plug-in has an independent IID value, such as the platform input method plug-in should be org. qt-project.Qt.QPlatformInputContextFactoryInterface,
Platform plug-ins should be org. qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2 and so on.
<<<
Generation Process of QLibraryPrivate metaData (library metaData)
You need to use the Q_PLUGIN_METADATA macro to set the metadata of a plug-in when writing the Qt plug-in. However, in the source code of Qt, the macro is empty, so needless to say, this macro
Macros are parsed by MOC instead of the C ++ compiler. Let's see how MOC will deal with this macro. I found a very simple file and processed it with moc to see what was generated.
The content of the main. cpp file is as follows, where the Q_PLUGIN_METADATA macro is used.
# Include
# Include
# Include "QtMinimalInputMethodFrame. h "QT_BEGIN_NAMESPACEclass QtMinimalInputMethodFramePlugin: public QPlatformInputContextPlugin {Q_OBJECT Q_PLUGIN_METADATA (IID" org. qt-project.Qt.QPlatformInputContextFactoryInterface "FILE" qtminimal. json ") // specifies the IID and. json file public: QtMinimalInputMethodFrame * create (const QString &, const QStringList &) ;}; QtMinimalInputMethodFrame * metadata: create (const QString & system, const QStringList javasmlist) {Q_UNUSED (paramList); if (system. compare (system, QStringLiteral ("qtminimal"), Qt: CaseInsensitive) = 0) return new QtMinimalInputMethodFrame; return 0;} QT_END_NAMESPACE # include "main. moc"
The content of the qtminimal. json file is as follows:
{ "Keys": [ "qtminimal" ]}
Use "moc main. cpp moc_main.cpp" to generate the moc_main.cpp file. open it and find that some code is as follows:
...... Static const unsigned char qt_pluginMetaData [] = {'q', 'T', 'M', 'e', 'T', 'A', 'D ', 'A', 'T', 'A', '', //" QTMETADATA ", this string can be seen as the header of the Qt plug-in metadata, this keyword can be used to search for the positions 0x71, 0x62, 0x6a, 0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00, 0x03, 0x00, 0x49, 0x49, 0x44, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f, 0x72, 0x67, 0x2e, 0x71, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x51, 0x74, 0x2e, 0x51, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, 0x9b, 0x0c, 0x00, 0x00, 0x09, 0x00, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x1f, 0x00, 0x51, 0x74, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x6c, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x5a, 0x60, 0xa0, 0x00, 0x07, 0x00, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x05, 0x00, 0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x95, 0x16, 0x00, 0x00, 0x08, 0x00, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0x04, 0x00, 0x4b, 0x65, 0x79, 0x73, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x71, 0x74, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x6c, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00 };...... // pay attention to the macro QT_MOC_EXPORT_PLUGIN (QtMinimalInputMethodFramePlugin, QtMinimalInputMethodFramePlugin )......
In the above code, an array named qt_pluginMetaData is generated. you can guess from its name that the array is related to the metadata of the plug-in,
Display the array with characters. The result is:
QTMETADATA qbjs ^ A ^ @ ^ K ^ @ ^ [^ C ^ @ ^ @ ^ C ^ @ IID ^ @ 7 ^ @ org. qt-project.Qt.QPlatformInputContextFactoryInterface/IDD ^ @ <9b> ^ L ^ @ className ^ @ ^ _ ^ @ QtMinimalInputMethodFramePlugin/class name ^ @ Z '^ @ ^ G ^ @ version ^ @ ^ Q ^ @ ^ E ^ @ // version debug ^ @ <95> ^ V ^ @ ^ @ ^ H ^ @ // debugMetaData ^ @ 8 ^ @ ^ C ^ @ 4 ^ @ ^ T ^ C ^ @ ^ @ ^ D ^ @ // MetaDataKeys ^ @ ^ \ ^ @ ^ B ^ @ ^ X ^ @ qtminimal // Keys ^ @ <8b> ^ A ^ @ ^ L ^ @ T ^ @ ^ @ <98> ^ @ <88> ^ @
It can be seen that it already contains information such as IDD and Keys. Therefore, it can be determined that metadata related to the plug-in exists in this array.
The above code uses the QT_MOC_EXPORT_PLUGIN Macro, which defines two functions, qt_plugin_instance () and
Qt_plugin_query_metadata (). The former is used to return an instance of the plug-in class (QtMinimalInputMethodFramePlugin), and the latter is used
Returns the pointer to the array qt_pluginMetaData. Therefore, after the library is loaded, it can be obtained through the qt_plugin_query_metadata () function in the library.
Array of library metadata (binary data ).
# Define Q_PLUGIN_INSTANCE (IMPLEMENTATION) \ // This macro is used to return the static instance of a class whose class name is IMPLEMENTATION {\ static QT_PREPEND_NAMESPACE (QPointer)
_ Instance; \ if (! _ Instance) \ _ instance = new IMPLEMENTATION; \ return _ instance ;\}# if defined (QT_STATICPLUGIN) // This part is the macro used for static compilation, no matter how it is # define QT_MOC_EXPORT_PLUGIN (PLUGINCLASS, PLUGINCLASSNAME) \ static QT_PREPEND_NAMESPACE (QObject) * qt_plugin_instance _ # PLUGINCLASSNAME () \ Q_PLUGIN_INSTANCE) \ static const char * prop _ # PLUGINCLASSNAME () {return (const char *) qt_pluginMetaData;} \ const QT_PREPEND_NAMESPACE (QStaticPlugin) qt_static_plugin _ # PLUGINCLASSNAME () {\ QT_PREPEND_NAMESPACE (QStaticPlugin) plugin = {qt_plugin_instance _ # PLUGINCLASSNAME, qt_plugin_query_metadata _ # PLUGINCLASSNAME}; \ return plugin; \}# else // This part is the macro used for dynamic compilation # define QT_MOC_EXPORT_PLUGIN (PLUGINCLASS, PLUGINCLASSNAME) \ Q_EXTERN_C Q_DECL_EXPORT \ const char * qt_plugin_query_metadata () \\// this function returns a pointer pointing to the meta information array {return (const char *) qt_pluginMetaData;} \ Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE (QObject) * qt_plugin_instance () \ This function returns a static instance Q_PLUGIN_INSTANCE (PLUGINCLASS) of the inclass class. # endif
Although we can use the qt_plugin_query_metadata () function to obtain the library metadata array (binary data), we also need
Convert binary data into a QJsonObject object to facilitate access to each field in the program. QLibraryPrivate class has one
The static member function fromRawMetaData can be used to construct a QJsonDocument object from binary data,
The object () method of the QJsonDocument object can return the required QJsonObject (library metadata ).
With these guesses, the metaData member of the QLibraryPrivate class is set as follows:
After a library file is loaded, resolve the qt_plugin_query_metadata () symbol in the library and obtain the pointer of the array qt_pluginMetaData through it,
Call the fromRawMetaData method of the QLibraryPrivate class to convert the meta information of binary storage to a QJsonObject object, and assign a value to the object.
To the metaData member of the QLibraryPrivate class.
Now the question is, where is the metaData of QLibraryPrivate and who sets it?
When you use the isPlugin () method of the QLibraryPrivate class for the first time to check whether a library is a plug-in, this method internally calls QLibraryPrivate: updatePluginState ().
Bool QLibraryPrivate: isPlugin () {if (pluginState = MightBeAPlugin) // pluginState will be initialized to MightBeAPlugin updatePluginState (); return pluginState = IsAPlugin ;}
In the QLibraryPrivate: updatePluginState () function, you need to read the metaData information of the QLibraryPrivate class to check whether a library is a plug-in, and metaData is also at this moment.
Set. From this function, we can also see that only the Qt plug-in has metaData, but the normal library does not (I cannot guarantee this, however, from the code of the following function, we should
Yes ).
Void QLibraryPrivate: updatePluginState () {errorString. clear (); if (pluginState! = MightBeAPlugin) return; // if the pluginState status is determined, return bool success = false; # if defined (Q_ OS _UNIX )&&! Defined (Q_ OS _MAC) if (fileName. endsWith (QLatin1String (". debug ") {// refuse to load a file that ends in. debug // these are the debug symbols from the libraries // the problem is that they are valid shared library files // and dlopen is known to crash while opening them // pretend we didn' t see the file errorString = QLibrary:: tr ("The shared library was not found. "); pluginState = IsNotAPlugin; r Eturn ;}# endif // Set metaData here. Both findPatternUnloaded () and qt_get_metadata () functions set metaData if (! PHnd) {// if the library has not been loaded, (pHnd = NULL indicates that the library has not been loaded), call the findPatternUnloaded function, which will open the corresponding library file in the room, read the content and find the Header ("QTMETADATA") of the Qt plug-in metadata. // if the Header is found, parse the metadata. The advantage of this method is that it can obtain its metadata without loading the database. // Scan for the plugin metadata without loading success = findPatternUnloaded (fileName, this);} else {// if the library has been loaded, call qt_get_metadata to obtain the metadata. // QtPluginQueryVerificationDataFunction is a function pointer type. its specific type is char * (*) (). It returns // A character pointer (pointing to a binary array). To be precise, he should return the pointer to the qt_pluginMetaData array mentioned above. // Library is already loaded (probably via QLibrary) // simply get the target function and call it. export getMetaData = NULL; getMetaData = (partial) resolve ("qt_plugin_query_metadata"); // The token symbol resolve in the above row comes out of success = qt_get_metadata (getMetaData, this );} if (! Success) {// if the metadata fails to be obtained, that is, if the current library does not have metadata, set pluginState to IsNotAPlugin, which indicates a non-Qt plug-in. // Because the current library does not have metadata, it is considered not a Qt plug-in. does this mean that only the Qt plug-in has metadata, but the common library does not? If (errorString. isEmpty () {if (fileName. isEmpty () errorString = QLibrary: tr ("The shared library was not found. "); else errorString = QLibrary: tr (" The file '% 1' is not a valid Qt plugin. "). arg (fileName);} pluginState = IsNotAPlugin; return;} pluginState = IsNotAPlugin; // be pessimistic // if the metadata is obtained successfully, check whether the version number meets the requirements. if the version number is correct, set pluginState to IsAPlugin, which indicates that the Qt plug-in uint qt_version = (uint) metaData. value (QLatin1String ("version ")). toDouble (); bool debug = metaData. value (QLatin1String ("debug ")). toBool (); if (qt_version & 0x00ff00)> (QT_VERSION & 0x00ff00) | (qt_version & 0xff0000 )! = (QT_VERSION & 0xff0000) {if (qt_debug_component () {qWarning ("In % s: \ n" "Plugin uses incompatible Qt library (% d. % d. % d) [% s] ", (const char *) QFile: encodeName (fileName), (qt_version & 0xff0000)> 16, (qt_version & 0xff00)> 8, qt_version & 0xff, debug? "Debug": "release");} errorString = QLibrary: tr ("The plugin '% 1' uses incompatible Qt library. (% 2.% 3.% 4) [% 5] "). arg (fileName ). arg (qt_version & 0xff0000)> 16 ). arg (qt_version & 0xff00)> 8 ). arg (qt_version & 0xff ). arg (debug? QLatin1String ("debug"): QLatin1String ("release"); # ifndef QT_NO_DEBUG_PLUGIN_CHECK} else if (debug! = QLIBRARY_AS_DEBUG) {// don't issue a qWarning since we will hopefully find a non-debug? -- Sam errorString = QLibrary: tr ("The plugin '% 1' uses incompatible Qt library. "" (Cannot mix debug and release libraries .) "). arg (fileName); # endif} else {pluginState = IsAPlugin ;}}