这里以Qt Creator 4.15.2版本的源码为示例进行分析
源码结构如下,为了追溯其插件加载过程,从main.cpp入手
Qt Creator的插件目录,生成的插件,好几十个呢
Qt Creator插件的读取
int main(int argc, char **argv)中以下代码创建插件的管理
PluginManager pluginManager;
PluginManager::setPluginIID(QLatin1String("org.qt-project.Qt.QtCreatorPlugin"));
PluginManager::setGlobalSettings(globalSettings);
PluginManager::setSettings(settings);
int main(int argc, char **argv)中以下设置插件的读取目录,读取所有插件信息
const QStringList pluginPaths = getPluginPaths() + options.customPluginPaths;
PluginManager::setPluginPaths(pluginPaths);//读取插件目录下的插件
从 PluginManager::setPluginPaths(pluginPaths)调用追溯到如下
void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
{
qCDebug(pluginLog) << "Plugin search paths:" << paths;
qCDebug(pluginLog) << "Required IID:" << pluginIID;
pluginPaths = paths;
readSettings();
readPluginPaths();
}
继续追溯void PluginManagerPrivate::readPluginPaths()
for (const QString &pluginFile : pluginFiles(pluginPaths)) {
PluginSpec *spec = PluginSpec::read(pluginFile);
PluginSpec *PluginSpec::read(const QString &filePath)
{
auto spec = new PluginSpec;
if (!spec->d->read(filePath)) { // not a Qt Creator plugin
delete spec;
return nullptr;
}
return spec;
}
其中bool PluginSpecPrivate::read(const QString &fileName)方法读取了插件的基本信息
Qt Creator 加载插件
从main函数中的 PluginManager::loadPlugins();开始追溯插件的加载
void PluginManagerPrivate::loadPlugins()
{
//所有插件都会从loaded-->initialized-->running
const QVector<PluginSpec *> queue = loadQueue();
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsLoading);
for (PluginSpec *spec : queue)
loadPlugin(spec, PluginSpec::Loaded);
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsInitializing);
for (PluginSpec *spec : queue)
loadPlugin(spec, PluginSpec::Initialized);
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing);
Utils::reverseForeach(queue, [this](PluginSpec *spec) {
loadPlugin(spec, PluginSpec::Running);//从这里开始加载插件...step2
if (spec->state() == PluginSpec::Running) {
delayedInitializeQueue.push(spec);
} else {
// Plugin initialization failed, so cleanup after it
spec->d->kill();
}
});
...
}
插件加载的几个主要步骤,load, initialize, run
在 void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState)中
switch (destState) {
case PluginSpec::Loaded:
profilingReport(">loadLibrary", spec);
spec->d->loadLibrary();
profilingReport("<loadLibrary", spec);
break;
case PluginSpec::Initialized:
profilingReport(">initializePlugin", spec);
spec->d->initializePlugin();
profilingReport("<initializePlugin", spec);
break;
case PluginSpec::Stopped:
profilingReport(">stop", spec);
if (spec->d->stop() == IPlugin::AsynchronousShutdown) {
asynchronousPlugins << spec;
connect(spec->plugin(), &IPlugin::asynchronousShutdownFinished,
this, &PluginManagerPrivate::asyncShutdownFinished);
}
profilingReport("<stop", spec);
break;
default:
break;
}
继续追溯bool PluginSpecPrivate::loadLibrary()
if (!loader.load()) {//这里是加载插件
hasError = true;
errorString = QDir::toNativeSeparators(filePath)
+ QString::fromLatin1(": ") + loader.errorString();
return false;
}
Qt Creator插件
合格的插件需要继承自IPlugin抽象类
以CppEditorPlugin为例
class CppEditorPlugin : public ExtensionSystem::IPlugin
看一下IPlugin类
#pragma once
#include "extensionsystem_global.h"
#include <QObject>
namespace ExtensionSystem {
namespace Internal {
class IPluginPrivate;
class PluginSpecPrivate;
}
class PluginManager;
class PluginSpec;
class EXTENSIONSYSTEM_EXPORT IPlugin : public QObject
{
Q_OBJECT
public:
enum ShutdownFlag {
SynchronousShutdown,
AsynchronousShutdown
};
IPlugin();
~IPlugin() override;
virtual bool initialize(const QStringList &arguments, QString *errorString) = 0;
virtual void extensionsInitialized() {}
virtual bool delayedInitialize() { return false; }
virtual ShutdownFlag aboutToShutdown() { return SynchronousShutdown; }
virtual QObject *remoteCommand(const QStringList & /* options */,
const QString & /* workingDirectory */,
const QStringList & /* arguments */) { return nullptr; }
virtual QVector<QObject *> createTestObjects() const;
PluginSpec *pluginSpec() const;
signals:
void asynchronousShutdownFinished();
private:
Internal::IPluginPrivate *d;
friend class Internal::PluginSpecPrivate;
};
} // namespace ExtensionSystem
实现具体的插件类时,以下方法是必须重写的
virtual bool initialize(const QStringList &arguments, QString *errorString) = 0;