Chris@1178: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1178: Chris@1178: /* Chris@1178: Sonic Visualiser Chris@1178: An audio file viewer and annotation editor. Chris@1178: Centre for Digital Music, Queen Mary, University of London. Chris@1178: Chris@1178: This program is free software; you can redistribute it and/or Chris@1178: modify it under the terms of the GNU General Public License as Chris@1178: published by the Free Software Foundation; either version 2 of the Chris@1178: License, or (at your option) any later version. See the file Chris@1178: COPYING included with this distribution for more information. Chris@1178: */ Chris@1178: Chris@1178: #include "PluginScan.h" Chris@1178: Chris@1178: #include "base/Debug.h" Chris@1246: #include "base/Preferences.h" Chris@1241: #include "base/HelperExecPath.h" Chris@1178: Chris@1249: #ifdef HAVE_PLUGIN_CHECKER_HELPER Chris@1180: #include "checker/knownplugins.h" Chris@1249: #else Chris@1249: class KnownPlugins {}; Chris@1249: #endif Chris@1180: Chris@1178: #include Chris@1181: #include Chris@1178: Chris@1178: using std::string; Chris@1178: Chris@1249: class PluginScan::Logger Chris@1249: #ifdef HAVE_PLUGIN_CHECKER_HELPER Chris@1249: : public PluginCandidates::LogCallback Chris@1249: #endif Chris@1180: { Chris@1180: protected: Chris@1180: void log(std::string message) { Chris@1180: SVDEBUG << "PluginScan: " << message; Chris@1180: } Chris@1180: }; Chris@1180: Chris@1180: PluginScan *PluginScan::getInstance() Chris@1180: { Chris@1178: static QMutex mutex; Chris@1178: static PluginScan *m_instance = 0; Chris@1178: mutex.lock(); Chris@1178: if (!m_instance) m_instance = new PluginScan(); Chris@1178: mutex.unlock(); Chris@1178: return m_instance; Chris@1178: } Chris@1178: Chris@1246: PluginScan::PluginScan() : m_succeeded(false), m_logger(new Logger) { Chris@1178: } Chris@1178: Chris@1178: PluginScan::~PluginScan() { Chris@1246: QMutexLocker locker(&m_mutex); Chris@1241: clear(); Chris@1180: delete m_logger; Chris@1178: } Chris@1178: Chris@1178: void Chris@1241: PluginScan::scan() Chris@1178: { Chris@1249: #ifdef HAVE_PLUGIN_CHECKER_HELPER Chris@1249: Chris@1246: QMutexLocker locker(&m_mutex); Chris@1246: Chris@1246: bool inProcess = Preferences::getInstance()->getRunPluginsInProcess(); Chris@1246: Chris@1246: HelperExecPath hep(inProcess ? Chris@1246: HelperExecPath::NativeArchitectureOnly : Chris@1246: HelperExecPath::AllInstalled); Chris@1246: Chris@1246: QString helperName("plugin-checker-helper"); Chris@1246: auto helpers = hep.getHelperExecutables(helperName); Chris@1241: Chris@1241: clear(); Chris@1241: Chris@1246: for (auto p: helpers) { Chris@1247: SVDEBUG << "NOTE: PluginScan: Found helper: " << p.executable << endl; Chris@1246: } Chris@1246: Chris@1246: if (helpers.empty()) { Chris@1247: SVDEBUG << "NOTE: No plugin checker helpers found in installation;" Chris@1246: << " found none of the following:" << endl; Chris@1246: for (auto d: hep.getHelperCandidatePaths(helperName)) { Chris@1247: SVDEBUG << "NOTE: " << d << endl; Chris@1246: } Chris@1246: } Chris@1246: Chris@1246: for (auto p: helpers) { Chris@1241: try { Chris@1246: KnownPlugins *kp = new KnownPlugins Chris@1246: (p.executable.toStdString(), m_logger); Chris@1246: if (m_kp.find(p.tag) != m_kp.end()) { Chris@1247: SVDEBUG << "WARNING: PluginScan::scan: Duplicate tag " << p.tag Chris@1246: << " for helpers" << endl; Chris@1246: continue; Chris@1246: } Chris@1246: m_kp[p.tag] = kp; Chris@1241: m_succeeded = true; Chris@1241: } catch (const std::exception &e) { Chris@1247: SVDEBUG << "ERROR: PluginScan::scan: " << e.what() Chris@1246: << " (with helper path = " << p.executable << ")" << endl; Chris@1241: } Chris@1241: } Chris@1249: Chris@1249: #endif Chris@1241: } Chris@1241: Chris@1246: bool Chris@1246: PluginScan::scanSucceeded() const Chris@1246: { Chris@1246: QMutexLocker locker(&m_mutex); Chris@1246: return m_succeeded; Chris@1246: } Chris@1246: Chris@1241: void Chris@1241: PluginScan::clear() Chris@1241: { Chris@1246: for (auto &p: m_kp) { Chris@1246: delete p.second; Chris@1246: } Chris@1241: m_kp.clear(); Chris@1179: m_succeeded = false; Chris@1179: } Chris@1179: Chris@1246: QList Chris@1180: PluginScan::getCandidateLibrariesFor(PluginType type) const Chris@1179: { Chris@1249: #ifdef HAVE_PLUGIN_CHECKER_HELPER Chris@1249: Chris@1246: QMutexLocker locker(&m_mutex); Chris@1246: Chris@1180: KnownPlugins::PluginType kpt; Chris@1180: switch (type) { Chris@1180: case VampPlugin: kpt = KnownPlugins::VampPlugin; break; Chris@1180: case LADSPAPlugin: kpt = KnownPlugins::LADSPAPlugin; break; Chris@1180: case DSSIPlugin: kpt = KnownPlugins::DSSIPlugin; break; Chris@1180: default: throw std::logic_error("Inconsistency in plugin type enums"); Chris@1180: } Chris@1180: Chris@1246: QList candidates; Chris@1245: Chris@1246: for (auto rec: m_kp) { Chris@1245: Chris@1246: KnownPlugins *kp = rec.second; Chris@1246: Chris@1241: auto c = kp->getCandidateLibrariesFor(kpt); Chris@1245: Chris@1247: SVDEBUG << "PluginScan: helper \"" << kp->getHelperExecutableName() Chris@1247: << "\" likes " << c.size() << " libraries of type " Chris@1247: << kp->getTagFor(kpt) << endl; Chris@1245: Chris@1246: for (auto s: c) { Chris@1246: candidates.push_back({ s.c_str(), rec.first }); Chris@1246: } Chris@1245: Chris@1245: if (type != VampPlugin) { Chris@1245: // We are only interested in querying multiple helpers Chris@1245: // when dealing with Vamp plugins, for which we can use Chris@1245: // external servers and so in some cases can support Chris@1245: // additional architectures. Other plugin formats are Chris@1245: // loaded directly and so must match the host, which is Chris@1245: // what the first helper is supposed to handle -- so Chris@1245: // break after the first one if not querying Vamp Chris@1245: break; Chris@1245: } Chris@1241: } Chris@1245: Chris@1179: return candidates; Chris@1249: Chris@1249: #else Chris@1249: return {}; Chris@1249: #endif Chris@1178: } Chris@1178: Chris@1178: QString Chris@1178: PluginScan::getStartupFailureReport() const Chris@1178: { Chris@1249: #ifdef HAVE_PLUGIN_CHECKER_HELPER Chris@1249: Chris@1246: QMutexLocker locker(&m_mutex); Chris@1246: Chris@1179: if (!m_succeeded) { Chris@1179: return QObject::tr("Failed to scan for plugins" Chris@1181: "

Failed to scan for plugins at startup. Possibly " Chris@1181: "the plugin checker helper program was not correctly " Chris@1181: "installed alongside %1?

") Chris@1181: .arg(QCoreApplication::applicationName()); Chris@1179: } Chris@1241: if (m_kp.empty()) { Chris@1179: return QObject::tr("Did not scan for plugins" Chris@1179: "

Apparently no scan for plugins was attempted " Chris@1179: "(internal error?)

"); Chris@1179: } Chris@1179: Chris@1241: QString report; Chris@1241: for (auto kp: m_kp) { Chris@1246: report += QString::fromStdString(kp.second->getFailureReport()); Chris@1241: } Chris@1179: if (report == "") { Chris@1241: return report; Chris@1179: } Chris@1179: Chris@1179: return QObject::tr("Failed to load plugins" Chris@1179: "

Failed to load one or more plugin libraries:

") Chris@1241: + report Chris@1181: + QObject::tr("

These plugins may be incompatible with the system, " Chris@1181: "and will be ignored during this run of %1.

") Chris@1181: .arg(QCoreApplication::applicationName()); Chris@1249: Chris@1249: #else Chris@1249: return ""; Chris@1249: #endif Chris@1178: } Chris@1178: