# HG changeset patch # User Chris Cannam # Date 1478182449 0 # Node ID 75aefcc9f07d51d22b0dd2ed66dfb623391ca7c8 # Parent 0492e54ccd5693d54e81c75c3fe0e0506909ebd9 Use plugin scan results to inform the list requests issued to Piper servers diff -r 0492e54ccd56 -r 75aefcc9f07d base/HelperExecPath.cpp --- a/base/HelperExecPath.cpp Tue Nov 01 16:02:15 2016 +0000 +++ b/base/HelperExecPath.cpp Thu Nov 03 14:14:09 2016 +0000 @@ -20,13 +20,17 @@ #include #include -static QStringList -getSuffixes() +QStringList +HelperExecPath::getTags() { if (sizeof(void *) == 8) { - return { "-64", "", "-32" }; + if (m_type == NativeArchitectureOnly) { + return { "64", "" }; + } else { + return { "64", "", "32" }; + } } else { - return { "", "-32" }; + return { "", "32" }; } } @@ -36,7 +40,7 @@ return QFile(path).exists() && QFileInfo(path).isExecutable(); } -QStringList +QList HelperExecPath::getHelperExecutables(QString basename) { QStringList dummy; @@ -46,9 +50,9 @@ QString HelperExecPath::getHelperExecutable(QString basename) { - QStringList execs = getHelperExecutables(basename); + auto execs = getHelperExecutables(basename); if (execs.empty()) return ""; - else return execs[0]; + else return execs[0].executable; } QStringList @@ -69,7 +73,7 @@ return candidates; } -QStringList +QList HelperExecPath::search(QString basename, QStringList &candidates) { // Helpers are expected to exist either in the same directory as @@ -80,15 +84,17 @@ extension = ".exe"; #endif - QStringList executables; + QList executables; QStringList dirs = getHelperDirPaths(); - for (QString s: getSuffixes()) { + for (QString t: getTags()) { for (QString d: dirs) { - QString path = d + QDir::separator() + basename + s + extension; + QString path = d + QDir::separator() + basename; + if (t != QString()) path += "-" + t; + path += extension; candidates.push_back(path); if (isGood(path)) { - executables.push_back(path); + executables.push_back({ path, t }); break; } } diff -r 0492e54ccd56 -r 75aefcc9f07d base/HelperExecPath.h --- a/base/HelperExecPath.h Tue Nov 01 16:02:15 2016 +0000 +++ b/base/HelperExecPath.h Thu Nov 03 14:14:09 2016 +0000 @@ -33,35 +33,52 @@ class HelperExecPath { public: + enum SearchType { + NativeArchitectureOnly, + AllInstalled + }; + + HelperExecPath(SearchType type) : m_type(type) { } + /** * Find a helper executable with the given base name in the bundle * directory or installation location, if one exists, and return * its full path. Equivalent to calling getHelperExecutables() and * taking the first result from the returned list (or "" if empty). */ - static QString getHelperExecutable(QString basename); + QString getHelperExecutable(QString basename); + + struct HelperExec { + QString executable; + QString tag; + }; /** * Find all helper executables with the given base name in the * bundle directory or installation location, and return their - * full paths in order of priority. + * full paths in order of priority. The "tag" string contains an + * identifier for the location or architecture of the helper, for + * example "32", "64", "js" etc. An empty tag signifies a default + * helper that matches the application's architecture. */ - static QStringList getHelperExecutables(QString basename); + QList getHelperExecutables(QString basename); /** * Return the list of directories searched for helper * executables. */ - static QStringList getHelperDirPaths(); + QStringList getHelperDirPaths(); /** * Return the list of executable paths examined in the search for * the helper executable with the given basename. */ - static QStringList getHelperCandidatePaths(QString basename); + QStringList getHelperCandidatePaths(QString basename); private: - static QStringList search(QString, QStringList &); + SearchType m_type; + QList search(QString, QStringList &); + QStringList getTags(); }; #endif diff -r 0492e54ccd56 -r 75aefcc9f07d plugin/LADSPAPluginFactory.cpp --- a/plugin/LADSPAPluginFactory.cpp Tue Nov 01 16:02:15 2016 +0000 +++ b/plugin/LADSPAPluginFactory.cpp Thu Nov 03 14:14:09 2016 +0000 @@ -668,11 +668,11 @@ generateFallbackCategories(); - QStringList candidates = + auto candidates = PluginScan::getInstance()->getCandidateLibrariesFor(getPluginType()); - for (QString c: candidates) { - discoverPluginsFrom(c); + for (auto c: candidates) { + discoverPluginsFrom(c.libraryPath); } } diff -r 0492e54ccd56 -r 75aefcc9f07d plugin/NativeVampPluginFactory.cpp --- a/plugin/NativeVampPluginFactory.cpp Tue Nov 01 16:02:15 2016 +0000 +++ b/plugin/NativeVampPluginFactory.cpp Thu Nov 03 14:14:09 2016 +0000 @@ -81,10 +81,12 @@ return m_identifiers; } - QStringList candidates = PluginScan::getInstance()->getCandidateLibrariesFor + auto candidates = PluginScan::getInstance()->getCandidateLibrariesFor (PluginScan::VampPlugin); - for (QString soname : candidates) { + for (auto candidate : candidates) { + + QString soname = candidate.libraryPath; void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); diff -r 0492e54ccd56 -r 75aefcc9f07d plugin/PiperVampPluginFactory.cpp --- a/plugin/PiperVampPluginFactory.cpp Tue Nov 01 16:02:15 2016 +0000 +++ b/plugin/PiperVampPluginFactory.cpp Thu Nov 03 14:14:09 2016 +0000 @@ -50,27 +50,23 @@ { QString serverName = "piper-vamp-simple-server"; - m_servers = HelperExecPath::getHelperExecutables(serverName); + HelperExecPath hep(HelperExecPath::AllInstalled); + m_servers = hep.getHelperExecutables(serverName); + for (auto n: m_servers) { + cerr << "NOTE: PiperVampPluginFactory: Found server: " + << n.executable << endl; + } + if (m_servers.empty()) { cerr << "NOTE: No Piper Vamp servers found in installation;" << " found none of the following:" << endl; - for (auto d: HelperExecPath::getHelperCandidatePaths(serverName)) { + for (auto d: hep.getHelperCandidatePaths(serverName)) { cerr << "NOTE: " << d << endl; } } } -QStringList -PiperVampPluginFactory::getServerSuffixes() -{ - if (sizeof(void *) == 8) { - return { "-64", "", "-32" }; - } else { - return { "", "-32" }; - } -} - vector PiperVampPluginFactory::getPluginIdentifiers(QString &errorMessage) { @@ -149,7 +145,7 @@ { QString someError; - for (QString s: m_servers) { + for (auto s: m_servers) { populateFrom(s, someError); @@ -160,10 +156,40 @@ } void -PiperVampPluginFactory::populateFrom(QString server, QString &errorMessage) +PiperVampPluginFactory::populateFrom(const HelperExecPath::HelperExec &server, + QString &errorMessage) { - piper_vamp::client::ProcessQtTransport transport(server.toStdString(), - "capnp"); + QString tag = server.tag; + string executable = server.executable.toStdString(); + + PluginScan *scan = PluginScan::getInstance(); + auto candidateLibraries = + scan->getCandidateLibrariesFor(PluginScan::VampPlugin); + + vector from; + for (const auto &c: candidateLibraries) { + if (c.helperTag == tag) { + string soname = QFileInfo(c.libraryPath).baseName().toStdString(); + cerr << "INFO: For tag \"" << tag << "\" giving library " << soname << endl; + from.push_back(soname); + } + } + + if (from.empty()) { + cerr << "PiperVampPluginFactory: No candidate libraries for tag \"" + << tag << "\""; + if (scan->scanSucceeded()) { + // we have to assume that they all failed to load (i.e. we + // exclude them all) rather than sending an empty list + // (which would mean no exclusions) + cerr << ", skipping" << endl; + return; + } else { + cerr << ", but it seems the scan failed, so bumbling on anyway" << endl; + } + } + + piper_vamp::client::ProcessQtTransport transport(executable, "capnp"); if (!transport.isOK()) { errorMessage = QObject::tr("Could not start external plugin host"); return; @@ -184,7 +210,7 @@ return; } - cerr << "PiperVampPluginFactory: server \"" << server << "\" lists " + cerr << "PiperVampPluginFactory: server \"" << executable << "\" lists " << lr.available.size() << " plugin(s)" << endl; for (const auto &pd: lr.available) { @@ -198,7 +224,7 @@ continue; } - m_origins[identifier] = server; + m_origins[identifier] = server.executable; m_pluginData[identifier] = pd; diff -r 0492e54ccd56 -r 75aefcc9f07d plugin/PiperVampPluginFactory.h --- a/plugin/PiperVampPluginFactory.h Tue Nov 01 16:02:15 2016 +0000 +++ b/plugin/PiperVampPluginFactory.h Thu Nov 03 14:14:09 2016 +0000 @@ -23,6 +23,7 @@ #include #include "base/Debug.h" +#include "base/HelperExecPath.h" /** * FeatureExtractionPluginFactory type for Vamp plugins hosted in a @@ -49,15 +50,13 @@ protected: QMutex m_mutex; - QStringList m_servers; // executable file paths + QList m_servers; // executable file paths std::map m_origins; // plugin identifier -> server path std::map m_pluginData; // identifier -> data std::map m_taxonomy; // identifier -> category string void populate(QString &errorMessage); - void populateFrom(QString server, QString &errorMessage); - - static QStringList getServerSuffixes(); + void populateFrom(const HelperExecPath::HelperExec &, QString &errorMessage); }; #endif diff -r 0492e54ccd56 -r 75aefcc9f07d plugin/PluginScan.cpp --- a/plugin/PluginScan.cpp Tue Nov 01 16:02:15 2016 +0000 +++ b/plugin/PluginScan.cpp Thu Nov 03 14:14:09 2016 +0000 @@ -15,6 +15,7 @@ #include "PluginScan.h" #include "base/Debug.h" +#include "base/Preferences.h" #include "base/HelperExecPath.h" #include "checker/knownplugins.h" @@ -47,10 +48,11 @@ return m_instance; } -PluginScan::PluginScan() : m_kp(0), m_succeeded(false), m_logger(new Logger) { +PluginScan::PluginScan() : m_succeeded(false), m_logger(new Logger) { } PluginScan::~PluginScan() { + QMutexLocker locker(&m_mutex); clear(); delete m_logger; } @@ -58,34 +60,71 @@ void PluginScan::scan() { - QStringList helperPaths = - HelperExecPath::getHelperExecutables("plugin-checker-helper"); + QMutexLocker locker(&m_mutex); + + bool inProcess = Preferences::getInstance()->getRunPluginsInProcess(); + + HelperExecPath hep(inProcess ? + HelperExecPath::NativeArchitectureOnly : + HelperExecPath::AllInstalled); + + QString helperName("plugin-checker-helper"); + auto helpers = hep.getHelperExecutables(helperName); clear(); - for (auto p: helperPaths) { + for (auto p: helpers) { + cerr << "NOTE: PluginScan: Found helper: " << p.executable << endl; + } + + if (helpers.empty()) { + cerr << "NOTE: No plugin checker helpers found in installation;" + << " found none of the following:" << endl; + for (auto d: hep.getHelperCandidatePaths(helperName)) { + cerr << "NOTE: " << d << endl; + } + } + + for (auto p: helpers) { try { - KnownPlugins *kp = new KnownPlugins(p.toStdString(), m_logger); - m_kp.push_back(kp); + KnownPlugins *kp = new KnownPlugins + (p.executable.toStdString(), m_logger); + if (m_kp.find(p.tag) != m_kp.end()) { + cerr << "WARNING: PluginScan::scan: Duplicate tag " << p.tag + << " for helpers" << endl; + continue; + } + m_kp[p.tag] = kp; m_succeeded = true; } catch (const std::exception &e) { cerr << "ERROR: PluginScan::scan: " << e.what() - << " (with helper path = " << p << ")" << endl; + << " (with helper path = " << p.executable << ")" << endl; } } } +bool +PluginScan::scanSucceeded() const +{ + QMutexLocker locker(&m_mutex); + return m_succeeded; +} + void PluginScan::clear() { - for (auto &p: m_kp) delete p; + for (auto &p: m_kp) { + delete p.second; + } m_kp.clear(); m_succeeded = false; } -QStringList +QList PluginScan::getCandidateLibrariesFor(PluginType type) const { + QMutexLocker locker(&m_mutex); + KnownPlugins::PluginType kpt; switch (type) { case VampPlugin: kpt = KnownPlugins::VampPlugin; break; @@ -94,17 +133,21 @@ default: throw std::logic_error("Inconsistency in plugin type enums"); } - QStringList candidates; + QList candidates; - for (auto kp: m_kp) { + for (auto rec: m_kp) { + KnownPlugins *kp = rec.second; + auto c = kp->getCandidateLibrariesFor(kpt); std::cerr << "PluginScan: helper \"" << kp->getHelperExecutableName() << "\" likes " << c.size() << " libraries of type " << kp->getTagFor(kpt) << std::endl; - for (auto s: c) candidates.push_back(s.c_str()); + for (auto s: c) { + candidates.push_back({ s.c_str(), rec.first }); + } if (type != VampPlugin) { // We are only interested in querying multiple helpers @@ -124,6 +167,8 @@ QString PluginScan::getStartupFailureReport() const { + QMutexLocker locker(&m_mutex); + if (!m_succeeded) { return QObject::tr("Failed to scan for plugins" "

Failed to scan for plugins at startup. Possibly " @@ -139,7 +184,7 @@ QString report; for (auto kp: m_kp) { - report += QString::fromStdString(kp->getFailureReport()); + report += QString::fromStdString(kp.second->getFailureReport()); } if (report == "") { return report; diff -r 0492e54ccd56 -r 75aefcc9f07d plugin/PluginScan.h --- a/plugin/PluginScan.h Tue Nov 01 16:02:15 2016 +0000 +++ b/plugin/PluginScan.h Thu Nov 03 14:14:09 2016 +0000 @@ -16,7 +16,9 @@ #define PLUGIN_SCAN_H #include +#include #include +#include class KnownPlugins; @@ -34,7 +36,11 @@ LADSPAPlugin, DSSIPlugin }; - QStringList getCandidateLibrariesFor(PluginType) const; + struct Candidate { + QString libraryPath; + QString helperTag; + }; + QList getCandidateLibrariesFor(PluginType) const; QString getStartupFailureReport() const; @@ -43,8 +49,10 @@ ~PluginScan(); void clear(); + + mutable QMutex m_mutex; // while scanning; definitely can't multi-thread this - std::vector m_kp; + std::map m_kp; // tag -> KnownPlugins client bool m_succeeded; class Logger;