2019-06-05 18:09:02 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** 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/progressmanager/progressmanager.h>
|
2021-06-01 16:21:03 +02:00
|
|
|
#include <projectexplorer/buildsystem.h>
|
2019-06-05 18:09:02 +02:00
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
|
|
|
#include <projectexplorer/taskhub.h>
|
|
|
|
|
|
2020-02-28 15:09:35 +01:00
|
|
|
#include <utils/stringutils.h>
|
2019-06-05 18:09:02 +02:00
|
|
|
|
2021-05-14 15:21:54 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2019-06-05 18:09:02 +02:00
|
|
|
namespace CMakeProjectManager {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
|
2021-06-14 12:06:23 +02:00
|
|
|
static QString stripTrailingNewline(QString str)
|
2019-06-05 18:09:02 +02:00
|
|
|
{
|
2021-06-14 12:06:23 +02:00
|
|
|
if (str.endsWith('\n'))
|
|
|
|
|
str.chop(1);
|
|
|
|
|
return str;
|
2019-06-05 18:09:02 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-14 16:42:41 +02:00
|
|
|
CMakeProcess::CMakeProcess()
|
|
|
|
|
{
|
|
|
|
|
connect(&m_cancelTimer, &QTimer::timeout, this, &CMakeProcess::checkForCancelled);
|
|
|
|
|
m_cancelTimer.setInterval(500);
|
|
|
|
|
}
|
2019-06-05 18:09:02 +02:00
|
|
|
|
|
|
|
|
CMakeProcess::~CMakeProcess()
|
|
|
|
|
{
|
2021-09-06 14:48:08 +02:00
|
|
|
m_process.reset();
|
2020-04-15 14:59:51 +02:00
|
|
|
m_parser.flush();
|
2019-06-05 18:09:02 +02:00
|
|
|
|
|
|
|
|
if (m_future) {
|
|
|
|
|
reportCanceled();
|
|
|
|
|
reportFinished();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList &arguments)
|
|
|
|
|
{
|
2020-04-15 14:59:51 +02:00
|
|
|
QTC_ASSERT(!m_process && !m_future, return);
|
2019-06-05 18:09:02 +02:00
|
|
|
|
|
|
|
|
CMakeTool *cmake = parameters.cmakeTool();
|
|
|
|
|
QTC_ASSERT(parameters.isValid() && cmake, return);
|
|
|
|
|
|
2021-06-14 12:06:23 +02:00
|
|
|
const FilePath buildDirectory = parameters.buildDirectory;
|
2021-08-25 12:09:10 +02:00
|
|
|
if (!buildDirectory.exists()) {
|
|
|
|
|
QString msg = tr("The build directory \"%1\" does not exist")
|
|
|
|
|
.arg(buildDirectory.toUserOutput());
|
|
|
|
|
BuildSystem::appendBuildSystemOutput(msg + '\n');
|
|
|
|
|
emit finished();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buildDirectory.needsDevice()) {
|
|
|
|
|
if (cmake->cmakeExecutable().host() != buildDirectory.host()) {
|
|
|
|
|
QString msg = tr("CMake executable \"%1\" and build directory "
|
|
|
|
|
"\"%2\" must be on the same device.")
|
|
|
|
|
.arg(cmake->cmakeExecutable().toUserOutput(), buildDirectory.toUserOutput());
|
|
|
|
|
BuildSystem::appendBuildSystemOutput(msg + '\n');
|
|
|
|
|
emit finished();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-05 18:09:02 +02:00
|
|
|
|
2020-04-15 14:59:51 +02:00
|
|
|
const auto parser = new CMakeParser;
|
2021-10-12 13:51:44 +02:00
|
|
|
parser->setSourceDirectory(parameters.sourceDirectory.path());
|
2020-04-15 14:59:51 +02:00
|
|
|
m_parser.addLineParser(parser);
|
2019-06-05 18:09:02 +02:00
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
2021-06-14 12:06:23 +02:00
|
|
|
auto process = std::make_unique<QtcProcess>();
|
2019-06-14 16:42:41 +02:00
|
|
|
m_processWasCanceled = false;
|
|
|
|
|
|
|
|
|
|
m_cancelTimer.start();
|
|
|
|
|
|
2021-06-09 15:08:13 +02:00
|
|
|
process->setWorkingDirectory(buildDirectory);
|
2019-06-05 18:09:02 +02:00
|
|
|
process->setEnvironment(parameters.environment);
|
|
|
|
|
|
2021-06-14 12:06:23 +02:00
|
|
|
process->setStdOutLineCallback([](const QString &s) {
|
|
|
|
|
BuildSystem::appendBuildSystemOutput(stripTrailingNewline(s));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
process->setStdErrLineCallback([this](const QString &s) {
|
|
|
|
|
m_parser.appendMessage(s, StdErrFormat);
|
|
|
|
|
BuildSystem::appendBuildSystemOutput(stripTrailingNewline(s));
|
|
|
|
|
});
|
|
|
|
|
|
2021-05-14 15:21:54 +02:00
|
|
|
connect(process.get(), &QtcProcess::finished,
|
2019-06-05 18:09:02 +02:00
|
|
|
this, &CMakeProcess::handleProcessFinished);
|
|
|
|
|
|
2021-10-12 13:51:44 +02:00
|
|
|
const FilePath cmakeExecutable = cmake->cmakeExecutable();
|
|
|
|
|
const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable);
|
|
|
|
|
|
|
|
|
|
CommandLine commandLine(cmakeExecutable);
|
|
|
|
|
commandLine.addArgs({"-S", sourceDirectory.mapToDevicePath(),
|
|
|
|
|
"-B", buildDirectory.mapToDevicePath()});
|
|
|
|
|
commandLine.addArgs(arguments);
|
2019-06-05 18:09:02 +02:00
|
|
|
|
|
|
|
|
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
|
|
|
|
|
2021-06-01 16:21:03 +02:00
|
|
|
BuildSystem::startNewBuildSystemOutput(
|
2021-06-09 15:08:13 +02:00
|
|
|
tr("Running %1 in %2.").arg(commandLine.toUserOutput()).arg(buildDirectory.toUserOutput()));
|
2019-06-05 18:09:02 +02:00
|
|
|
|
|
|
|
|
auto future = std::make_unique<QFutureInterface<void>>();
|
|
|
|
|
future->setProgressRange(0, 1);
|
2019-06-17 12:39:40 +02:00
|
|
|
Core::ProgressManager::addTimedTask(*future.get(),
|
|
|
|
|
tr("Configuring \"%1\"").arg(parameters.projectName),
|
|
|
|
|
"CMake.Configure",
|
|
|
|
|
10);
|
2019-06-05 18:09:02 +02:00
|
|
|
|
2019-06-07 15:26:00 +02:00
|
|
|
process->setCommand(commandLine);
|
2019-06-05 18:09:02 +02:00
|
|
|
emit started();
|
2020-02-28 12:44:00 +01:00
|
|
|
m_elapsed.start();
|
2019-06-05 18:09:02 +02:00
|
|
|
process->start();
|
|
|
|
|
|
|
|
|
|
m_process = std::move(process);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-28 14:48:25 +02:00
|
|
|
void CMakeProcess::handleProcessFinished()
|
2019-06-05 18:09:02 +02:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_process && m_future, return);
|
|
|
|
|
|
2019-06-14 16:42:41 +02:00
|
|
|
m_cancelTimer.stop();
|
|
|
|
|
|
2021-05-28 14:48:25 +02:00
|
|
|
const int code = m_process->exitCode();
|
2021-06-14 12:06:23 +02:00
|
|
|
|
2019-06-05 18:09:02 +02:00
|
|
|
QString msg;
|
2021-05-28 14:48:25 +02:00
|
|
|
if (m_process->exitStatus() != QProcess::NormalExit) {
|
2019-06-14 16:42:41 +02:00
|
|
|
if (m_processWasCanceled) {
|
2019-10-28 16:12:21 +01:00
|
|
|
msg = tr("CMake process was canceled by the user.");
|
2019-06-14 16:42:41 +02:00
|
|
|
} else {
|
2019-10-28 16:12:21 +01:00
|
|
|
msg = tr("CMake process crashed.");
|
2019-06-14 16:42:41 +02:00
|
|
|
}
|
|
|
|
|
} else if (code != 0) {
|
2019-10-28 16:12:21 +01:00
|
|
|
msg = tr("CMake process exited with exit code %1.").arg(code);
|
2019-06-14 16:42:41 +02:00
|
|
|
}
|
2020-09-28 15:10:04 +02:00
|
|
|
m_lastExitCode = code;
|
2019-06-05 18:09:02 +02:00
|
|
|
|
|
|
|
|
if (!msg.isEmpty()) {
|
2021-06-14 12:06:23 +02:00
|
|
|
BuildSystem::appendBuildSystemOutput(msg + '\n');
|
2020-01-15 08:56:11 +01:00
|
|
|
TaskHub::addTask(BuildSystemTask(Task::Error, msg));
|
2019-06-05 18:09:02 +02:00
|
|
|
m_future->reportCanceled();
|
|
|
|
|
} else {
|
|
|
|
|
m_future->setProgressValue(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_future->reportFinished();
|
|
|
|
|
|
2021-06-08 13:40:45 +02:00
|
|
|
emit finished();
|
2020-02-28 12:44:00 +01:00
|
|
|
|
2020-02-28 15:09:35 +01:00
|
|
|
const QString elapsedTime = Utils::formatElapsedTime(m_elapsed.elapsed());
|
2021-06-14 12:06:23 +02:00
|
|
|
BuildSystem::appendBuildSystemOutput(elapsedTime + '\n');
|
2019-06-05 18:09:02 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-14 16:42:41 +02:00
|
|
|
void CMakeProcess::checkForCancelled()
|
|
|
|
|
{
|
|
|
|
|
if (!m_process || !m_future)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (m_future->isCanceled()) {
|
|
|
|
|
m_cancelTimer.stop();
|
|
|
|
|
m_processWasCanceled = true;
|
|
|
|
|
m_process->close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-05 18:09:02 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace CMakeProjectManager
|