Chris@2: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@2: Chris@2: #include "plugincandidates.h" Chris@2: Chris@2: #include Chris@2: #include Chris@2: #include Chris@2: Chris@2: #include Chris@2: #include Chris@2: Chris@2: #ifdef _WIN32 Chris@2: #define PLUGIN_GLOB "*.dll" Chris@2: #define PATH_SEPARATOR ';' Chris@2: #else Chris@2: #define PATH_SEPARATOR ':' Chris@2: #ifdef __APPLE__ Chris@2: #define PLUGIN_GLOB "*.dylib *.so" Chris@2: #else Chris@2: #define PLUGIN_GLOB "*.so" Chris@2: #endif Chris@2: #endif Chris@2: Chris@2: using namespace std; Chris@2: Chris@2: PluginCandidates::PluginCandidates(string helperExecutableName) : Chris@2: m_helper(helperExecutableName) Chris@2: { Chris@2: } Chris@2: Chris@2: vector Chris@2: PluginCandidates::getCandidateLibrariesFor(string tag) Chris@2: { Chris@2: return m_candidates[tag]; Chris@2: } Chris@2: Chris@2: vector Chris@2: PluginCandidates::getFailedLibrariesFor(string tag) Chris@2: { Chris@2: return m_failures[tag]; Chris@2: } Chris@2: Chris@2: vector Chris@2: PluginCandidates::getLibrariesInPath(vector path) Chris@2: { Chris@2: vector candidates; Chris@2: Chris@2: for (string dirname: path) { Chris@2: Chris@2: //#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE Chris@2: cerr << "getLibrariesInPath: scanning directory " << dirname << endl; Chris@2: //#endif Chris@2: Chris@2: QDir dir(dirname.c_str(), PLUGIN_GLOB, Chris@2: QDir::Name | QDir::IgnoreCase, Chris@2: QDir::Files | QDir::Readable); Chris@2: Chris@2: for (unsigned int i = 0; i < dir.count(); ++i) { Chris@2: QString soname = dir.filePath(dir[i]); Chris@2: candidates.push_back(soname.toStdString()); Chris@2: } Chris@2: } Chris@2: Chris@2: return candidates; Chris@2: } Chris@2: Chris@2: void Chris@2: PluginCandidates::scan(string tag, Chris@2: vector pluginPath, Chris@2: string descriptorFunctionName) Chris@2: { Chris@2: vector libraries = getLibrariesInPath(pluginPath); Chris@2: vector remaining = libraries; Chris@2: Chris@2: int runlimit = 20; Chris@2: int runcount = 0; Chris@2: Chris@2: vector result; Chris@2: Chris@2: while (result.size() < libraries.size() && runcount < runlimit) { Chris@2: vector output = runHelper(remaining, descriptorFunctionName); Chris@2: result.insert(result.end(), output.begin(), output.end()); Chris@2: int shortfall = int(remaining.size()) - int(output.size()); Chris@2: if (shortfall > 0) { Chris@2: // Helper bailed out for some reason presumably associated Chris@2: // with the plugin following the last one it reported Chris@2: // on. Add a null entry for that one and continue with the Chris@2: // following ones. Chris@2: result.push_back(""); Chris@2: if (shortfall == 1) { Chris@2: remaining = vector(); Chris@2: } else { Chris@2: remaining = vector Chris@2: (remaining.rbegin(), remaining.rbegin() + shortfall - 1); Chris@2: } Chris@2: } Chris@2: ++runcount; Chris@2: } Chris@2: Chris@2: recordResult(tag, result); Chris@2: } Chris@2: Chris@2: vector Chris@2: PluginCandidates::runHelper(vector libraries, string descriptor) Chris@2: { Chris@2: vector output; Chris@2: cerr << "running helper with following library list:" << endl; Chris@2: for (auto &lib: libraries) cerr << lib << endl; Chris@2: Chris@2: QProcess process; Chris@2: process.setReadChannel(QProcess::StandardOutput); Chris@2: process.start(m_helper.c_str(), { descriptor.c_str() }); Chris@2: if (!process.waitForStarted()) { Chris@2: cerr << "helper failed to start" << endl; Chris@2: throw runtime_error("plugin load helper failed to start"); Chris@2: } Chris@2: for (auto &lib: libraries) { Chris@2: process.write(lib.c_str(), lib.size()); Chris@2: process.write("\n", 1); Chris@2: } Chris@2: Chris@2: int buflen = 4096; Chris@2: while (process.waitForReadyRead()) { Chris@2: char buf[buflen]; Chris@2: qint64 linelen = process.readLine(buf, buflen); Chris@2: // cerr << "read line: " << buf; Chris@2: if (linelen < 0) { Chris@2: cerr << "read failed from plugin load helper" << endl; Chris@2: return output; Chris@2: } Chris@2: output.push_back(buf); Chris@2: if (output.size() == libraries.size()) { Chris@2: process.close(); Chris@2: process.waitForFinished(); Chris@2: break; Chris@2: } Chris@2: } Chris@2: Chris@2: return output; Chris@2: } Chris@2: Chris@2: void Chris@2: PluginCandidates::recordResult(string tag, vector result) Chris@2: { Chris@2: cerr << "recordResult: not yet implemented, but result was:" << endl; Chris@2: for (auto &r: result) cerr << r; Chris@2: cerr << "(ends)" << endl; Chris@2: } Chris@2: