forked from qt-creator/qt-creator
CMake: Factor out code to run cmake from tealeafreader
Change-Id: I10947596ce08eb0148a5bf258bdf26cfced43db1 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
230
src/plugins/cmakeprojectmanager/cmakeprocess.cpp
Normal file
230
src/plugins/cmakeprojectmanager/cmakeprocess.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "cmakeprocess.h"
|
||||
|
||||
#include "cmakeparser.h"
|
||||
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <coreplugin/reaper.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QObject>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
static QString lineSplit(const QString &rest, const QByteArray &array, std::function<void(const QString &)> f)
|
||||
{
|
||||
QString tmp = rest + Utils::SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(array));
|
||||
int start = 0;
|
||||
int end = tmp.indexOf(QLatin1Char('\n'), start);
|
||||
while (end >= 0) {
|
||||
f(tmp.mid(start, end - start));
|
||||
start = end + 1;
|
||||
end = tmp.indexOf(QLatin1Char('\n'), start);
|
||||
}
|
||||
return tmp.mid(start);
|
||||
}
|
||||
|
||||
|
||||
CMakeProcess::CMakeProcess() = default;
|
||||
|
||||
CMakeProcess::~CMakeProcess()
|
||||
{
|
||||
if (m_process) {
|
||||
processStandardOutput();
|
||||
processStandardError();
|
||||
|
||||
m_process->disconnect();
|
||||
Core::Reaper::reap(m_process.release());
|
||||
}
|
||||
|
||||
// Delete issue parser:
|
||||
if (m_parser)
|
||||
m_parser->flush();
|
||||
|
||||
if (m_future) {
|
||||
reportCanceled();
|
||||
reportFinished();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList CMakeProcess::toArguments(const CMakeConfig &config,
|
||||
const Utils::MacroExpander *expander) {
|
||||
return Utils::transform(config, [expander](const CMakeConfigItem &i) -> QString {
|
||||
return i.toArgument(expander);
|
||||
});
|
||||
}
|
||||
|
||||
void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList &arguments)
|
||||
{
|
||||
QTC_ASSERT(!m_process && !m_parser && !m_future, return);
|
||||
|
||||
CMakeTool *cmake = parameters.cmakeTool();
|
||||
QTC_ASSERT(parameters.isValid() && cmake, return);
|
||||
|
||||
const Utils::FilePath workDirectory = parameters.workDirectory;
|
||||
QTC_ASSERT(workDirectory.exists(), return);
|
||||
|
||||
const QString srcDir = parameters.sourceDirectory.toString();
|
||||
|
||||
auto parser = std::make_unique<CMakeParser>();
|
||||
QDir source = QDir(srcDir);
|
||||
connect(parser.get(), &IOutputParser::addTask, parser.get(),
|
||||
[source](const Task &task) {
|
||||
if (task.file.isEmpty() || task.file.toFileInfo().isAbsolute()) {
|
||||
TaskHub::addTask(task);
|
||||
} else {
|
||||
Task t = task;
|
||||
t.file = Utils::FilePath::fromString(source.absoluteFilePath(task.file.toString()));
|
||||
TaskHub::addTask(t);
|
||||
}
|
||||
});
|
||||
|
||||
// Always use the sourceDir: If we are triggered because the build directory is getting deleted
|
||||
// then we are racing against CMakeCache.txt also getting deleted.
|
||||
|
||||
auto process = std::make_unique<Utils::QtcProcess>();
|
||||
process->setWorkingDirectory(workDirectory.toString());
|
||||
process->setEnvironment(parameters.environment);
|
||||
|
||||
connect(process.get(), &QProcess::readyReadStandardOutput,
|
||||
this, &CMakeProcess::processStandardOutput);
|
||||
connect(process.get(), &QProcess::readyReadStandardError,
|
||||
this, &CMakeProcess::processStandardError);
|
||||
connect(process.get(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &CMakeProcess::handleProcessFinished);
|
||||
|
||||
QString args;
|
||||
Utils::QtcProcess::addArg(&args, srcDir);
|
||||
Utils::QtcProcess::addArgs(&args, parameters.generatorArguments);
|
||||
Utils::QtcProcess::addArgs(&args, arguments);
|
||||
|
||||
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
||||
|
||||
Core::MessageManager::write(tr("Running \"%1 %2\" in %3.")
|
||||
.arg(cmake->cmakeExecutable().toUserOutput())
|
||||
.arg(args)
|
||||
.arg(workDirectory.toUserOutput()));
|
||||
|
||||
auto future = std::make_unique<QFutureInterface<void>>();
|
||||
future->setProgressRange(0, 1);
|
||||
Core::ProgressManager::addTask(future->future(),
|
||||
tr("Configuring \"%1\"").arg(parameters.projectName),
|
||||
"CMake.Configure");
|
||||
|
||||
process->setCommand(Utils::CommandLine(cmake->cmakeExecutable(), args, Utils::CommandLine::Raw));
|
||||
emit started();
|
||||
process->start();
|
||||
|
||||
m_process = std::move(process);
|
||||
m_parser = std::move(parser);
|
||||
m_future = std::move(future);
|
||||
}
|
||||
|
||||
QProcess::ProcessState CMakeProcess::state() const
|
||||
{
|
||||
if (m_process)
|
||||
return m_process->state();
|
||||
return QProcess::NotRunning;
|
||||
}
|
||||
|
||||
void CMakeProcess::reportCanceled()
|
||||
{
|
||||
QTC_ASSERT(m_future, return);
|
||||
m_future->reportCanceled();
|
||||
}
|
||||
|
||||
void CMakeProcess::reportFinished()
|
||||
{
|
||||
QTC_ASSERT(m_future, return);
|
||||
m_future->reportFinished();
|
||||
m_future.reset();
|
||||
}
|
||||
|
||||
void CMakeProcess::setProgressValue(int p)
|
||||
{
|
||||
QTC_ASSERT(m_future, return);
|
||||
m_future->setProgressValue(p);
|
||||
}
|
||||
|
||||
void CMakeProcess::processStandardOutput()
|
||||
{
|
||||
QTC_ASSERT(m_process, return);
|
||||
|
||||
static QString rest;
|
||||
rest = lineSplit(rest, m_process->readAllStandardOutput(),
|
||||
[](const QString &s) { Core::MessageManager::write(s); });
|
||||
|
||||
}
|
||||
|
||||
void CMakeProcess::processStandardError()
|
||||
{
|
||||
QTC_ASSERT(m_process, return);
|
||||
|
||||
static QString rest;
|
||||
rest = lineSplit(rest, m_process->readAllStandardError(), [this](const QString &s) {
|
||||
m_parser->stdError(s);
|
||||
Core::MessageManager::write(s);
|
||||
});
|
||||
}
|
||||
|
||||
void CMakeProcess::handleProcessFinished(int code, QProcess::ExitStatus status)
|
||||
{
|
||||
QTC_ASSERT(m_process && m_future, return);
|
||||
|
||||
processStandardOutput();
|
||||
processStandardError();
|
||||
|
||||
QString msg;
|
||||
if (status != QProcess::NormalExit)
|
||||
msg = tr("*** cmake process crashed.");
|
||||
else if (code != 0)
|
||||
msg = tr("*** cmake process exited with exit code %1.").arg(code);
|
||||
|
||||
if (!msg.isEmpty()) {
|
||||
Core::MessageManager::write(msg);
|
||||
TaskHub::addTask(Task::Error, msg, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
||||
m_future->reportCanceled();
|
||||
} else {
|
||||
m_future->setProgressValue(1);
|
||||
}
|
||||
|
||||
m_future->reportFinished();
|
||||
|
||||
emit finished(code, status);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CMakeProjectManager
|
||||
Reference in New Issue
Block a user