Qt Creator插件

这里以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;

相关推荐
小杍随笔6 小时前
【Rust全栈项目接入UUID主键实战:从选型到PostgreSQL适配(含v7优化)】
开发语言·postgresql·rust
无限的鲜花15 小时前
反射(原创推荐)
java·开发语言
yongche_shi15 小时前
ragas官方文档中文版(五十)
开发语言·python·ai·ragas·如何评估和改进 rag 应用
一路向北he15 小时前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
AI行业学习17 小时前
Notepad++ 官方下载 + 完整安装 + 全套优化配置(2026最新)
开发语言·人工智能·python·前端框架·html·notepad++
大圣编程17 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
upgrador18 小时前
基础知识:C++ STL构造函数的左闭右开惯例及其实现原理
开发语言·c++
yoothey19 小时前
报废审批流规则引擎设计——责任链模式完整实现
linux·开发语言·bash
尘中远19 小时前
【Qwt 7.0 系列】坐标轴与刻度系统 —— 刻度引擎、网格、图例与刻度朝内
qt·数据可视化·qcustomplot·qwt·工业软件·科学绘图
geovindu19 小时前
python: Functional Options Pattern
开发语言·后端·python·设计模式·惯用法模式·函数式选项模式