QbsProjectManager: Switch to an out-of-process approach

That is, do not link to the qbscore library anymore. Instead, use the
JSON-based API.
Advantages:
    - We can build Qt Creator with qbs support without qbs being present
      on the build machine.
    - Smaller memory footprint for Qt Creator, as the qbs build graphs
      are now being managed by a separate process.
    - Potential crashes in qbs will not kill the Qt Creator process.

Fixes: QTCREATORBUG-20622
Task-number: QTCREATORBUG-22904
Change-Id: If7d344b0ac65a99ff0a3a3db215d61b8d903e47e
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Christian Kandeler
2019-06-28 14:30:32 +02:00
parent c2127c9ec4
commit 6913947986
38 changed files with 2339 additions and 1972 deletions

View File

@@ -28,6 +28,7 @@
#include "qbsbuildconfiguration.h"
#include "qbsproject.h"
#include "qbsprojectmanagerconstants.h"
#include "qbssession.h"
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/kit.h>
@@ -36,6 +37,9 @@
#include <projectexplorer/target.h>
#include <utils/qtcassert.h>
#include <QJsonArray>
#include <QJsonObject>
using namespace ProjectExplorer;
namespace QbsProjectManager {
@@ -73,66 +77,60 @@ QbsCleanStep::QbsCleanStep(ProjectExplorer::BuildStepList *bsl) :
QbsCleanStep::~QbsCleanStep()
{
doCancel();
if (m_job) {
m_job->deleteLater();
m_job = nullptr;
}
if (m_session)
m_session->disconnect(this);
}
bool QbsCleanStep::init()
{
if (buildSystem()->isParsing() || m_job)
if (buildSystem()->isParsing() || m_session)
return false;
auto bc = static_cast<QbsBuildConfiguration *>(buildConfiguration());
const auto bc = static_cast<QbsBuildConfiguration *>(buildConfiguration());
if (!bc)
return false;
m_products = bc->products();
return true;
}
void QbsCleanStep::doRun()
{
qbs::CleanOptions options;
options.setDryRun(m_dryRunAspect->value());
options.setKeepGoing(m_keepGoingAspect->value());
QString error;
m_job = qbsBuildSystem()->clean(options, m_products, error);
if (!m_job) {
emit addOutput(error, OutputFormat::ErrorMessage);
m_session = static_cast<QbsBuildSystem*>(buildSystem())->session();
if (!m_session) {
emit addOutput(tr("No qbs session exists for this target."), OutputFormat::ErrorMessage);
emit finished(false);
return;
}
QJsonObject request;
request.insert("type", "clean-project");
if (!m_products.isEmpty())
request.insert("products", QJsonArray::fromStringList(m_products));
request.insert("dry-run", m_dryRunAspect->value());
request.insert("keep-going", m_keepGoingAspect->value());
m_session->sendRequest(request);
m_maxProgress = 0;
connect(m_job, &qbs::AbstractJob::finished, this, &QbsCleanStep::cleaningDone);
connect(m_job, &qbs::AbstractJob::taskStarted,
this, &QbsCleanStep::handleTaskStarted);
connect(m_job, &qbs::AbstractJob::taskProgress,
this, &QbsCleanStep::handleProgress);
connect(m_session, &QbsSession::projectCleaned, this, &QbsCleanStep::cleaningDone);
connect(m_session, &QbsSession::taskStarted, this, &QbsCleanStep::handleTaskStarted);
connect(m_session, &QbsSession::taskProgress, this, &QbsCleanStep::handleProgress);
connect(m_session, &QbsSession::errorOccurred, this, [this] {
cleaningDone(ErrorInfo(tr("Cleaning canceled: Qbs session failed.")));
});
}
void QbsCleanStep::doCancel()
{
if (m_job)
m_job->cancel();
if (m_session)
m_session->cancelCurrentJob();
}
void QbsCleanStep::cleaningDone(bool success)
void QbsCleanStep::cleaningDone(const ErrorInfo &error)
{
// Report errors:
foreach (const qbs::ErrorItem &item, m_job->error().items()) {
createTaskAndOutput(ProjectExplorer::Task::Error, item.description(),
item.codeLocation().filePath(), item.codeLocation().line());
}
m_session->disconnect(this);
m_session = nullptr;
emit finished(success);
m_job->deleteLater();
m_job = nullptr;
for (const ErrorInfoItem &item : error.items)
createTaskAndOutput(Task::Error, item.description, item.filePath.toString(), item.line);
emit finished(!error.hasError());
}
void QbsCleanStep::handleTaskStarted(const QString &desciption, int max)
@@ -149,9 +147,8 @@ void QbsCleanStep::handleProgress(int value)
void QbsCleanStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message, const QString &file, int line)
{
ProjectExplorer::Task task = ProjectExplorer::Task(type, message,
Utils::FilePath::fromString(file), line,
ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
Task task(type, message, Utils::FilePath::fromString(file), line,
ProjectExplorer::Constants::TASK_CATEGORY_COMPILE);
emit addTask(task, 1);
emit addOutput(message, OutputFormat::Stdout);
}