diff --git a/projectmanagers/cmake/cmakeimportjsonjob.cpp b/projectmanagers/cmake/cmakeimportjsonjob.cpp index 1dc54a78f3..8b14695758 100644 --- a/projectmanagers/cmake/cmakeimportjsonjob.cpp +++ b/projectmanagers/cmake/cmakeimportjsonjob.cpp @@ -1,219 +1,220 @@ /* KDevelop CMake Support * * Copyright 2014 Kevin Funk * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakeimportjsonjob.h" #include "cmakeutils.h" #include "cmakeprojectdata.h" #include "cmakemodelitems.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; namespace { template static T kTransform(const Q& list, W func) { T ret; ret.reserve(list.size()); for (auto it = list.constBegin(), itEnd = list.constEnd(); it!=itEnd; ++it) ret += func(*it); return ret; } CMakeFilesCompilationData importCommands(const Path& commandsFile) { // NOTE: to get compile_commands.json, you need -DCMAKE_EXPORT_COMPILE_COMMANDS=ON QFile f(commandsFile.toLocalFile()); bool r = f.open(QFile::ReadOnly|QFile::Text); if(!r) { qCWarning(CMAKE) << "Couldn't open commands file" << commandsFile; return {}; } qCDebug(CMAKE) << "Found commands file" << commandsFile; CMakeFilesCompilationData data; QJsonParseError error; const QJsonDocument document = QJsonDocument::fromJson(f.readAll(), &error); if (error.error) { qCWarning(CMAKE) << "Failed to parse JSON in commands file:" << error.errorString() << commandsFile; data.isValid = false; return data; } else if (!document.isArray()) { qCWarning(CMAKE) << "JSON document in commands file is not an array: " << commandsFile; data.isValid = false; return data; } MakeFileResolver resolver; static const QString KEY_COMMAND = QStringLiteral("command"); static const QString KEY_DIRECTORY = QStringLiteral("directory"); static const QString KEY_FILE = QStringLiteral("file"); auto rt = ICore::self()->runtimeController()->currentRuntime(); foreach(const QJsonValue& value, document.array()) { if (!value.isObject()) { qCWarning(CMAKE) << "JSON command file entry is not an object:" << value; continue; } const QJsonObject entry = value.toObject(); if (!entry.contains(KEY_FILE) || !entry.contains(KEY_COMMAND) || !entry.contains(KEY_DIRECTORY)) { qCWarning(CMAKE) << "JSON command file entry does not contain required keys:" << entry; continue; } PathResolutionResult result = resolver.processOutput(entry[KEY_COMMAND].toString(), entry[KEY_DIRECTORY].toString()); auto convert = [rt](const Path &path) { return rt->pathInHost(path); }; CMakeFile ret; ret.includes = kTransform(result.paths, convert); ret.frameworkDirectories = kTransform(result.frameworkDirectories, convert); ret.defines = result.defines; const Path path(rt->pathInHost(Path(entry[KEY_FILE].toString()))); qDebug() << "entering..." << path << entry[KEY_FILE]; data.files[path] = ret; } data.isValid = true; return data; } QVector importTestSuites(const Path &buildDir) { QVector ret; #pragma message("TODO use subdirs instead of this") foreach(const QFileInfo &info, QDir(buildDir.toLocalFile()).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { ret += importTestSuites(Path(buildDir, info.fileName())); } QFile file(buildDir.toLocalFile()+"/CTestTestfile.cmake"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return ret; } const QRegularExpression rx(QStringLiteral("add_test *\\((.+?) (.*?)\\) *$")); Q_ASSERT(rx.isValid()); for (; !file.atEnd();) { QByteArray line = file.readLine(); line.chop(1); const auto match = rx.match(QString::fromLocal8Bit(line)); if (match.hasMatch()) { Test test; QStringList args = KShell::splitArgs(match.captured(2)); test.name = match.captured(1); test.executable = Path(buildDir, args.takeFirst()); test.arguments = args; ret += test; } } return ret; } ImportData import(const Path& commandsFile, const Path &targetsFilePath, const QString &sourceDir, const KDevelop::Path &buildPath) { return ImportData { importCommands(commandsFile), CMake::enumerateTargets(targetsFilePath, sourceDir, buildPath), importTestSuites(buildPath) }; } } CMakeImportJsonJob::CMakeImportJsonJob(IProject* project, QObject* parent) : KJob(parent) , m_project(project) , m_data({}) { connect(&m_futureWatcher, &QFutureWatcher::finished, this, &CMakeImportJsonJob::importCompileCommandsJsonFinished); } CMakeImportJsonJob::~CMakeImportJsonJob() {} void CMakeImportJsonJob::start() { auto commandsFile = CMake::commandsFile(project()); if (!QFileInfo::exists(commandsFile.toLocalFile())) { qCWarning(CMAKE) << "Could not import CMake project" << project()->path() << "('compile_commands.json' missing)"; emitResult(); return; } const Path currentBuildDir = CMake::currentBuildDir(m_project); Q_ASSERT (!currentBuildDir.isEmpty()); const Path targetsFilePath = CMake::targetDirectoriesFile(m_project); const QString sourceDir = m_project->path().toLocalFile(); + auto rt = ICore::self()->runtimeController()->currentRuntime(); - auto future = QtConcurrent::run(import, commandsFile, targetsFilePath, sourceDir, currentBuildDir); + auto future = QtConcurrent::run(import, commandsFile, targetsFilePath, sourceDir, rt->pathInRuntime(currentBuildDir)); m_futureWatcher.setFuture(future); } void CMakeImportJsonJob::importCompileCommandsJsonFinished() { Q_ASSERT(m_project->thread() == QThread::currentThread()); Q_ASSERT(m_futureWatcher.isFinished()); auto future = m_futureWatcher.future(); auto data = future.result(); if (!data.compilationData.isValid) { qCWarning(CMAKE) << "Could not import CMake project ('compile_commands.json' invalid)"; emitResult(); return; } m_data = CMakeProjectData {data.targets, data.compilationData, data.testSuites}; qCDebug(CMAKE) << "Done importing, found" << data.compilationData.files.count() << "entries for" << project()->path(); emitResult(); } IProject* CMakeImportJsonJob::project() const { return m_project; } CMakeProjectData CMakeImportJsonJob::projectData() const { Q_ASSERT(!m_futureWatcher.isRunning()); return m_data; } #include "moc_cmakeimportjsonjob.cpp"