Qt Creator源码分析系列——extensionsystem::PluginManager

在这里插入图片描述

PluginManager

ExtensionSystem命名空间提供了属于核心插件系统的类。 基本扩展系统包含插件管理器及其支持类,以及必须由插件提供程序实现的IPlugin接口。
ExtensionSystem::PluginManager类实现了管理插件,插件的生命周期及其注册对象的核心插件系统。
插件管理器用于以下任务:管理插件及其状态和操纵“公共对象池”。

管理插件

插件由XML描述符文件和包含Qt插件的库组成,该Qt插件必须从IPlugin类派生,并且IID为“ org.qt-project.Qt.QtCreatorPlugin”。插件管理器用于设置文件系统目录列表,以搜索插件,检索有关这些插件状态的信息并加载它们。 通常,应用程序创建一个PluginManager实例并启动加载。
'plugins’和subdirs将在插件中搜索,loadPlugins尝试加载所有的插件。

PluginManager::setPluginPaths(QStringList("plugins"));
PluginManager::loadPlugins();

此外,可以直接访问插件规范(描述符文件中的信息),插件实例(通过PluginSpec)及其状态。

操纵“公共对象池”

插件(以及其他所有人)可以将对象添加到位于插件管理器中的公共“池”中。池中的对象必须派生自QObject,没有其他先决条件。 可以通过getObject和getObjectByName函数从对象池中检索对象。
每当对象池的状态更改时,插件管理器都会发出相应的信号。 对象池的常见用例是插件(或应用程序)为其他插件提供“扩展点”,这是可以实现并添加到对象池的类/接口。 提供扩展点的插件在对象池中查找类/接口的实现。

// Plugin A provides a "MimeTypeHandler" extension point
// in plugin B:
MyMimeTypeHandler *handler = new MyMimeTypeHandler();
PluginManager::instance()->addObject(handler);
// In plugin A:
MimeTypeHandler *mimeHandler = PluginManager::getObject<MimeTypeHandler>();

ExtensionSystem :: Invoker类模板为使用“软”扩展点提供了“语法糖”,这些扩展点可能由池中的对象提供,也可能不由池中的对象提供。 这种方法既不需要将“用户”插件链接到“提供者”插件,也不需要公共共享头文件。 公开的接口由对象池中“提供者”对象的可调用函数隐式给出。
ExtensionSystem :: invoke函数模板封装了ExtensionSystem :: Invoker构造,用于不检查调用成功的常见情况。

// In the "provide" plugin A:
namespace PluginA {
	class SomeProvider : public QObject
    {
        Q_OBJECT
    public:
        Q_INVOKABLE QString doit(const QString &msg, int n) {
        {
        	qDebug() << "I AM DOING IT " << msg;
            return QString::number(n);
        }
    };
} // namespace PluginA


// In the "user" plugin B:
int someFuntionUsingPluginA()
{
	using namespace ExtensionSystem;
    QObject *target = PluginManager::getObjectByClassName("PluginA::SomeProvider");
	if (target) {
    	// Some random argument.
        QString msg = "REALLY.";
        // Plain function call, no return value.
        invoke<void>(target, "doit", msg, 2);
        // Plain function with no return value.
        qDebug() << "Result: " << invoke<QString>(target, "doit", msg, 21);
        // Record success of function call with return value.
        Invoker<QString> in1(target, "doit", msg, 21);
        qDebug() << "Success: (expected)" << in1.wasSuccessful();
        // Try to invoke a non-existing function.
        Invoker<QString> in2(target, "doitWrong", msg, 22);
        qDebug() << "Success (not expected):" << in2.wasSuccessful();
    } else {
         // We have to cope with plugin A's absence.
    }
};

传递给invoke调用的参数类型由参数本身推导得出,并且必须与被调用函数exactly的参数类型相匹配。 没有转换甚至整数提升都不适用,因此要使用long参数显式地使用long(43)等调用函数。对象池操作函数是线程安全的。

class EXTENSIONSYSTEM_EXPORT PluginManager : public QObject
{
    Q_OBJECT
public:
    static PluginManager *instance();
    PluginManager();
    ~PluginManager() override;
    // Object pool operations 对象池操作
    // 将对象obj添加到对象池
    static void addObject(QObject *obj) { d->addObject(obj); }
    // 从对象池中删除对象
    static void removeObject(QObject *obj) { d->removeObject(obj); }
    // 检索池中所有对象的列表
    static QVector<QObject *> allObjects() { return d->allObjects; }
    static QReadWriteLock *listLock() { return &d->m_lock; }
    // This is useful for soft dependencies using pure interfaces.
    template <typename T> static T *getObject()
    {
        QReadLocker lock(listLock());
        QVector<QObject *> all = allObjects();
        foreach (QObject *obj, all) {
            if (T *result = qobject_cast<T *>(obj))
                return result;
        }
        return nullptr;
    }
    template <typename T, typename Predicate> static T *getObject(Predicate predicate)
    {
        QReadLocker lock(listLock());
        QVector<QObject *> all = allObjects();
        foreach (QObject *obj, all) {
            if (T *result = qobject_cast<T *>(obj))
                if (predicate(result))
                    return result;
        }
        return 0;
    }
    // 从对象池中检索一个具有名称的对象。
    static QObject *getObjectByName(const QString &name) 
    {
    	QReadLocker lock(&d->m_lock);
    	return Utils::findOrDefault(allObjects(), [&name](const QObject *obj) {
        	return obj->objectName() == name;
    	});
    }
    // Plugin operations 插件操作
    // 返回加载顺序的插件列表。
    static QVector<PluginSpec *> loadQueue() { return d->loadQueue(); }
    // 尝试加载在设置插件搜索路径时先前找到的所有插件
    static void loadPlugins() { d->loadPlugins(); }
    // 路径列表是插件管理器搜索插件的路径
    static QStringList pluginPaths() { return d->pluginPaths; }
    // 设置插件搜索路径,即插件管理器在其中查找插件说明的文件系统路径。 在所有给定的路径及其子目录树中搜索插件xml描述文件。
    static void setPluginPaths(const QStringList &paths) { d->setPluginPaths(paths); }
    // 有效插件必须具有的IID。
    static QString pluginIID() { return d->pluginIID; }
    // 设置有效插件必须具有的IID。 仅加载具有此IID的插件,而其他插件则被忽略。
    static void setPluginIID(const QString &iid) { d->pluginIID = iid; }
    // 在插件搜索路径中找到的所有插件规范的列表。 此列表在setPluginPaths调用之后直接有效。 插件规范包含来自插件的xml描述文件的信息以及插件的当前状态。 如果插件库已经成功加载,则插件规范也将引用创建的插件实例。
    static const QVector<PluginSpec *> plugins() { return d->pluginSpecs; }
    static QHash<QString, QVector<PluginSpec *>> pluginCollections() { return d->pluginCategories; }
    // 如果任何插件即使启用也有错误,则返回true。
    static bool hasError()
    {
    	return Utils::anyOf(plugins(), [](PluginSpec *spec) {
        // only show errors on startup if plugin is enabled.
        	return spec->hasError() && spec->isEffectivelyEnabled();
    	});
	}
    static const QStringList allErrors()
    {
    	return Utils::transform<QStringList>(Utils::filtered(plugins(), [](const PluginSpec *spec) {
        	return spec->hasError() && spec->isEffectivelyEnabled();
    	}), [](const PluginSpec *spec) {
        	return spec->name().append(": ").append(spec->errorString());
    	});
	}
    static QSet<PluginSpec *> pluginsRequiringPlugin(PluginSpec *spec);
    static QSet<PluginSpec *> pluginsRequiredByPlugin(PluginSpec *spec);
    static void checkForProblematicPlugins()
    {
		d->checkForProblematicPlugins();
	}
    // Settings
    // 定义用户特定的设置以用于有关已启用和已禁用插件的信息。 需要在使用setPluginPaths设置插件搜索路径之前进行设置。
    static void setSettings(QSettings *settings) { d->setSettings(settings); }
    // 返回特定于用户的设置,以用于有关已启用的禁用插件的信息。
    static QSettings *settings() { return d->settings; }
    // 定义全局(独立于用户)设置,以用于有关默认禁用的插件的信息。 需要在使用setPluginPaths设置插件搜索路径之前进行设置。
    static void setGlobalSettings(QSettings *settings) { d->setGlobalSettings(settings); }
    // 返回用于与默认禁用插件有关的信息的全局(独立于用户)设置。
    static QSettings *globalSettings() { return d->globalSettings; }
    static void writeSettings() { d->writeSettings(); }
    // command line arguments
    // 解析后剩下的参数(既不是启动参数也不是插件参数)。 通常,这是要打开的文件列表。
    static QStringList arguments() { return d->arguments; }
    // 自动重新启动应用程序时应使用的参数。 这包括用于启用或禁用插件的插件管理器相关选项,但不包括其他选项,例如arguments返回的参数和传递给parseOptions方法的appOptions。
    static QStringList argumentsForRestart() { return d->argumentsForRestart; }
    static bool parseOptions(const QStringList &args, const QMap<QString, bool> &appOptions,
        QMap<QString, QString> *foundAppOptions, QString *errorString);
    static void formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation);
    static void formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation);
    // 格式化用于命令行帮助的插件规范的版本。
    static void formatPluginVersions(QTextStream &str)
    {	foreach (PluginSpec *ps, d->pluginSpecs)
        	str << "  " << ps->name() << ' ' << ps->version() << ' ' << ps->description() <<  '\n'; }
    static QString serializedArguments();
    static bool testRunRequested() { return !d->testSpecs.empty(); }
    // 创建一个分析条目,如果激活了分析,则显示经过的时间。
    static void profilingReport(const char *what, const PluginSpec *spec = nullptr) { d->profilingReport(what, spec); }
    static QString platformName()
    {
		static const QString result = getPlatformName() + " (" + QSysInfo::prettyProductName() + ')';
    	return result;
	}
    static bool isInitializationDone() { return d->m_isInitializationDone; }
    void remoteArguments(const QString &serializedArguments, QObject *socket);
    // 关闭并删除所有插件。
    void shutdown() { d->shutdown(); }
    QString systemInformation() const;
signals:
    void objectAdded(QObject *obj);
    void aboutToRemoveObject(QObject *obj);
    void pluginsChanged();
    void initializationDone();
    void testsFinished(int failedTests);
    friend class Internal::PluginManagerPrivate;
};
static Internal::PluginManagerPrivate *d = nullptr;
static PluginManager *m_instance = nullptr;

从PluginManager类的实现文件中可以看出插件管理依赖上述定义的PluginManagerPrivate和PluginManager两个静态指针。

// 创建一个插件管理器, 每个应用程序只能执行一次
PluginManager::PluginManager()
{
    m_instance = this;
    d = new PluginManagerPrivate(this);
}
// 获取唯一的插件管理器实例
PluginManager *PluginManager::instance()
{
    return m_instance;
}

void PluginManager::addObject(QObject *obj)将对象obj添加到对象池,以便可以按类型再次从池中检索它。 插件管理器不执行任何内存管理-添加的对象必须从池中删除,并由负责该对象的任何人手动删除。 发出objectAdded()信号。
将obj添加到对象池发送信号的函数void PluginManager::objectAdded(QObject *obj)

void PluginManager::removeObject(QObject *obj)发出aboutToRemoveObject()并从对象池中删除对象obj。

QVector<QObject *> PluginManager::allObjects()检索池中所有对象的列表,未过滤。 通常,客户端不需要调用此函数。

void PluginManager::loadPlugins()尝试加载在设置插件搜索路径时先前找到的所有插件。 插件的插件规格可用于检索有关单个插件的错误和状态信息。

QSet<PluginSpec *> PluginManager::pluginsRequiringPlugin(PluginSpec *spec)返回所有需要加载规范的插件。 递归为依赖项。

QSet<PluginSpec *> PluginManager::pluginsRequiringPlugin(PluginSpec *spec)
{
    QSet<PluginSpec *> dependingPlugins({spec});
    // recursively add plugins that depend on plugins that.... that depend on spec
    foreach (PluginSpec *spec, d->loadQueue()) {
        if (spec->requiresAny(dependingPlugins))
            dependingPlugins.insert(spec);
    }
    dependingPlugins.remove(spec);
    return dependingPlugins;
}

返回所有需要加载spec的插件。 递归为依赖项。 //广度遍历

QSet<PluginSpec *> PluginManager::pluginsRequiredByPlugin(PluginSpec *spec)
{
    QSet<PluginSpec *> recursiveDependencies;
    recursiveDependencies.insert(spec);
    std::queue<PluginSpec *> queue;
    queue.push(spec);
    while (!queue.empty()) {
        PluginSpec *checkSpec = queue.front();
        queue.pop();
        const QHash<PluginDependency, PluginSpec *> deps = checkSpec->dependencySpecs();
        for (auto depIt = deps.cbegin(), end = deps.cend(); depIt != end; ++depIt) {
            if (depIt.key().type != PluginDependency::Required)
                continue;
            PluginSpec *depSpec = depIt.value();
            if (!recursiveDependencies.contains(depSpec)) {
                recursiveDependencies.insert(depSpec);
                queue.push(depSpec);
            }
        }
    }
    recursiveDependencies.remove(spec);
    return recursiveDependencies;
}

序列化插件选项和参数以通过QtSingleApplication发送单个字符串:":myplugin|-option1|-option2|:arguments|argument1|argument2"。作为由带有冒号的关键字开头的列表的列表,参数是最后的。

QString PluginManager::serializedArguments()
{
    const QChar separator = QLatin1Char('|');
    QString rc;
    foreach (const PluginSpec *ps, plugins()) {
        if (!ps->arguments().isEmpty()) {
            if (!rc.isEmpty())
                rc += separator;
            rc += QLatin1Char(':');
            rc += ps->name();
            rc += separator;
            rc +=  ps->arguments().join(separator);
        }
    }
    if (!rc.isEmpty())
        rc += separator;
    rc += QLatin1String(pwdKeywordC) + separator + QDir::currentPath();
    if (!d->arguments.isEmpty()) {
        if (!rc.isEmpty())
            rc += separator;
        rc += QLatin1String(argumentKeywordC);
        foreach (const QString &argument, d->arguments)
            rc += separator + argument;
    }
    return rc;
}

在\ a args中获取命令行选项的列表并进行解析。 插件管理器本身可能会直接自行处理一些选项(-noload ),并将插件注册的选项添加到其插件规格中。 调用者(应用程序)可以通过\ a appOptions列表为选项注册自己,其中包含成对的“选项字符串”和一个布尔值,用于指示选项是否需要参数。 应用程序选项始终会覆盖任何插件的选项。
对于找到的任何应用程序选项,\ a foundAppOptions都设置为成对的(“选项字符串”,“参数”)。 可以通过arguments()函数来检索未处理的命令行选项。 如果发生错误(例如缺少要求一个选项的参数),则\ a errorString包含该错误的描述性消息。 如果有错误,则返回。

bool PluginManager::parseOptions(const QStringList &args,
    const QMap<QString, bool> &appOptions,
    QMap<QString, QString> *foundAppOptions,
    QString *errorString)
{
    OptionsParser options(args, appOptions, foundAppOptions, errorString, d);
    return options.parse();
}

格式化插件管理器的启动选项以获取命令行帮助

void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation)
{
    formatOption(str, QLatin1String(OptionsParser::LOAD_OPTION),
                 QLatin1String("plugin"), QLatin1String("Load <plugin> and all plugins that it requires"),
                 optionIndentation, descriptionIndentation);
    formatOption(str, QLatin1String(OptionsParser::LOAD_OPTION) + QLatin1String(" all"),
                 QString(), QLatin1String("Load all available plugins"),
                 optionIndentation, descriptionIndentation);
    formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION),
                 QLatin1String("plugin"), QLatin1String("Do not load <plugin> and all plugins that require it"),
                 optionIndentation, descriptionIndentation);
    formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION) + QLatin1String(" all"),
                 QString(), QString::fromLatin1("Do not load any plugin (useful when "
                                                "followed by one or more \"%1\" arguments)")
                 .arg(QLatin1String(OptionsParser::LOAD_OPTION)),
                 optionIndentation, descriptionIndentation);
    formatOption(str, QLatin1String(OptionsParser::PROFILE_OPTION),
                 QString(), QLatin1String("Profile plugin loading"),
                 optionIndentation, descriptionIndentation);
#ifdef WITH_TESTS
    formatOption(str, QString::fromLatin1(OptionsParser::TEST_OPTION)
                 + QLatin1String(" <plugin>[,testfunction[:testdata]]..."), QString(),
                 QLatin1String("Run plugin's tests (by default a separate settings path is used)"),
                 optionIndentation, descriptionIndentation);
    formatOption(str, QString::fromLatin1(OptionsParser::TEST_OPTION) + QLatin1String(" all"),
                 QString(), QLatin1String("Run tests from all plugins"),
                 optionIndentation, descriptionIndentation);
    formatOption(str, QString::fromLatin1(OptionsParser::NOTEST_OPTION),
                 QLatin1String("plugin"), QLatin1String("Exclude all of the plugin's tests from the test run"),
                 optionIndentation, descriptionIndentation);
#endif
}

格式化插件规范的插件选项以获取命令行帮助。

void PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation)
{
    // Check plugins for options
    foreach (PluginSpec *ps, d->pluginSpecs) {
        const PluginSpec::PluginArgumentDescriptions pargs = ps->argumentDescriptions();
        if (!pargs.empty()) {
            str << "\nPlugin: " <<  ps->name() << '\n';
            foreach (PluginArgumentDescription pad, pargs)
                formatOption(str, pad.name, pad.parameter, pad.description, optionIndentation, descriptionIndentation);
        }
    }
}

格式化用于命令行帮助的插件规范的版本。

void PluginManager::formatPluginVersions(QTextStream &str)
{
    foreach (PluginSpec *ps, d->pluginSpecs)
        str << "  " << ps->name() << ' ' << ps->version() << ' ' << ps->description() <<  '\n';
}

解析由serializedArguments()const编码的选项,并将它们与参数一起传递给相应的插件。完成操作(例如,文档已关闭)以支持-block标志时,将传递套接字以断开对等方。

void PluginManager::remoteArguments(const QString &serializedArgument, QObject *socket)
{
    if (serializedArgument.isEmpty())
        return;
    QStringList serializedArguments = serializedArgument.split(QLatin1Char('|'));
    const QStringList pwdValue = subList(serializedArguments, QLatin1String(pwdKeywordC));
    const QString workingDirectory = pwdValue.isEmpty() ? QString() : pwdValue.first();
    const QStringList arguments = subList(serializedArguments, QLatin1String(argumentKeywordC));
    foreach (const PluginSpec *ps, plugins()) {
        if (ps->state() == PluginSpec::Running) {
            const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name());
            QObject *socketParent = ps->plugin()->remoteCommand(pluginOptions, workingDirectory,
                                                                arguments);
            if (socketParent && socket) {
                socket->setParent(socketParent);
                socket = nullptr;
            }
        }
    }
    if (socket)
        delete socket;
}

PluginManagerPrivate

class EXTENSIONSYSTEM_EXPORT PluginManagerPrivate : public QObject
{
    Q_OBJECT
public:
    PluginManagerPrivate(PluginManager *pluginManager) : q(pluginManager) {}
    ~PluginManagerPrivate() override;
    // Object pool operations 对象池操作
    void addObject(QObject *obj);
    void removeObject(QObject *obj);
    // Plugin operations 插件操作
    void checkForProblematicPlugins();
    void loadPlugins();
    void shutdown();
    void setPluginPaths(const QStringList &paths);
    QVector<ExtensionSystem::PluginSpec *> loadQueue();
    void loadPlugin(PluginSpec *spec, PluginSpec::State destState);
    void resolveDependencies();
    void enableDependenciesIndirectly();
    void initProfiling();
    void profilingSummary() const;
    void profilingReport(const char *what, const PluginSpec *spec = nullptr);
    void setSettings(QSettings *settings);
    void setGlobalSettings(QSettings *settings);
    void readSettings();
    void writeSettings();
    class TestSpec {
    public:
        TestSpec(PluginSpec *pluginSpec, const QStringList &testFunctionsOrObjects = QStringList())
            : pluginSpec(pluginSpec)
            , testFunctionsOrObjects(testFunctionsOrObjects)
        {}
        PluginSpec *pluginSpec = nullptr;
        QStringList testFunctionsOrObjects;
    };
    bool containsTestSpec(PluginSpec *pluginSpec) const
    {
        return Utils::contains(testSpecs, [pluginSpec](const TestSpec &s) { return s.pluginSpec == pluginSpec; });
    }
    void removeTestSpec(PluginSpec *pluginSpec)
    {
        testSpecs = Utils::filtered(testSpecs, [pluginSpec](const TestSpec &s) { return s.pluginSpec != pluginSpec; });
    }
    QHash<QString, QVector<PluginSpec *>> pluginCategories;
    QVector<PluginSpec *> pluginSpecs;
    std::vector<TestSpec> testSpecs;
    QStringList pluginPaths;
    QString pluginIID;
    QVector<QObject *> allObjects;      // ### make this a QVector<QPointer<QObject> > > ?
    QStringList defaultDisabledPlugins; // Plugins/Ignored from install settings
    QStringList defaultEnabledPlugins; // Plugins/ForceEnabled from install settings
    QStringList disabledPlugins;
    QStringList forceEnabledPlugins;
    // delayed initialization
    QTimer *delayedInitializeTimer = nullptr;
    std::queue<PluginSpec *> delayedInitializeQueue;
    // ansynchronous shutdown
    QSet<PluginSpec *> asynchronousPlugins;  // plugins that have requested async shutdown
    QEventLoop *shutdownEventLoop = nullptr; // used for async shutdown
    QStringList arguments;
    QStringList argumentsForRestart;
    QScopedPointer<QElapsedTimer> m_profileTimer;
    QHash<const PluginSpec *, int> m_profileTotal;
    int m_profileElapsedMS = 0;
    unsigned m_profilingVerbosity = 0;
    QSettings *settings = nullptr;
    QSettings *globalSettings = nullptr;
    // Look in argument descriptions of the specs for the option.
    PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
    PluginSpec *pluginByName(const QString &name) const;
    // used by tests
    static PluginSpec *createSpec() { return new PluginSpec(); }
    static PluginSpecPrivate *privateSpec(PluginSpec *spec) { return spec->d; }
    mutable QReadWriteLock m_lock;
    bool m_isInitializationDone = false;
private:
    PluginManager *q;
    void nextDelayedInitialize();
    void asyncShutdownFinished();
    void readPluginPaths();
    bool loadQueue(PluginSpec *spec,
                   QVector<ExtensionSystem::PluginSpec *> &queue,
                   QVector<ExtensionSystem::PluginSpec *> &circularityCheckQueue);
    void stopAll();
    void deleteAll();
#ifdef WITH_TESTS
    void startTests();
#endif
};

对象池操作

QScopedPointer<QElapsedTimer> m_profileTimer
QElapsedTimer类提供了一种计算经过时间的快速方法。QElapsedTimer类通常用于快速计算两个事件之间经过了多少时间。 它的API与QTime相似,因此可以将正在使用的代码快速移植到新类中。但是,与QTime不同,QElapsedTimer在可能的情况下尝试使用单调时钟。 这意味着不可能将QElapsedTimer对象转换为人类可读的时间。该类的典型用例是确定在缓慢的操作上花费了多少时间。 这种情况的最简单示例是出于调试目的,如以下示例所示:

QElapsedTimer timer;
timer.start();
slowOperation1();
qDebug() << "The slow operation took" << timer.elapsed() << "milliseconds";

在此示例中,计时器是通过调用start来启动的,而经过的计时器是由elapsed函数计算的。

void PluginManagerPrivate::addObject(QObject *obj)
{
	QWriteLocker lock(&m_lock);
    if (obj == nullptr) {
    	qWarning() << "PluginManagerPrivate::addObject(): trying to add null object";
        return; }
    if (allObjects.contains(obj)) {
    	qWarning() << "PluginManagerPrivate::addObject(): trying to add duplicate object";
        return; }
    if (debugLeaks)
    	qDebug() << "PluginManagerPrivate::addObject" << obj << obj->objectName();
    if (m_profilingVerbosity && !m_profileTimer.isNull()) {
    // Report a timestamp when adding an object. Useful for profiling
    // its initialization time.
    const int absoluteElapsedMS = int(m_profileTimer->elapsed());
    qDebug("  %-43s %8dms", obj->metaObject()->className(), absoluteElapsedMS); }
  allObjects.append(obj);
  emit q->objectAdded(obj);
}
void PluginManagerPrivate::removeObject(QObject *obj)
{
    if (obj == nullptr) {
        qWarning() << "PluginManagerPrivate::removeObject(): trying to remove null object";
        return; }
    if (!allObjects.contains(obj)) {
        qWarning() << "PluginManagerPrivate::removeObject(): object not in list:" << obj << obj->objectName();
        return; }
    if (debugLeaks)
        qDebug() << "PluginManagerPrivate::removeObject" << obj << obj->objectName();
    emit q->aboutToRemoveObject(obj);
    QWriteLocker lock(&m_lock);
    allObjects.removeAll(obj);
}

插件操作

// 设置插件settings和globalSettings的QSettings
void PluginManagerPrivate::setSettings(QSettings *s)
{
    if (settings)
        delete settings;
    settings = s;
    if (settings)
        settings->setParent(this);
}
void PluginManagerPrivate::setGlobalSettings(QSettings *s)
{
    if (globalSettings)
        delete globalSettings;
    globalSettings = s;
    if (globalSettings)
        globalSettings->setParent(this);
}
// 根据settings和globalSettings读配置
void PluginManagerPrivate::readSettings()
{
    if (globalSettings) {
        defaultDisabledPlugins = globalSettings->value(QLatin1String(C_IGNORED_PLUGINS)).toStringList();
        defaultEnabledPlugins = globalSettings->value(QLatin1String(C_FORCEENABLED_PLUGINS)).toStringList();
    }
    if (settings) {
        disabledPlugins = settings->value(QLatin1String(C_IGNORED_PLUGINS)).toStringList();
        forceEnabledPlugins = settings->value(QLatin1String(C_FORCEENABLED_PLUGINS)).toStringList();
    }
}
// 根据插件的enabledByDefault和EnabledBySettings写配置
void PluginManagerPrivate::writeSettings()
{
    if (!settings)
        return;
    QStringList tempDisabledPlugins;
    QStringList tempForceEnabledPlugins;
    foreach (PluginSpec *spec, pluginSpecs) {
        if (spec->isEnabledByDefault() && !spec->isEnabledBySettings())
            tempDisabledPlugins.append(spec->name());
        if (!spec->isEnabledByDefault() && spec->isEnabledBySettings())
            tempForceEnabledPlugins.append(spec->name());
    }
    settings->setValue(QLatin1String(C_IGNORED_PLUGINS), tempDisabledPlugins);
    settings->setValue(QLatin1String(C_FORCEENABLED_PLUGINS), tempForceEnabledPlugins);
}
// 设置需加载的插件路劲
void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
{
    qCDebug(pluginLog) << "Plugin search paths:" << paths;
    qCDebug(pluginLog) << "Required IID:" << pluginIID;
    pluginPaths = paths;
    readSettings();
    readPluginPaths();
}
bool PluginManagerPrivate::loadQueue(PluginSpec *spec,
                                     QVector<PluginSpec *> &queue,
                                     QVector<PluginSpec *> &circularityCheckQueue)
{
    if (queue.contains(spec))
        return true;
    // check for circular dependencies
    if (circularityCheckQueue.contains(spec)) {
        spec->d->hasError = true;
        spec->d->errorString = PluginManager::tr("Circular dependency detected:");
        spec->d->errorString += QLatin1Char('\n');
        int index = circularityCheckQueue.indexOf(spec);
        for (int i = index; i < circularityCheckQueue.size(); ++i) {
            spec->d->errorString.append(PluginManager::tr("%1 (%2) depends on")
                .arg(circularityCheckQueue.at(i)->name()).arg(circularityCheckQueue.at(i)->version()));
            spec->d->errorString += QLatin1Char('\n');
        }
        spec->d->errorString.append(PluginManager::tr("%1 (%2)").arg(spec->name()).arg(spec->version()));
        return false;
    }
    circularityCheckQueue.append(spec);
    // check if we have the dependencies
    if (spec->state() == PluginSpec::Invalid || spec->state() == PluginSpec::Read) {
        queue.append(spec);
        return false;
    }

    // add dependencies
    const QHash<PluginDependency, PluginSpec *> deps = spec->dependencySpecs();
    for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) {
        // Skip test dependencies since they are not real dependencies but just force-loaded
        // plugins when running tests
        if (it.key().type == PluginDependency::Test)
            continue;
        PluginSpec *depSpec = it.value();
        if (!loadQueue(depSpec, queue, circularityCheckQueue)) {
            spec->d->hasError = true;
            spec->d->errorString =
                PluginManager::tr("Cannot load plugin because dependency failed to load: %1 (%2)\nReason: %3")
                    .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());
            return false;
        }
    }
    // add self
    queue.append(spec);
    return true;
}
QVector<PluginSpec *> PluginManagerPrivate::loadQueue()
{
    QVector<PluginSpec *> queue;
    foreach (PluginSpec *spec, pluginSpecs) {
        QVector<PluginSpec *> circularityCheckQueue;
        loadQueue(spec, queue, circularityCheckQueue);
    }
    return queue;
}
void PluginManagerPrivate::loadPlugins()
{
    QVector<PluginSpec *> queue = loadQueue();
    Utils::setMimeStartupPhase(MimeStartupPhase::PluginsLoading);
    foreach (PluginSpec *spec, queue) {
        loadPlugin(spec, PluginSpec::Loaded);
    }
    Utils::setMimeStartupPhase(MimeStartupPhase::PluginsInitializing);
    foreach (PluginSpec *spec, queue) {
        loadPlugin(spec, PluginSpec::Initialized);
    }
    Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing);
    Utils::reverseForeach(queue, [this](PluginSpec *spec) {
        loadPlugin(spec, PluginSpec::Running);
        if (spec->state() == PluginSpec::Running) {
            delayedInitializeQueue.push(spec);
        } else {
            // Plugin initialization failed, so cleanup after it
            spec->d->kill();
        }
    });
    emit q->pluginsChanged();
    Utils::setMimeStartupPhase(MimeStartupPhase::UpAndRunning);
	//延时初始化
    delayedInitializeTimer = new QTimer;
    delayedInitializeTimer->setInterval(DELAYED_INITIALIZE_INTERVAL);
    delayedInitializeTimer->setSingleShot(true);
    connect(delayedInitializeTimer, &QTimer::timeout,
            this, &PluginManagerPrivate::nextDelayedInitialize);
    delayedInitializeTimer->start();
}
void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState)
{
    if (spec->hasError() || spec->state() != destState-1)
        return;
    // don't load disabled plugins.
    if (!spec->isEffectivelyEnabled() && destState == PluginSpec::Loaded)
        return;
    LockFile f(this, spec);
    switch (destState) {
    case PluginSpec::Running:
        profilingReport(">initializeExtensions", spec);
        spec->d->initializeExtensions();
        profilingReport("<initializeExtensions", spec);
        return;
    case PluginSpec::Deleted:
        profilingReport(">delete", spec);
        spec->d->kill();
        profilingReport("<delete", spec);
        return;
    default:
        break;
    }
    // check if dependencies have loaded without error
    const QHash<PluginDependency, PluginSpec *> deps = spec->dependencySpecs();
    for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) {
        if (it.key().type != PluginDependency::Required)
            continue;
        PluginSpec *depSpec = it.value();
        if (depSpec->state() != destState) {
            spec->d->hasError = true;
            spec->d->errorString =
                PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
                    .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());
            return;
        }
    }
    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;
    }
}

查看该选项规格的参数描述。

PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const
{
    // Look in the plugins for an option
    *requiresArgument = false;
    foreach (PluginSpec *spec, pluginSpecs) {
        PluginArgumentDescription match = Utils::findOrDefault(spec->argumentDescriptions(),
                                                               [option](PluginArgumentDescription pad) {
                                                                   return pad.name == option;
                                                               });
        if (!match.name.isEmpty()) {
            *requiresArgument = !match.parameter.isEmpty();
            return spec;
        }
    }
    return nullptr;
}

main函数中的使用

const QStringList pluginArguments = app.arguments();
QSettings *settings = userSettings();
QSettings *globalSettings = new QSettings(QSettings::IniFormat, QSettings::SystemScope, QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR), QLatin1String(Core::Constants::IDE_CASED_ID));
PluginManager pluginManager;
PluginManager::setPluginIID(QLatin1String("org.qt-project.Qt.QtCreatorPlugin")); // 设置PluginIID的值为org.qt-project.Qt.QtCreatorPlugin
PluginManager::setGlobalSettings(globalSettings);
PluginManager::setSettings(settings); 

// Load
const QStringList pluginPaths = getPluginPaths() + options.customPluginPaths;
PluginManager::setPluginPaths(pluginPaths);
QMap<QString, QString> foundAppOptions;
if (pluginArguments.size() > 1) { // 如果pluginArguments参数QString数量大于1
	QMap<QString, bool> appOptions;
    appOptions.insert(QLatin1String(HELP_OPTION1), false);
    appOptions.insert(QLatin1String(HELP_OPTION2), false);
    appOptions.insert(QLatin1String(HELP_OPTION3), false);
    appOptions.insert(QLatin1String(HELP_OPTION4), false);
    appOptions.insert(QLatin1String(VERSION_OPTION), false);
    appOptions.insert(QLatin1String(CLIENT_OPTION), false);
    appOptions.insert(QLatin1String(PID_OPTION), true);
    appOptions.insert(QLatin1String(BLOCK_OPTION), false);
    QString errorMessage;
    if (!PluginManager::parseOptions(pluginArguments, appOptions, &foundAppOptions, &errorMessage)) {
    	displayError(errorMessage);
        printHelp(QFileInfo(app.applicationFilePath()).baseName());
        return -1;
    }
}  
restarter.setArguments(options.preAppArguments + PluginManager::argumentsForRestart() + lastSessionArgument());

const PluginSpecSet plugins = PluginManager::plugins();
PluginSpec *coreplugin = nullptr;
foreach (PluginSpec *spec, plugins) {
	 if (spec->name() == QLatin1String(corePluginNameC)) {
     	coreplugin = spec;
        break;
     }
}
if (!coreplugin) {
	QString nativePaths = QDir::toNativeSeparators(pluginPaths.join(QLatin1Char(',')));
   const QString reason = QCoreApplication::translate("Application", "Could not find Core plugin in %1").arg(nativePaths);
   displayError(msgCoreLoadFailure(reason));
   return 1;
}
if (!coreplugin->isEffectivelyEnabled()) {
   const QString reason = QCoreApplication::translate("Application", "Core plugin is disabled.");
   displayError(msgCoreLoadFailure(reason));
   return 1;
}
if (coreplugin->hasError()) {
   displayError(msgCoreLoadFailure(coreplugin->errorString()));
   return 1;
}  

PluginManager::checkForProblematicPlugins();
PluginManager::loadPlugins();
if (coreplugin->hasError()) {
	displayError(msgCoreLoadFailure(coreplugin->errorString()));
    return 1;
}

// Set up remote arguments.
QObject::connect(&app, &SharedTools::QtSingleApplication::messageReceived,
                     &pluginManager, &PluginManager::remoteArguments);

QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(),
                     SLOT(fileOpenRequest(QString)));

// shutdown plugin manager on the exit
QObject::connect(&app, &QCoreApplication::aboutToQuit, &pluginManager, &PluginManager::shutdown);
                                         

Qt Creator源码分析系列——extensionsystem::IPlugin
Qt Creator源码分析系列——extensionsystem::PluginSpec

发布了134 篇原创文章 · 获赞 141 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/asmartkiller/article/details/104478168
今日推荐