annotate plugin/PluginScan.cpp @ 1247:8f076d02569a piper

Make SVDEBUG always write to a log file -- formerly this was disabled in NDEBUG builds. I think there's little use to that, it just means that we keep adding more cerr debug output because we aren't getting the log we need. And SVDEBUG logging is not usually used in tight loops, I don't think the performance overhead is too serious. Also update the About box.
author Chris Cannam
date Thu, 03 Nov 2016 14:57:00 +0000
parents 75aefcc9f07d
children d45a16c232bd
rev   line source
Chris@1178 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1178 2
Chris@1178 3 /*
Chris@1178 4 Sonic Visualiser
Chris@1178 5 An audio file viewer and annotation editor.
Chris@1178 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1178 7
Chris@1178 8 This program is free software; you can redistribute it and/or
Chris@1178 9 modify it under the terms of the GNU General Public License as
Chris@1178 10 published by the Free Software Foundation; either version 2 of the
Chris@1178 11 License, or (at your option) any later version. See the file
Chris@1178 12 COPYING included with this distribution for more information.
Chris@1178 13 */
Chris@1178 14
Chris@1178 15 #include "PluginScan.h"
Chris@1178 16
Chris@1178 17 #include "base/Debug.h"
Chris@1246 18 #include "base/Preferences.h"
Chris@1241 19 #include "base/HelperExecPath.h"
Chris@1178 20
Chris@1180 21 #include "checker/knownplugins.h"
Chris@1180 22
Chris@1178 23 #include <QMutex>
Chris@1181 24 #include <QCoreApplication>
Chris@1178 25
Chris@1178 26 using std::string;
Chris@1178 27
Chris@1180 28 class PluginScan::Logger : public PluginCandidates::LogCallback
Chris@1180 29 {
Chris@1180 30 protected:
Chris@1180 31 void log(std::string message) {
Chris@1180 32 SVDEBUG << "PluginScan: " << message;
Chris@1180 33 }
Chris@1180 34 };
Chris@1180 35
Chris@1180 36 PluginScan *PluginScan::getInstance()
Chris@1180 37 {
Chris@1178 38 static QMutex mutex;
Chris@1178 39 static PluginScan *m_instance = 0;
Chris@1178 40 mutex.lock();
Chris@1178 41 if (!m_instance) m_instance = new PluginScan();
Chris@1178 42 mutex.unlock();
Chris@1178 43 return m_instance;
Chris@1178 44 }
Chris@1178 45
Chris@1246 46 PluginScan::PluginScan() : m_succeeded(false), m_logger(new Logger) {
Chris@1178 47 }
Chris@1178 48
Chris@1178 49 PluginScan::~PluginScan() {
Chris@1246 50 QMutexLocker locker(&m_mutex);
Chris@1241 51 clear();
Chris@1180 52 delete m_logger;
Chris@1178 53 }
Chris@1178 54
Chris@1178 55 void
Chris@1241 56 PluginScan::scan()
Chris@1178 57 {
Chris@1246 58 QMutexLocker locker(&m_mutex);
Chris@1246 59
Chris@1246 60 bool inProcess = Preferences::getInstance()->getRunPluginsInProcess();
Chris@1246 61
Chris@1246 62 HelperExecPath hep(inProcess ?
Chris@1246 63 HelperExecPath::NativeArchitectureOnly :
Chris@1246 64 HelperExecPath::AllInstalled);
Chris@1246 65
Chris@1246 66 QString helperName("plugin-checker-helper");
Chris@1246 67 auto helpers = hep.getHelperExecutables(helperName);
Chris@1241 68
Chris@1241 69 clear();
Chris@1241 70
Chris@1246 71 for (auto p: helpers) {
Chris@1247 72 SVDEBUG << "NOTE: PluginScan: Found helper: " << p.executable << endl;
Chris@1246 73 }
Chris@1246 74
Chris@1246 75 if (helpers.empty()) {
Chris@1247 76 SVDEBUG << "NOTE: No plugin checker helpers found in installation;"
Chris@1246 77 << " found none of the following:" << endl;
Chris@1246 78 for (auto d: hep.getHelperCandidatePaths(helperName)) {
Chris@1247 79 SVDEBUG << "NOTE: " << d << endl;
Chris@1246 80 }
Chris@1246 81 }
Chris@1246 82
Chris@1246 83 for (auto p: helpers) {
Chris@1241 84 try {
Chris@1246 85 KnownPlugins *kp = new KnownPlugins
Chris@1246 86 (p.executable.toStdString(), m_logger);
Chris@1246 87 if (m_kp.find(p.tag) != m_kp.end()) {
Chris@1247 88 SVDEBUG << "WARNING: PluginScan::scan: Duplicate tag " << p.tag
Chris@1246 89 << " for helpers" << endl;
Chris@1246 90 continue;
Chris@1246 91 }
Chris@1246 92 m_kp[p.tag] = kp;
Chris@1241 93 m_succeeded = true;
Chris@1241 94 } catch (const std::exception &e) {
Chris@1247 95 SVDEBUG << "ERROR: PluginScan::scan: " << e.what()
Chris@1246 96 << " (with helper path = " << p.executable << ")" << endl;
Chris@1241 97 }
Chris@1241 98 }
Chris@1241 99 }
Chris@1241 100
Chris@1246 101 bool
Chris@1246 102 PluginScan::scanSucceeded() const
Chris@1246 103 {
Chris@1246 104 QMutexLocker locker(&m_mutex);
Chris@1246 105 return m_succeeded;
Chris@1246 106 }
Chris@1246 107
Chris@1241 108 void
Chris@1241 109 PluginScan::clear()
Chris@1241 110 {
Chris@1246 111 for (auto &p: m_kp) {
Chris@1246 112 delete p.second;
Chris@1246 113 }
Chris@1241 114 m_kp.clear();
Chris@1179 115 m_succeeded = false;
Chris@1179 116 }
Chris@1179 117
Chris@1246 118 QList<PluginScan::Candidate>
Chris@1180 119 PluginScan::getCandidateLibrariesFor(PluginType type) const
Chris@1179 120 {
Chris@1246 121 QMutexLocker locker(&m_mutex);
Chris@1246 122
Chris@1180 123 KnownPlugins::PluginType kpt;
Chris@1180 124 switch (type) {
Chris@1180 125 case VampPlugin: kpt = KnownPlugins::VampPlugin; break;
Chris@1180 126 case LADSPAPlugin: kpt = KnownPlugins::LADSPAPlugin; break;
Chris@1180 127 case DSSIPlugin: kpt = KnownPlugins::DSSIPlugin; break;
Chris@1180 128 default: throw std::logic_error("Inconsistency in plugin type enums");
Chris@1180 129 }
Chris@1180 130
Chris@1246 131 QList<Candidate> candidates;
Chris@1245 132
Chris@1246 133 for (auto rec: m_kp) {
Chris@1245 134
Chris@1246 135 KnownPlugins *kp = rec.second;
Chris@1246 136
Chris@1241 137 auto c = kp->getCandidateLibrariesFor(kpt);
Chris@1245 138
Chris@1247 139 SVDEBUG << "PluginScan: helper \"" << kp->getHelperExecutableName()
Chris@1247 140 << "\" likes " << c.size() << " libraries of type "
Chris@1247 141 << kp->getTagFor(kpt) << endl;
Chris@1245 142
Chris@1246 143 for (auto s: c) {
Chris@1246 144 candidates.push_back({ s.c_str(), rec.first });
Chris@1246 145 }
Chris@1245 146
Chris@1245 147 if (type != VampPlugin) {
Chris@1245 148 // We are only interested in querying multiple helpers
Chris@1245 149 // when dealing with Vamp plugins, for which we can use
Chris@1245 150 // external servers and so in some cases can support
Chris@1245 151 // additional architectures. Other plugin formats are
Chris@1245 152 // loaded directly and so must match the host, which is
Chris@1245 153 // what the first helper is supposed to handle -- so
Chris@1245 154 // break after the first one if not querying Vamp
Chris@1245 155 break;
Chris@1245 156 }
Chris@1241 157 }
Chris@1245 158
Chris@1179 159 return candidates;
Chris@1178 160 }
Chris@1178 161
Chris@1178 162 QString
Chris@1178 163 PluginScan::getStartupFailureReport() const
Chris@1178 164 {
Chris@1246 165 QMutexLocker locker(&m_mutex);
Chris@1246 166
Chris@1179 167 if (!m_succeeded) {
Chris@1179 168 return QObject::tr("<b>Failed to scan for plugins</b>"
Chris@1181 169 "<p>Failed to scan for plugins at startup. Possibly "
Chris@1181 170 "the plugin checker helper program was not correctly "
Chris@1181 171 "installed alongside %1?</p>")
Chris@1181 172 .arg(QCoreApplication::applicationName());
Chris@1179 173 }
Chris@1241 174 if (m_kp.empty()) {
Chris@1179 175 return QObject::tr("<b>Did not scan for plugins</b>"
Chris@1179 176 "<p>Apparently no scan for plugins was attempted "
Chris@1179 177 "(internal error?)</p>");
Chris@1179 178 }
Chris@1179 179
Chris@1241 180 QString report;
Chris@1241 181 for (auto kp: m_kp) {
Chris@1246 182 report += QString::fromStdString(kp.second->getFailureReport());
Chris@1241 183 }
Chris@1179 184 if (report == "") {
Chris@1241 185 return report;
Chris@1179 186 }
Chris@1179 187
Chris@1179 188 return QObject::tr("<b>Failed to load plugins</b>"
Chris@1179 189 "<p>Failed to load one or more plugin libraries:</p>")
Chris@1241 190 + report
Chris@1181 191 + QObject::tr("<p>These plugins may be incompatible with the system, "
Chris@1181 192 "and will be ignored during this run of %1.</p>")
Chris@1181 193 .arg(QCoreApplication::applicationName());
Chris@1178 194 }
Chris@1178 195