2013-01-30 18:19:31 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2013-01-30 18:19:31 +01:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2013-01-30 18:19:31 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2013-01-30 18:19:31 +01:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "qbsproject.h"
|
|
|
|
|
|
|
|
|
|
#include "qbsbuildconfiguration.h"
|
2018-04-16 15:57:20 +02:00
|
|
|
#include "qbsbuildstep.h"
|
2019-10-10 17:19:09 +02:00
|
|
|
#include "qbsinstallstep.h"
|
2019-06-28 14:30:32 +02:00
|
|
|
#include "qbsnodes.h"
|
2016-03-11 11:21:11 +01:00
|
|
|
#include "qbspmlogging.h"
|
2017-06-07 18:35:51 +02:00
|
|
|
#include "qbsprojectimporter.h"
|
2014-06-16 14:42:21 +02:00
|
|
|
#include "qbsprojectparser.h"
|
2013-01-30 18:19:31 +01:00
|
|
|
#include "qbsprojectmanagerconstants.h"
|
2017-02-20 13:33:11 +01:00
|
|
|
#include "qbsnodetreebuilder.h"
|
2019-06-28 14:30:32 +02:00
|
|
|
#include "qbssession.h"
|
2019-11-21 17:07:11 +01:00
|
|
|
#include "qbssettings.h"
|
2013-01-30 18:19:31 +01:00
|
|
|
|
|
|
|
|
#include <coreplugin/documentmanager.h>
|
|
|
|
|
#include <coreplugin/icontext.h>
|
2014-08-18 16:30:43 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2019-08-15 12:25:20 +02:00
|
|
|
#include <coreplugin/id.h>
|
2014-08-18 16:30:43 +02:00
|
|
|
#include <coreplugin/iversioncontrol.h>
|
2014-07-18 15:46:24 +02:00
|
|
|
#include <coreplugin/messagemanager.h>
|
2013-01-30 18:19:31 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2019-08-15 12:25:20 +02:00
|
|
|
#include <coreplugin/vcsmanager.h>
|
2014-09-15 00:12:27 +02:00
|
|
|
#include <cpptools/cppmodelmanager.h>
|
2017-02-06 16:59:53 +01:00
|
|
|
#include <cpptools/cppprojectupdater.h>
|
2019-08-28 12:23:37 +02:00
|
|
|
#include <cpptools/cpptoolsconstants.h>
|
2019-08-15 12:25:20 +02:00
|
|
|
#include <cpptools/generatedcodemodelsupport.h>
|
2016-01-15 16:12:54 +01:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
2013-01-30 18:19:31 +01:00
|
|
|
#include <projectexplorer/buildenvironmentwidget.h>
|
2017-07-27 10:10:51 +02:00
|
|
|
#include <projectexplorer/buildinfo.h>
|
2014-02-25 13:50:56 +01:00
|
|
|
#include <projectexplorer/buildmanager.h>
|
2013-09-02 10:12:37 +02:00
|
|
|
#include <projectexplorer/buildtargetinfo.h>
|
2019-10-10 17:19:09 +02:00
|
|
|
#include <projectexplorer/deployconfiguration.h>
|
2013-09-02 10:12:37 +02:00
|
|
|
#include <projectexplorer/deploymentdata.h>
|
2019-08-15 12:25:20 +02:00
|
|
|
#include <projectexplorer/headerpath.h>
|
2013-01-30 18:19:31 +01:00
|
|
|
#include <projectexplorer/kit.h>
|
|
|
|
|
#include <projectexplorer/kitinformation.h>
|
|
|
|
|
#include <projectexplorer/projectexplorer.h>
|
|
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
|
|
|
#include <projectexplorer/target.h>
|
|
|
|
|
#include <projectexplorer/taskhub.h>
|
2013-03-26 15:06:51 +01:00
|
|
|
#include <projectexplorer/toolchain.h>
|
2019-08-15 12:25:20 +02:00
|
|
|
#include <utils/algorithm.h>
|
2014-03-28 13:26:46 +01:00
|
|
|
#include <utils/hostosinfo.h>
|
2014-07-18 15:46:24 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2020-02-04 14:59:08 +01:00
|
|
|
#include <utils/runextensions.h>
|
2019-08-15 12:25:20 +02:00
|
|
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
|
|
|
|
#include <qmljstools/qmljsmodelmanager.h>
|
|
|
|
|
#include <qtsupport/qtcppkitinfo.h>
|
|
|
|
|
#include <qtsupport/qtkitinformation.h>
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2014-02-25 16:39:09 +01:00
|
|
|
#include <QCoreApplication>
|
2017-01-24 18:13:48 +01:00
|
|
|
#include <QElapsedTimer>
|
2013-01-30 18:19:31 +01:00
|
|
|
#include <QFileInfo>
|
2019-06-28 14:30:32 +02:00
|
|
|
#include <QJsonArray>
|
2014-08-18 16:30:43 +02:00
|
|
|
#include <QMessageBox>
|
2018-10-17 11:25:36 +03:00
|
|
|
#include <QSet>
|
2014-07-22 09:49:51 +02:00
|
|
|
#include <QVariantMap>
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2016-11-23 12:17:02 +01:00
|
|
|
#include <algorithm>
|
2017-04-07 13:46:50 +02:00
|
|
|
#include <type_traits>
|
2016-11-23 12:17:02 +01:00
|
|
|
|
2013-08-29 17:56:28 +02:00
|
|
|
using namespace Core;
|
2013-08-29 18:25:59 +02:00
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
using namespace Utils;
|
2013-08-29 17:56:28 +02:00
|
|
|
|
|
|
|
|
namespace QbsProjectManager {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
// Constants:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
2017-01-24 18:13:48 +01:00
|
|
|
class OpTimer
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
OpTimer(const char *name) : m_name(name)
|
|
|
|
|
{
|
|
|
|
|
m_timer.start();
|
|
|
|
|
}
|
|
|
|
|
~OpTimer()
|
|
|
|
|
{
|
|
|
|
|
if (qEnvironmentVariableIsSet(Constants::QBS_PROFILING_ENV)) {
|
|
|
|
|
MessageManager::write(QString("operation %1 took %2ms")
|
|
|
|
|
.arg(QLatin1String(m_name)).arg(m_timer.elapsed()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QElapsedTimer m_timer;
|
|
|
|
|
const char * const m_name;
|
|
|
|
|
};
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
// QbsProject:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
2019-08-15 12:25:20 +02:00
|
|
|
QbsProject::QbsProject(const FilePath &fileName)
|
|
|
|
|
: Project(Constants::MIME_TYPE, fileName)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2013-09-27 16:30:20 +02:00
|
|
|
setId(Constants::PROJECT_ID);
|
2017-01-30 14:59:10 +01:00
|
|
|
setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
|
2019-06-03 17:36:02 +02:00
|
|
|
setCanBuildProducts();
|
2019-10-25 09:55:32 +02:00
|
|
|
setDisplayName(fileName.toFileInfo().completeBaseName());
|
|
|
|
|
}
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
QbsProject::~QbsProject()
|
|
|
|
|
{
|
|
|
|
|
delete m_importer;
|
|
|
|
|
}
|
2019-10-22 14:55:51 +02:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
ProjectImporter *QbsProject::projectImporter() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_importer)
|
|
|
|
|
m_importer = new QbsProjectImporter(projectFilePath());
|
|
|
|
|
return m_importer;
|
|
|
|
|
}
|
2017-04-07 14:35:49 +02:00
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
void QbsProject::configureAsExampleProject()
|
2019-10-25 09:55:32 +02:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
QList<BuildInfo> infoList;
|
|
|
|
|
const QList<Kit *> kits = KitManager::kits();
|
|
|
|
|
for (Kit *k : kits) {
|
|
|
|
|
if (QtSupport::QtKitAspect::qtVersion(k) != nullptr) {
|
|
|
|
|
if (auto factory = BuildConfigurationFactory::find(k, projectFilePath()))
|
|
|
|
|
infoList << factory->allAvailableSetups(k, projectFilePath());
|
|
|
|
|
}
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
setup(infoList);
|
|
|
|
|
if (activeTarget())
|
|
|
|
|
static_cast<QbsBuildSystem *>(activeTarget()->buildSystem())->prepareForParsing();
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
2019-08-02 13:59:21 +02:00
|
|
|
|
2013-06-06 18:45:53 +02:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
static bool supportsNodeAction(ProjectAction action, const Node *node)
|
|
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
const auto project = static_cast<QbsProject *>(node->getProject());
|
2019-10-25 09:55:32 +02:00
|
|
|
Target *t = project ? project->activeTarget() : nullptr;
|
|
|
|
|
QbsBuildSystem *bs = t ? static_cast<QbsBuildSystem *>(t->buildSystem()) : nullptr;
|
|
|
|
|
if (!bs)
|
|
|
|
|
return false;
|
|
|
|
|
if (!bs->isProjectEditable())
|
|
|
|
|
return false;
|
|
|
|
|
if (action == RemoveFile || action == Rename)
|
|
|
|
|
return node->asFileNode();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-08-15 12:25:20 +02:00
|
|
|
|
2020-03-02 09:41:58 +01:00
|
|
|
static QString buildKeyValue(const QJsonObject &product)
|
|
|
|
|
{
|
|
|
|
|
return product.value("name").toString() + '.'
|
|
|
|
|
+ product.value("multiplex-configuration-id").toString();
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc)
|
|
|
|
|
: BuildSystem(bc->target()),
|
2019-06-28 14:30:32 +02:00
|
|
|
m_session(new QbsSession(this)),
|
2019-10-25 09:55:32 +02:00
|
|
|
m_cppCodeModelUpdater(new CppTools::CppProjectUpdater),
|
|
|
|
|
m_buildConfiguration(bc)
|
|
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
connect(m_session, &QbsSession::newGeneratedFilesForSources, this,
|
|
|
|
|
[this](const QHash<QString, QStringList> &generatedFiles) {
|
|
|
|
|
for (ExtraCompiler * const ec : qAsConst(m_extraCompilers))
|
|
|
|
|
ec->deleteLater();
|
|
|
|
|
m_extraCompilers.clear();
|
|
|
|
|
for (auto it = m_sourcesForGeneratedFiles.cbegin();
|
|
|
|
|
it != m_sourcesForGeneratedFiles.cend(); ++it) {
|
|
|
|
|
for (const QString &sourceFile : it.value()) {
|
2019-12-17 14:07:53 +01:00
|
|
|
const FilePaths generatedFilePaths = transform(
|
2019-06-28 14:30:32 +02:00
|
|
|
generatedFiles.value(sourceFile),
|
|
|
|
|
[](const QString &s) { return FilePath::fromString(s); });
|
|
|
|
|
if (!generatedFilePaths.empty()) {
|
|
|
|
|
m_extraCompilers.append(it.key()->create(
|
|
|
|
|
project(), FilePath::fromString(sourceFile),
|
|
|
|
|
generatedFilePaths));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CppTools::GeneratedCodeModelSupport::update(m_extraCompilers);
|
|
|
|
|
m_sourcesForGeneratedFiles.clear();
|
|
|
|
|
});
|
|
|
|
|
connect(m_session, &QbsSession::errorOccurred, this, [](QbsSession::Error e) {
|
2020-01-15 08:56:11 +01:00
|
|
|
const QString msg = tr("Fatal qbs error: %1").arg(QbsSession::errorString(e));
|
|
|
|
|
TaskHub::addTask(BuildSystemTask(Task::Error, msg));
|
2019-06-28 14:30:32 +02:00
|
|
|
});
|
|
|
|
|
connect(m_session, &QbsSession::fileListUpdated, this, &QbsBuildSystem::delayParsing);
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
m_parsingDelay.setInterval(1000); // delay parsing by 1s.
|
|
|
|
|
delayParsing();
|
|
|
|
|
|
|
|
|
|
connect(bc->project(), &Project::activeTargetChanged,
|
|
|
|
|
this, &QbsBuildSystem::changeActiveTarget);
|
|
|
|
|
|
|
|
|
|
connect(bc->target(), &Target::activeBuildConfigurationChanged,
|
|
|
|
|
this, &QbsBuildSystem::delayParsing);
|
|
|
|
|
|
|
|
|
|
connect(&m_parsingDelay, &QTimer::timeout, this, &QbsBuildSystem::triggerParsing);
|
|
|
|
|
|
|
|
|
|
connect(bc->project(), &Project::projectFileIsDirty, this, &QbsBuildSystem::delayParsing);
|
2020-02-04 14:59:08 +01:00
|
|
|
updateProjectNodes({});
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QbsBuildSystem::~QbsBuildSystem()
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2017-02-06 16:59:53 +01:00
|
|
|
delete m_cppCodeModelUpdater;
|
2014-06-16 14:42:21 +02:00
|
|
|
delete m_qbsProjectParser;
|
2014-08-22 09:39:38 +02:00
|
|
|
if (m_qbsUpdateFutureInterface) {
|
|
|
|
|
m_qbsUpdateFutureInterface->reportCanceled();
|
2014-09-13 21:25:32 +03:00
|
|
|
m_qbsUpdateFutureInterface->reportFinished();
|
2014-08-22 09:39:38 +02:00
|
|
|
delete m_qbsUpdateFutureInterface;
|
2018-07-27 12:10:20 +02:00
|
|
|
m_qbsUpdateFutureInterface = nullptr;
|
2014-08-22 09:39:38 +02:00
|
|
|
}
|
2016-01-15 16:12:54 +01:00
|
|
|
qDeleteAll(m_extraCompilers);
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
bool QbsBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
|
2016-03-02 10:20:43 +02:00
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
if (dynamic_cast<QbsGroupNode *>(context)) {
|
|
|
|
|
if (action == AddNewFile || action == AddExistingFile)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dynamic_cast<QbsProductNode *>(context)) {
|
|
|
|
|
if (action == AddNewFile || action == AddExistingFile)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return supportsNodeAction(action, node);
|
2016-03-02 10:20:43 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
bool QbsBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded)
|
2017-06-07 18:35:51 +02:00
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
if (auto n = dynamic_cast<QbsGroupNode *>(context)) {
|
|
|
|
|
QStringList notAddedDummy;
|
|
|
|
|
if (!notAdded)
|
|
|
|
|
notAdded = ¬AddedDummy;
|
|
|
|
|
|
|
|
|
|
const QbsProductNode *prdNode = parentQbsProductNode(n);
|
2019-06-28 14:30:32 +02:00
|
|
|
QTC_ASSERT(prdNode, *notAdded += filePaths; return false);
|
|
|
|
|
return addFilesToProduct(filePaths, prdNode->productData(), n->groupData(), notAdded);
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto n = dynamic_cast<QbsProductNode *>(context)) {
|
|
|
|
|
QStringList notAddedDummy;
|
|
|
|
|
if (!notAdded)
|
|
|
|
|
notAdded = ¬AddedDummy;
|
2019-06-28 14:30:32 +02:00
|
|
|
return addFilesToProduct(filePaths, n->productData(), n->mainGroup(), notAdded);
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BuildSystem::addFiles(context, filePaths, notAdded);
|
2017-06-07 18:35:51 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
RemovedFilesFromProject QbsBuildSystem::removeFiles(Node *context, const QStringList &filePaths,
|
|
|
|
|
QStringList *notRemoved)
|
|
|
|
|
{
|
|
|
|
|
if (auto n = dynamic_cast<QbsGroupNode *>(context)) {
|
|
|
|
|
QStringList notRemovedDummy;
|
|
|
|
|
if (!notRemoved)
|
|
|
|
|
notRemoved = ¬RemovedDummy;
|
2019-06-28 14:30:32 +02:00
|
|
|
const QbsProductNode * const prdNode = parentQbsProductNode(n);
|
|
|
|
|
QTC_ASSERT(prdNode, *notRemoved += filePaths; return RemovedFilesFromProject::Error);
|
|
|
|
|
return removeFilesFromProduct(filePaths, prdNode->productData(), n->groupData(),
|
|
|
|
|
notRemoved);
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto n = dynamic_cast<QbsProductNode *>(context)) {
|
|
|
|
|
QStringList notRemovedDummy;
|
|
|
|
|
if (!notRemoved)
|
|
|
|
|
notRemoved = ¬RemovedDummy;
|
2019-06-28 14:30:32 +02:00
|
|
|
return removeFilesFromProduct(filePaths, n->productData(), n->mainGroup(), notRemoved);
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BuildSystem::removeFiles(context, filePaths, notRemoved);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QbsBuildSystem::renameFile(Node *context, const QString &filePath, const QString &newFilePath)
|
|
|
|
|
{
|
|
|
|
|
if (auto *n = dynamic_cast<QbsGroupNode *>(context)) {
|
2019-06-28 14:30:32 +02:00
|
|
|
const QbsProductNode * const prdNode = parentQbsProductNode(n);
|
|
|
|
|
QTC_ASSERT(prdNode, return false);
|
|
|
|
|
return renameFileInProduct(filePath, newFilePath, prdNode->productData(), n->groupData());
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto *n = dynamic_cast<QbsProductNode *>(context)) {
|
2019-06-28 14:30:32 +02:00
|
|
|
return renameFileInProduct(filePath, newFilePath, n->productData(), n->mainGroup());
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BuildSystem::renameFile(context, filePath, newFilePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant QbsBuildSystem::additionalData(Id id) const
|
2018-08-20 14:48:02 +02:00
|
|
|
{
|
|
|
|
|
if (id == "QmlDesignerImportPath") {
|
|
|
|
|
QStringList designerImportPaths;
|
2019-06-28 14:30:32 +02:00
|
|
|
const QJsonObject project = session()->projectData();
|
|
|
|
|
QStringList paths;
|
|
|
|
|
forAllProducts(project, [&paths](const QJsonObject &product) {
|
|
|
|
|
for (const QJsonValue &v : product.value("properties").toObject()
|
|
|
|
|
.value("qmlDesignerImportPaths").toArray()) {
|
|
|
|
|
paths << v.toString();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return paths;
|
2018-08-20 14:48:02 +02:00
|
|
|
}
|
2019-10-25 09:55:32 +02:00
|
|
|
return BuildSystem::additionalData(id);
|
2018-08-20 14:48:02 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-12 14:49:59 +02:00
|
|
|
ProjectExplorer::DeploymentKnowledge QbsProject::deploymentKnowledge() const
|
|
|
|
|
{
|
|
|
|
|
return DeploymentKnowledge::Perfect;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
QStringList QbsBuildSystem::filesGeneratedFrom(const QString &sourceFile) const
|
2016-03-01 16:03:58 +01:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
return session()->filesGeneratedFrom(sourceFile);
|
2016-03-01 16:03:58 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
bool QbsBuildSystem::isProjectEditable() const
|
2014-07-24 12:18:29 +02:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
return !isParsing() && !BuildManager::isBuilding(target());
|
2014-07-24 12:18:29 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
bool QbsBuildSystem::ensureWriteableQbsFile(const QString &file)
|
2014-08-18 16:30:43 +02:00
|
|
|
{
|
|
|
|
|
// Ensure that the file is not read only
|
|
|
|
|
QFileInfo fi(file);
|
|
|
|
|
if (!fi.isWritable()) {
|
|
|
|
|
// Try via vcs manager
|
2015-02-03 23:56:02 +02:00
|
|
|
IVersionControl *versionControl =
|
|
|
|
|
VcsManager::findVersionControlForDirectory(fi.absolutePath());
|
2014-08-18 16:30:43 +02:00
|
|
|
if (!versionControl || !versionControl->vcsOpen(file)) {
|
|
|
|
|
bool makeWritable = QFile::setPermissions(file, fi.permissions() | QFile::WriteUser);
|
|
|
|
|
if (!makeWritable) {
|
2015-02-03 23:56:02 +02:00
|
|
|
QMessageBox::warning(ICore::mainWindow(),
|
2016-11-04 10:42:39 +01:00
|
|
|
tr("Failed"),
|
2014-08-18 16:30:43 +02:00
|
|
|
tr("Could not write project file %1.").arg(file));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
bool QbsBuildSystem::addFilesToProduct(
|
|
|
|
|
const QStringList &filePaths,
|
|
|
|
|
const QJsonObject &product,
|
|
|
|
|
const QJsonObject &group,
|
|
|
|
|
QStringList *notAdded)
|
2014-07-18 15:46:24 +02:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
const QString groupFilePath = group.value("location").toObject().value("file-path").toString();
|
|
|
|
|
ensureWriteableQbsFile(groupFilePath);
|
|
|
|
|
const FileChangeResult result = session()->addFiles(
|
|
|
|
|
filePaths,
|
|
|
|
|
product.value("full-display-name").toString(),
|
|
|
|
|
group.value("name").toString());
|
|
|
|
|
if (result.error().hasError()) {
|
|
|
|
|
MessageManager::write(result.error().toString(), Core::MessageManager::ModeSwitch);
|
|
|
|
|
*notAdded = result.failedFiles();
|
2014-07-18 15:46:24 +02:00
|
|
|
}
|
|
|
|
|
return notAdded->isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
RemovedFilesFromProject QbsBuildSystem::removeFilesFromProduct(
|
|
|
|
|
const QStringList &filePaths,
|
|
|
|
|
const QJsonObject &product,
|
|
|
|
|
const QJsonObject &group,
|
|
|
|
|
QStringList *notRemoved)
|
2014-07-18 15:46:24 +02:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
const auto allWildcardsInGroup = transform<QStringList>(
|
|
|
|
|
group.value("source-artifacts-from-wildcards").toArray(),
|
|
|
|
|
[](const QJsonValue &v) { return v.toObject().value("file-path").toString(); });
|
2019-06-18 14:39:38 +03:00
|
|
|
QStringList wildcardFiles;
|
|
|
|
|
QStringList nonWildcardFiles;
|
|
|
|
|
for (const QString &filePath : filePaths) {
|
2019-06-28 14:30:32 +02:00
|
|
|
if (allWildcardsInGroup.contains(filePath))
|
2019-06-18 14:39:38 +03:00
|
|
|
wildcardFiles << filePath;
|
2019-06-28 14:30:32 +02:00
|
|
|
else
|
2019-06-18 14:39:38 +03:00
|
|
|
nonWildcardFiles << filePath;
|
2014-07-18 15:46:24 +02:00
|
|
|
}
|
2019-06-18 14:39:38 +03:00
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
const QString groupFilePath = group.value("location")
|
|
|
|
|
.toObject().value("file-path").toString();
|
|
|
|
|
ensureWriteableQbsFile(groupFilePath);
|
|
|
|
|
const FileChangeResult result = session()->removeFiles(
|
|
|
|
|
nonWildcardFiles,
|
|
|
|
|
product.value("name").toString(),
|
|
|
|
|
group.value("name").toString());
|
|
|
|
|
|
|
|
|
|
*notRemoved = result.failedFiles();
|
|
|
|
|
if (result.error().hasError())
|
|
|
|
|
MessageManager::write(result.error().toString(), Core::MessageManager::ModeSwitch);
|
2019-06-18 14:39:38 +03:00
|
|
|
const bool success = notRemoved->isEmpty();
|
2019-06-28 14:30:32 +02:00
|
|
|
if (!wildcardFiles.isEmpty())
|
2019-06-18 14:39:38 +03:00
|
|
|
*notRemoved += wildcardFiles;
|
|
|
|
|
if (!success)
|
|
|
|
|
return RemovedFilesFromProject::Error;
|
|
|
|
|
if (!wildcardFiles.isEmpty())
|
|
|
|
|
return RemovedFilesFromProject::Wildcard;
|
|
|
|
|
return RemovedFilesFromProject::Ok;
|
2014-07-18 15:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
bool QbsBuildSystem::renameFileInProduct(
|
|
|
|
|
const QString &oldPath,
|
|
|
|
|
const QString &newPath,
|
|
|
|
|
const QJsonObject &product,
|
|
|
|
|
const QJsonObject &group)
|
2014-09-11 17:12:03 +02:00
|
|
|
{
|
|
|
|
|
if (newPath.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
QStringList dummy;
|
2019-06-28 14:30:32 +02:00
|
|
|
if (removeFilesFromProduct(QStringList(oldPath), product, group, &dummy)
|
2019-06-18 14:39:38 +03:00
|
|
|
!= RemovedFilesFromProject::Ok) {
|
2014-09-11 17:12:03 +02:00
|
|
|
return false;
|
2019-06-18 14:39:38 +03:00
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
return addFilesToProduct(QStringList(newPath), product, group, &dummy);
|
2013-04-12 16:19:52 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
QString QbsBuildSystem::profile() const
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2019-12-05 15:15:35 +01:00
|
|
|
return QbsProfileManager::ensureProfileForKit(target()->kit());
|
2013-04-16 13:14:07 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
bool QbsBuildSystem::checkCancelStatus()
|
2016-03-11 11:21:11 +01:00
|
|
|
{
|
|
|
|
|
const CancelStatus cancelStatus = m_cancelStatus;
|
|
|
|
|
m_cancelStatus = CancelStatusNone;
|
|
|
|
|
if (cancelStatus != CancelStatusCancelingForReparse)
|
|
|
|
|
return false;
|
|
|
|
|
qCDebug(qbsPmLog) << "Cancel request while parsing, starting re-parse";
|
|
|
|
|
m_qbsProjectParser->deleteLater();
|
2018-07-27 12:10:20 +02:00
|
|
|
m_qbsProjectParser = nullptr;
|
2020-02-04 14:59:08 +01:00
|
|
|
m_treeCreationWatcher = nullptr;
|
2019-08-06 14:46:37 +02:00
|
|
|
m_guard = {};
|
2016-03-11 11:21:11 +01:00
|
|
|
parseCurrentBuildConfiguration();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::updateAfterParse()
|
2016-03-08 14:00:56 +01:00
|
|
|
{
|
2016-03-11 17:53:26 +01:00
|
|
|
qCDebug(qbsPmLog) << "Updating data after parse";
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer opTimer("updateAfterParse");
|
2020-02-04 14:59:08 +01:00
|
|
|
updateProjectNodes([this] {
|
|
|
|
|
updateDocuments();
|
|
|
|
|
updateBuildTargetData();
|
|
|
|
|
updateCppCodeModel();
|
|
|
|
|
updateExtraCompilers();
|
|
|
|
|
updateQmlJsCodeModel();
|
|
|
|
|
m_envCache.clear();
|
|
|
|
|
m_guard.markAsSuccess();
|
|
|
|
|
m_guard = {};
|
|
|
|
|
emitBuildSystemUpdated();
|
|
|
|
|
});
|
2016-03-08 14:00:56 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::delayedUpdateAfterParse()
|
2017-11-14 14:19:52 +01:00
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
QTimer::singleShot(0, this, &QbsBuildSystem::updateAfterParse);
|
2017-11-14 14:19:52 +01:00
|
|
|
}
|
|
|
|
|
|
2020-02-04 14:59:08 +01:00
|
|
|
void QbsBuildSystem::updateProjectNodes(const std::function<void ()> &continuation)
|
2017-01-24 18:13:48 +01:00
|
|
|
{
|
2020-02-04 14:59:08 +01:00
|
|
|
m_treeCreationWatcher = new TreeCreationWatcher(this);
|
|
|
|
|
connect(m_treeCreationWatcher, &TreeCreationWatcher::finished, this,
|
|
|
|
|
[this, watcher = m_treeCreationWatcher, continuation] {
|
|
|
|
|
std::unique_ptr<QbsProjectNode> rootNode(m_treeCreationWatcher->result());
|
|
|
|
|
if (watcher != m_treeCreationWatcher) {
|
|
|
|
|
watcher->deleteLater();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
OpTimer("updateProjectNodes continuation");
|
|
|
|
|
m_treeCreationWatcher->deleteLater();
|
|
|
|
|
m_treeCreationWatcher = nullptr;
|
|
|
|
|
if (target() != project()->activeTarget()
|
|
|
|
|
|| target()->activeBuildConfiguration()->buildSystem() != this) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
project()->setDisplayName(rootNode->displayName());
|
|
|
|
|
setRootProjectNode(std::move(rootNode));
|
|
|
|
|
if (continuation)
|
|
|
|
|
continuation();
|
|
|
|
|
});
|
|
|
|
|
m_treeCreationWatcher->setFuture(runAsync(ProjectExplorerPlugin::sharedThreadPool(),
|
|
|
|
|
QThread::LowPriority, &QbsNodeTreeBuilder::buildTree,
|
|
|
|
|
project()->displayName(), project()->projectFilePath(), project()->projectDirectory(),
|
|
|
|
|
projectData()));
|
2017-01-24 18:13:48 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
FilePath QbsBuildSystem::installRoot()
|
2018-04-16 15:57:20 +02:00
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
const auto dc = target()->activeDeployConfiguration();
|
2019-10-10 17:19:09 +02:00
|
|
|
if (dc) {
|
2019-10-16 17:44:15 +02:00
|
|
|
const QList<BuildStep *> steps = dc->stepList()->steps();
|
|
|
|
|
for (const BuildStep * const step : steps) {
|
|
|
|
|
if (!step->enabled())
|
|
|
|
|
continue;
|
|
|
|
|
if (const auto qbsInstallStep = qobject_cast<const QbsInstallStep *>(step))
|
|
|
|
|
return FilePath::fromString(qbsInstallStep->installRoot());
|
2019-10-10 17:19:09 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-25 09:55:32 +02:00
|
|
|
const QbsBuildStep * const buildStep = m_buildConfiguration->qbsStep();
|
2019-05-28 13:49:26 +02:00
|
|
|
return buildStep && buildStep->install() ? buildStep->installRoot() : FilePath();
|
2018-04-16 15:57:20 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::handleQbsParsingDone(bool success)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2014-06-16 14:42:21 +02:00
|
|
|
QTC_ASSERT(m_qbsProjectParser, return);
|
2016-03-11 11:21:11 +01:00
|
|
|
QTC_ASSERT(m_qbsUpdateFutureInterface, return);
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2016-03-11 17:53:26 +01:00
|
|
|
qCDebug(qbsPmLog) << "Parsing done, success:" << success;
|
2014-07-14 14:22:27 +02:00
|
|
|
|
2016-03-11 11:21:11 +01:00
|
|
|
if (checkCancelStatus())
|
2014-07-14 10:22:37 +02:00
|
|
|
return;
|
|
|
|
|
|
2014-06-16 14:42:21 +02:00
|
|
|
generateErrors(m_qbsProjectParser->error());
|
|
|
|
|
|
2016-03-11 17:53:26 +01:00
|
|
|
bool dataChanged = false;
|
2019-07-05 16:58:07 +02:00
|
|
|
bool envChanged = m_lastParseEnv != m_qbsProjectParser->environment();
|
|
|
|
|
m_lastParseEnv = m_qbsProjectParser->environment();
|
2014-07-10 17:01:54 +02:00
|
|
|
if (success) {
|
2019-06-28 14:30:32 +02:00
|
|
|
const QJsonObject projectData = m_qbsProjectParser->session()->projectData();
|
2016-03-11 17:53:26 +01:00
|
|
|
if (projectData != m_projectData) {
|
|
|
|
|
m_projectData = projectData;
|
|
|
|
|
dataChanged = true;
|
|
|
|
|
}
|
2014-07-14 10:22:37 +02:00
|
|
|
} else {
|
|
|
|
|
m_qbsUpdateFutureInterface->reportCanceled();
|
2014-07-10 17:01:54 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-16 14:42:21 +02:00
|
|
|
m_qbsProjectParser->deleteLater();
|
2018-07-27 12:10:20 +02:00
|
|
|
m_qbsProjectParser = nullptr;
|
2016-03-11 11:21:11 +01:00
|
|
|
m_qbsUpdateFutureInterface->reportFinished();
|
|
|
|
|
delete m_qbsUpdateFutureInterface;
|
2018-07-27 12:10:20 +02:00
|
|
|
m_qbsUpdateFutureInterface = nullptr;
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2020-02-04 14:59:08 +01:00
|
|
|
if (dataChanged) {
|
2016-03-11 17:53:26 +01:00
|
|
|
updateAfterParse();
|
2020-02-04 14:59:08 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2019-07-05 16:58:07 +02:00
|
|
|
else if (envChanged)
|
|
|
|
|
updateCppCodeModel();
|
2019-06-28 14:30:32 +02:00
|
|
|
if (success)
|
|
|
|
|
m_guard.markAsSuccess();
|
2019-08-06 14:46:37 +02:00
|
|
|
m_guard = {};
|
2019-11-15 15:44:45 +01:00
|
|
|
|
|
|
|
|
// This one used to change the executable path of a Qbs desktop run configuration
|
|
|
|
|
// in case the "install" check box in the build step is unchecked and then build
|
|
|
|
|
// is triggered (which is otherwise a no-op).
|
|
|
|
|
emitBuildSystemUpdated();
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::changeActiveTarget(Target *t)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
if (t)
|
2018-08-30 10:53:50 +02:00
|
|
|
delayParsing();
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::triggerParsing()
|
2013-11-26 16:19:43 +01:00
|
|
|
{
|
2014-03-03 14:15:46 +01:00
|
|
|
// Qbs does update the build graph during the build. So we cannot
|
|
|
|
|
// start to parse while a build is running or we will lose information.
|
2019-10-25 09:55:32 +02:00
|
|
|
if (BuildManager::isBuilding(project())) {
|
2014-07-14 14:22:27 +02:00
|
|
|
scheduleParsing();
|
2014-03-03 14:15:46 +01:00
|
|
|
return;
|
2014-07-14 14:22:27 +02:00
|
|
|
}
|
2014-03-03 14:15:46 +01:00
|
|
|
|
2014-07-17 12:02:56 +02:00
|
|
|
parseCurrentBuildConfiguration();
|
2013-11-26 16:19:43 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::delayParsing()
|
2013-06-06 18:45:53 +02:00
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
if (m_buildConfiguration->isActive())
|
|
|
|
|
m_parsingDelay.start();
|
2013-06-06 18:45:53 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::parseCurrentBuildConfiguration()
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2014-07-11 12:44:12 +02:00
|
|
|
m_parsingScheduled = false;
|
2014-07-14 14:22:27 +02:00
|
|
|
if (m_cancelStatus == CancelStatusCancelingForReparse)
|
2014-07-14 10:22:37 +02:00
|
|
|
return;
|
2013-11-26 16:19:43 +01:00
|
|
|
|
2014-07-14 14:22:27 +02:00
|
|
|
// The CancelStatusCancelingAltoghether type can only be set by a build job, during
|
|
|
|
|
// which no other parse requests come through to this point (except by the build job itself,
|
|
|
|
|
// but of course not while canceling is in progress).
|
|
|
|
|
QTC_ASSERT(m_cancelStatus == CancelStatusNone, return);
|
|
|
|
|
|
2014-07-14 10:22:37 +02:00
|
|
|
// New parse requests override old ones.
|
|
|
|
|
// NOTE: We need to wait for the current operation to finish, since otherwise there could
|
|
|
|
|
// be a conflict. Consider the case where the old qbs::ProjectSetupJob is writing
|
|
|
|
|
// to the build graph file when the cancel request comes in. If we don't wait for
|
|
|
|
|
// acknowledgment, it might still be doing that when the new one already reads from the
|
|
|
|
|
// same file.
|
|
|
|
|
if (m_qbsProjectParser) {
|
2014-07-14 14:22:27 +02:00
|
|
|
m_cancelStatus = CancelStatusCancelingForReparse;
|
2014-07-14 10:22:37 +02:00
|
|
|
m_qbsProjectParser->cancel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
QVariantMap config = m_buildConfiguration->qbsConfiguration();
|
2019-11-21 17:07:11 +01:00
|
|
|
if (!config.contains(Constants::QBS_INSTALL_ROOT_KEY)) {
|
|
|
|
|
config.insert(Constants::QBS_INSTALL_ROOT_KEY, m_buildConfiguration->macroExpander()
|
|
|
|
|
->expand(QbsSettings::defaultInstallDirTemplate()));
|
|
|
|
|
}
|
2019-10-25 09:55:32 +02:00
|
|
|
Environment env = m_buildConfiguration->environment();
|
|
|
|
|
QString dir = m_buildConfiguration->buildDirectory().toString();
|
|
|
|
|
|
|
|
|
|
m_guard = guardParsingRun();
|
|
|
|
|
|
|
|
|
|
prepareForParsing();
|
|
|
|
|
|
|
|
|
|
m_parsingDelay.stop();
|
|
|
|
|
|
|
|
|
|
QTC_ASSERT(!m_qbsProjectParser, return);
|
|
|
|
|
m_qbsProjectParser = new QbsProjectParser(this, m_qbsUpdateFutureInterface);
|
2020-02-04 14:59:08 +01:00
|
|
|
m_treeCreationWatcher = nullptr;
|
2019-10-25 09:55:32 +02:00
|
|
|
connect(m_qbsProjectParser, &QbsProjectParser::done,
|
|
|
|
|
this, &QbsBuildSystem::handleQbsParsingDone);
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
QbsProfileManager::updateProfileIfNecessary(target()->kit());
|
2019-10-25 09:55:32 +02:00
|
|
|
m_qbsProjectParser->parse(config, env, dir, m_buildConfiguration->configurationName());
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::cancelParsing()
|
2014-07-14 14:22:27 +02:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_qbsProjectParser, return);
|
|
|
|
|
m_cancelStatus = CancelStatusCancelingAltoghether;
|
|
|
|
|
m_qbsProjectParser->cancel();
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::updateAfterBuild()
|
2014-07-11 12:44:12 +02:00
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer opTimer("updateAfterBuild");
|
2019-06-28 14:30:32 +02:00
|
|
|
const QJsonObject projectData = session()->projectData();
|
2018-04-16 15:57:20 +02:00
|
|
|
if (projectData == m_projectData) {
|
2019-10-25 09:55:32 +02:00
|
|
|
DeploymentData deploymentDataTmp = deploymentData();
|
|
|
|
|
deploymentDataTmp.setLocalInstallRoot(installRoot());
|
|
|
|
|
setDeploymentData(deploymentDataTmp);
|
2019-11-15 15:44:45 +01:00
|
|
|
emitBuildSystemUpdated();
|
2016-10-06 15:59:23 +02:00
|
|
|
return;
|
2018-04-16 15:57:20 +02:00
|
|
|
}
|
2016-10-06 15:59:23 +02:00
|
|
|
qCDebug(qbsPmLog) << "Updating data after build";
|
|
|
|
|
m_projectData = projectData;
|
2020-02-04 14:59:08 +01:00
|
|
|
updateProjectNodes([this] {
|
|
|
|
|
updateBuildTargetData();
|
|
|
|
|
updateExtraCompilers();
|
|
|
|
|
m_envCache.clear();
|
|
|
|
|
});
|
2014-07-11 12:44:12 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
void QbsBuildSystem::generateErrors(const ErrorInfo &e)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
for (const ErrorInfoItem &item : e.items) {
|
2020-01-15 08:56:11 +01:00
|
|
|
TaskHub::addTask(BuildSystemTask(Task::Error, item.description,
|
|
|
|
|
item.filePath, item.line));
|
2017-07-27 10:10:51 +02:00
|
|
|
}
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::prepareForParsing()
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2013-08-29 18:25:59 +02:00
|
|
|
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
2013-11-15 15:24:11 +01:00
|
|
|
if (m_qbsUpdateFutureInterface) {
|
2013-01-30 18:19:31 +01:00
|
|
|
m_qbsUpdateFutureInterface->reportCanceled();
|
2013-11-15 15:24:11 +01:00
|
|
|
m_qbsUpdateFutureInterface->reportFinished();
|
|
|
|
|
}
|
2013-01-30 18:19:31 +01:00
|
|
|
delete m_qbsUpdateFutureInterface;
|
2018-07-27 12:10:20 +02:00
|
|
|
m_qbsUpdateFutureInterface = nullptr;
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2014-06-16 14:42:21 +02:00
|
|
|
m_qbsUpdateFutureInterface = new QFutureInterface<bool>();
|
2013-01-30 18:19:31 +01:00
|
|
|
m_qbsUpdateFutureInterface->setProgressRange(0, 0);
|
2013-09-03 15:18:37 +02:00
|
|
|
ProgressManager::addTask(m_qbsUpdateFutureInterface->future(),
|
2019-10-25 09:55:32 +02:00
|
|
|
tr("Reading Project \"%1\"").arg(project()->displayName()), "Qbs.QbsEvaluate");
|
2013-01-30 18:19:31 +01:00
|
|
|
m_qbsUpdateFutureInterface->reportStarted();
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
void QbsBuildSystem::updateDocuments()
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer opTimer("updateDocuments");
|
2019-06-28 14:30:32 +02:00
|
|
|
const FilePath buildDir = FilePath::fromString(
|
|
|
|
|
m_projectData.value("build-directory").toString());
|
2020-03-02 18:34:12 +01:00
|
|
|
const auto filePaths = transform<QSet<FilePath>>(
|
2019-06-28 14:30:32 +02:00
|
|
|
m_projectData.value("build-system-files").toArray(),
|
|
|
|
|
[](const QJsonValue &v) { return FilePath::fromString(v.toString()); });
|
|
|
|
|
|
|
|
|
|
// A changed qbs file (project, module etc) should trigger a re-parse, but not if
|
|
|
|
|
// the file was generated by qbs itself, in which case that might cause an infinite loop.
|
2020-03-02 18:34:12 +01:00
|
|
|
const QSet<FilePath> nonBuildDirFilePaths = filtered(filePaths,
|
2019-08-15 12:25:20 +02:00
|
|
|
[buildDir](const FilePath &p) {
|
2019-10-18 11:01:08 +02:00
|
|
|
return !p.isChildOf(buildDir);
|
2019-08-15 12:25:20 +02:00
|
|
|
});
|
2019-10-25 09:55:32 +02:00
|
|
|
project()->setExtraProjectFiles(nonBuildDirFilePaths);
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
static QString getMimeType(const QJsonObject &sourceArtifact)
|
2016-02-22 15:47:39 +01:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
const auto tags = sourceArtifact.value("file-tags").toArray();
|
|
|
|
|
if (tags.contains("hpp")) {
|
|
|
|
|
if (CppTools::ProjectFile::isAmbiguousHeader(sourceArtifact.value("file-path").toString()))
|
2019-09-04 06:42:04 +02:00
|
|
|
return QString(CppTools::Constants::AMBIGUOUS_HEADER_MIMETYPE);
|
|
|
|
|
return QString(CppTools::Constants::CPP_HEADER_MIMETYPE);
|
2017-01-24 15:37:28 +01:00
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
if (tags.contains("cpp"))
|
2019-09-04 06:42:04 +02:00
|
|
|
return QString(CppTools::Constants::CPP_SOURCE_MIMETYPE);
|
2019-06-28 14:30:32 +02:00
|
|
|
if (tags.contains("c"))
|
2019-09-04 06:42:04 +02:00
|
|
|
return QString(CppTools::Constants::C_SOURCE_MIMETYPE);
|
2019-06-28 14:30:32 +02:00
|
|
|
if (tags.contains("objc"))
|
2019-09-04 06:42:04 +02:00
|
|
|
return QString(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE);
|
2019-06-28 14:30:32 +02:00
|
|
|
if (tags.contains("objcpp"))
|
2019-09-04 06:42:04 +02:00
|
|
|
return QString(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE);
|
2019-08-28 12:23:37 +02:00
|
|
|
return {};
|
2016-02-22 15:47:39 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
static QString groupLocationToCallGroupId(const QJsonObject &location)
|
2016-04-11 13:13:07 +02:00
|
|
|
{
|
|
|
|
|
return QString::fromLatin1("%1:%2:%3")
|
2019-06-28 14:30:32 +02:00
|
|
|
.arg(location.value("file-path").toString())
|
|
|
|
|
.arg(location.value("line").toString())
|
|
|
|
|
.arg(location.value("column").toString());
|
2016-04-11 13:13:07 +02:00
|
|
|
}
|
|
|
|
|
|
2016-11-04 15:49:34 +01:00
|
|
|
// TODO: Receive the values from qbs when QBS-1030 is resolved.
|
|
|
|
|
static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags,
|
2019-06-28 14:30:32 +02:00
|
|
|
const QJsonObject &properties)
|
2016-11-04 15:49:34 +01:00
|
|
|
{
|
|
|
|
|
const auto getCppProp = [properties](const char *propertyName) {
|
2019-06-28 14:30:32 +02:00
|
|
|
return properties.value("cpp." + QLatin1String(propertyName));
|
2016-11-04 15:49:34 +01:00
|
|
|
};
|
2019-06-28 14:30:32 +02:00
|
|
|
const QJsonValue &enableExceptions = getCppProp("enableExceptions");
|
|
|
|
|
const QJsonValue &enableRtti = getCppProp("enableRtti");
|
|
|
|
|
QStringList commonFlags = arrayToStringList(getCppProp("platformCommonCompilerFlags"));
|
|
|
|
|
commonFlags << arrayToStringList(getCppProp("commonCompilerFlags"))
|
|
|
|
|
<< arrayToStringList(getCppProp("platformDriverFlags"))
|
|
|
|
|
<< arrayToStringList(getCppProp("driverFlags"));
|
|
|
|
|
const QStringList toolchain = arrayToStringList(properties.value("qbs.toolchain"));
|
2016-11-04 15:49:34 +01:00
|
|
|
if (toolchain.contains("gcc")) {
|
|
|
|
|
bool hasTargetOption = false;
|
|
|
|
|
if (toolchain.contains("clang")) {
|
|
|
|
|
const int majorVersion = getCppProp("compilerVersionMajor").toInt();
|
|
|
|
|
const int minorVersion = getCppProp("compilerVersionMinor").toInt();
|
|
|
|
|
if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 1))
|
|
|
|
|
hasTargetOption = true;
|
|
|
|
|
}
|
|
|
|
|
if (hasTargetOption) {
|
|
|
|
|
commonFlags << "-target" << getCppProp("target").toString();
|
|
|
|
|
} else {
|
|
|
|
|
const QString targetArch = getCppProp("targetArch").toString();
|
|
|
|
|
if (targetArch == "x86_64")
|
|
|
|
|
commonFlags << "-m64";
|
|
|
|
|
else if (targetArch == "i386")
|
|
|
|
|
commonFlags << "-m32";
|
|
|
|
|
const QString machineType = getCppProp("machineType").toString();
|
|
|
|
|
if (!machineType.isEmpty())
|
|
|
|
|
commonFlags << ("-march=" + machineType);
|
|
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
const QStringList targetOS = arrayToStringList(properties.value("qbs.targetOS"));
|
2016-11-04 15:49:34 +01:00
|
|
|
if (targetOS.contains("unix")) {
|
|
|
|
|
const QVariant positionIndependentCode = getCppProp("positionIndependentCode");
|
|
|
|
|
if (!positionIndependentCode.isValid() || positionIndependentCode.toBool())
|
|
|
|
|
commonFlags << "-fPIC";
|
|
|
|
|
}
|
|
|
|
|
cFlags = cxxFlags = commonFlags;
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
const auto cxxLanguageVersion = arrayToStringList(getCppProp("cxxLanguageVersion"));
|
2018-08-06 16:49:12 +02:00
|
|
|
if (cxxLanguageVersion.contains("c++17"))
|
|
|
|
|
cxxFlags << "-std=c++17";
|
|
|
|
|
else if (cxxLanguageVersion.contains("c++14"))
|
|
|
|
|
cxxFlags << "-std=c++14";
|
|
|
|
|
else if (cxxLanguageVersion.contains("c++11"))
|
|
|
|
|
cxxFlags << "-std=c++11";
|
2016-11-04 15:49:34 +01:00
|
|
|
else if (!cxxLanguageVersion.isEmpty())
|
2018-08-06 16:49:12 +02:00
|
|
|
cxxFlags << ("-std=" + cxxLanguageVersion.first());
|
2016-11-04 15:49:34 +01:00
|
|
|
const QString cxxStandardLibrary = getCppProp("cxxStandardLibrary").toString();
|
|
|
|
|
if (!cxxStandardLibrary.isEmpty() && toolchain.contains("clang"))
|
|
|
|
|
cxxFlags << ("-stdlib=" + cxxStandardLibrary);
|
2019-06-28 14:30:32 +02:00
|
|
|
if (!enableExceptions.isUndefined()) {
|
2016-11-04 15:49:34 +01:00
|
|
|
cxxFlags << QLatin1String(enableExceptions.toBool()
|
|
|
|
|
? "-fexceptions" : "-fno-exceptions");
|
|
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
if (!enableRtti.isUndefined())
|
2016-11-04 15:49:34 +01:00
|
|
|
cxxFlags << QLatin1String(enableRtti.toBool() ? "-frtti" : "-fno-rtti");
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
const auto cLanguageVersion = arrayToStringList(getCppProp("cLanguageVersion"));
|
2018-08-06 16:49:12 +02:00
|
|
|
if (cLanguageVersion.contains("c11"))
|
|
|
|
|
cFlags << "-std=c11";
|
|
|
|
|
else if (cLanguageVersion.contains("c99"))
|
|
|
|
|
cFlags << "-std=c99";
|
2016-11-04 15:49:34 +01:00
|
|
|
else if (!cLanguageVersion.isEmpty())
|
2018-08-06 16:49:12 +02:00
|
|
|
cFlags << ("-std=" + cLanguageVersion.first());
|
2019-05-08 08:43:50 +02:00
|
|
|
|
|
|
|
|
if (targetOS.contains("darwin")) {
|
|
|
|
|
const auto darwinVersion = getCppProp("minimumDarwinVersion").toString();
|
|
|
|
|
if (!darwinVersion.isEmpty()) {
|
|
|
|
|
const auto darwinVersionFlag = getCppProp("minimumDarwinVersionCompilerFlag")
|
|
|
|
|
.toString();
|
|
|
|
|
if (!darwinVersionFlag.isEmpty())
|
|
|
|
|
cxxFlags << (darwinVersionFlag + '=' + darwinVersion);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-04 15:49:34 +01:00
|
|
|
} else if (toolchain.contains("msvc")) {
|
|
|
|
|
if (enableExceptions.toBool()) {
|
|
|
|
|
const QString exceptionModel = getCppProp("exceptionHandlingModel").toString();
|
|
|
|
|
if (exceptionModel == "default")
|
|
|
|
|
commonFlags << "/EHsc";
|
|
|
|
|
else if (exceptionModel == "seh")
|
|
|
|
|
commonFlags << "/EHa";
|
|
|
|
|
else if (exceptionModel == "externc")
|
|
|
|
|
commonFlags << "/EHs";
|
|
|
|
|
}
|
|
|
|
|
cFlags = cxxFlags = commonFlags;
|
|
|
|
|
cFlags << "/TC";
|
|
|
|
|
cxxFlags << "/TP";
|
2019-06-28 14:30:32 +02:00
|
|
|
if (!enableRtti.isUndefined())
|
2016-11-04 15:49:34 +01:00
|
|
|
cxxFlags << QLatin1String(enableRtti.toBool() ? "/GR" : "/GR-");
|
2019-06-28 14:30:32 +02:00
|
|
|
if (getCppProp("cxxLanguageVersion").toArray().contains("c++17"))
|
2018-08-06 16:49:12 +02:00
|
|
|
cxxFlags << "/std:c++17";
|
2016-11-04 15:49:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-04 12:27:58 +01:00
|
|
|
static RawProjectParts generateProjectParts(
|
|
|
|
|
const QJsonObject &projectData,
|
|
|
|
|
const std::shared_ptr<const ToolChain> &cToolChain,
|
|
|
|
|
const std::shared_ptr<const ToolChain> &cxxToolChain,
|
|
|
|
|
QtVersion qtVersion
|
|
|
|
|
)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2019-08-28 18:22:45 +02:00
|
|
|
RawProjectParts rpps;
|
2020-02-04 11:18:03 +01:00
|
|
|
forAllProducts(projectData, [&](const QJsonObject &prd) {
|
2019-06-28 14:30:32 +02:00
|
|
|
const QString productName = prd.value("full-display-name").toString();
|
2016-11-23 12:17:02 +01:00
|
|
|
QString cPch;
|
|
|
|
|
QString cxxPch;
|
|
|
|
|
QString objcPch;
|
|
|
|
|
QString objcxxPch;
|
2019-06-28 14:30:32 +02:00
|
|
|
const auto &pchFinder = [&cPch, &cxxPch, &objcPch, &objcxxPch](const QJsonObject &artifact) {
|
|
|
|
|
const QJsonArray fileTags = artifact.value("file-tags").toArray();
|
2018-10-17 11:25:36 +03:00
|
|
|
if (fileTags.contains("c_pch_src"))
|
2019-06-28 14:30:32 +02:00
|
|
|
cPch = artifact.value("file-path").toString();
|
2018-10-17 11:25:36 +03:00
|
|
|
if (fileTags.contains("cpp_pch_src"))
|
2019-06-28 14:30:32 +02:00
|
|
|
cxxPch = artifact.value("file-path").toString();
|
2018-10-17 11:25:36 +03:00
|
|
|
if (fileTags.contains("objc_pch_src"))
|
2019-06-28 14:30:32 +02:00
|
|
|
objcPch = artifact.value("file-path").toString();
|
2018-10-17 11:25:36 +03:00
|
|
|
if (fileTags.contains("objcpp_pch_src"))
|
2019-06-28 14:30:32 +02:00
|
|
|
objcxxPch = artifact.value("file-path").toString();
|
2016-11-23 12:17:02 +01:00
|
|
|
};
|
2019-06-28 14:30:32 +02:00
|
|
|
forAllArtifacts(prd, ArtifactType::All, pchFinder);
|
2016-11-23 12:17:02 +01:00
|
|
|
|
2019-08-28 13:04:16 +02:00
|
|
|
const Utils::QtVersion qtVersionForPart
|
2019-06-28 14:30:32 +02:00
|
|
|
= prd.value("module-properties").toObject().value("Qt.core.version").isUndefined()
|
|
|
|
|
? Utils::QtVersion::None
|
2020-02-04 12:27:58 +01:00
|
|
|
: qtVersion;
|
2019-06-28 14:30:32 +02:00
|
|
|
|
|
|
|
|
const QJsonArray groups = prd.value("groups").toArray();
|
|
|
|
|
for (const QJsonValue &g : groups) {
|
|
|
|
|
const QJsonObject grp = g.toObject();
|
|
|
|
|
const QString groupName = grp.value("name").toString();
|
2017-02-17 16:17:01 +01:00
|
|
|
|
2019-08-28 18:22:45 +02:00
|
|
|
RawProjectPart rpp;
|
2017-02-06 16:59:53 +01:00
|
|
|
rpp.setQtVersion(qtVersionForPart);
|
2019-06-28 14:30:32 +02:00
|
|
|
QJsonObject props = grp.value("module-properties").toObject();
|
|
|
|
|
if (props.isEmpty())
|
|
|
|
|
props = prd.value("module-properties").toObject();
|
|
|
|
|
rpp.setCallGroupId(groupLocationToCallGroupId(grp.value("location").toObject()));
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2016-11-04 15:49:34 +01:00
|
|
|
QStringList cFlags;
|
|
|
|
|
QStringList cxxFlags;
|
|
|
|
|
getExpandedCompilerFlags(cFlags, cxxFlags, props);
|
2020-02-04 12:27:58 +01:00
|
|
|
rpp.setFlagsForC({cToolChain.get(), cFlags});
|
|
|
|
|
rpp.setFlagsForCxx({cxxToolChain.get(), cxxFlags});
|
2013-04-28 17:18:50 +04:00
|
|
|
|
2020-03-09 16:44:13 +01:00
|
|
|
const QStringList defines = arrayToStringList(props.value("cpp.defines"))
|
|
|
|
|
+ arrayToStringList(props.value("cpp.platformDefines"));
|
|
|
|
|
rpp.setMacros(transform<QVector>(defines,
|
2019-06-28 14:30:32 +02:00
|
|
|
[](const QString &s) { return Macro::fromKeyValue(s); }));
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2018-09-03 16:10:43 +02:00
|
|
|
ProjectExplorer::HeaderPaths grpHeaderPaths;
|
2019-06-28 14:30:32 +02:00
|
|
|
QStringList list = arrayToStringList(props.value("cpp.includePaths"));
|
2019-07-09 14:45:27 +02:00
|
|
|
list.removeDuplicates();
|
|
|
|
|
for (const QString &p : qAsConst(list))
|
2019-05-28 13:49:26 +02:00
|
|
|
grpHeaderPaths += {FilePath::fromUserInput(p).toString(), HeaderPathType::User};
|
2019-06-28 14:30:32 +02:00
|
|
|
list = arrayToStringList(props.value("cpp.systemIncludePaths"));
|
2019-07-09 14:45:27 +02:00
|
|
|
list.removeDuplicates();
|
|
|
|
|
for (const QString &p : qAsConst(list))
|
|
|
|
|
grpHeaderPaths += {FilePath::fromUserInput(p).toString(), HeaderPathType::System};
|
2019-06-28 14:30:32 +02:00
|
|
|
list = arrayToStringList(props.value("cpp.frameworkPaths"));
|
|
|
|
|
list.append(arrayToStringList(props.value("cpp.systemFrameworkPaths")));
|
2017-01-20 11:30:49 +01:00
|
|
|
list.removeDuplicates();
|
2019-06-28 14:30:32 +02:00
|
|
|
for (const QString &p : qAsConst(list)) {
|
|
|
|
|
grpHeaderPaths += {FilePath::fromUserInput(p).toString(),
|
|
|
|
|
HeaderPathType::Framework};
|
|
|
|
|
}
|
2017-02-06 16:59:53 +01:00
|
|
|
rpp.setHeaderPaths(grpHeaderPaths);
|
2019-06-28 14:30:32 +02:00
|
|
|
rpp.setDisplayName(groupName);
|
|
|
|
|
const QJsonObject location = grp.value("location").toObject();
|
|
|
|
|
rpp.setProjectFileLocation(location.value("file-path").toString(),
|
|
|
|
|
location.value("line").toInt(),
|
|
|
|
|
location.value("column").toInt());
|
2020-03-02 09:41:58 +01:00
|
|
|
rpp.setBuildSystemTarget(buildKeyValue(prd));
|
2019-06-28 14:30:32 +02:00
|
|
|
rpp.setBuildTargetType(prd.value("is-runnable").toBool()
|
|
|
|
|
? BuildTargetType::Executable
|
|
|
|
|
: BuildTargetType::Library);
|
2020-03-18 09:29:10 +01:00
|
|
|
rpp.setSelectedForBuilding(grp.value("is-enabled").toBool());
|
2019-06-28 14:30:32 +02:00
|
|
|
|
|
|
|
|
QHash<QString, QJsonObject> filePathToSourceArtifact;
|
2016-11-23 12:17:02 +01:00
|
|
|
bool hasCFiles = false;
|
|
|
|
|
bool hasCxxFiles = false;
|
|
|
|
|
bool hasObjcFiles = false;
|
|
|
|
|
bool hasObjcxxFiles = false;
|
2020-02-04 11:18:03 +01:00
|
|
|
const auto artifactWorker = [&](const QJsonObject &source) {
|
2019-06-28 14:30:32 +02:00
|
|
|
const QString filePath = source.value("file-path").toString();
|
|
|
|
|
filePathToSourceArtifact.insert(filePath, source);
|
|
|
|
|
for (const QJsonValue &tag : source.value("file-tags").toArray()) {
|
2016-11-23 12:17:02 +01:00
|
|
|
if (tag == "c")
|
|
|
|
|
hasCFiles = true;
|
|
|
|
|
else if (tag == "cpp")
|
|
|
|
|
hasCxxFiles = true;
|
|
|
|
|
else if (tag == "objc")
|
|
|
|
|
hasObjcFiles = true;
|
|
|
|
|
else if (tag == "objcpp")
|
|
|
|
|
hasObjcxxFiles = true;
|
2013-08-07 12:29:52 +02:00
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
};
|
|
|
|
|
forAllArtifacts(grp, artifactWorker);
|
2014-08-19 12:01:47 +02:00
|
|
|
|
2018-10-17 11:25:36 +03:00
|
|
|
QSet<QString> pchFiles;
|
2019-06-28 14:30:32 +02:00
|
|
|
if (hasCFiles && props.value("cpp.useCPrecompiledHeader").toBool()
|
2016-11-23 12:17:02 +01:00
|
|
|
&& !cPch.isEmpty()) {
|
|
|
|
|
pchFiles << cPch;
|
|
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
if (hasCxxFiles && props.value("cpp.useCxxPrecompiledHeader").toBool()
|
2016-11-23 12:17:02 +01:00
|
|
|
&& !cxxPch.isEmpty()) {
|
|
|
|
|
pchFiles << cxxPch;
|
|
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
if (hasObjcFiles && props.value("cpp.useObjcPrecompiledHeader").toBool()
|
2016-11-23 12:17:02 +01:00
|
|
|
&& !objcPch.isEmpty()) {
|
|
|
|
|
pchFiles << objcPch;
|
|
|
|
|
}
|
|
|
|
|
if (hasObjcxxFiles
|
2019-06-28 14:30:32 +02:00
|
|
|
&& props.value("cpp.useObjcxxPrecompiledHeader").toBool()
|
2016-11-23 12:17:02 +01:00
|
|
|
&& !objcxxPch.isEmpty()) {
|
|
|
|
|
pchFiles << objcxxPch;
|
|
|
|
|
}
|
|
|
|
|
if (pchFiles.count() > 1) {
|
|
|
|
|
qCWarning(qbsPmLog) << "More than one pch file enabled for source files in group"
|
2019-06-28 14:30:32 +02:00
|
|
|
<< groupName << "in product" << productName;
|
2016-11-23 12:17:02 +01:00
|
|
|
qCWarning(qbsPmLog) << "Expect problems with code model";
|
|
|
|
|
}
|
2019-07-26 17:11:22 +02:00
|
|
|
rpp.setPreCompiledHeaders(Utils::toList(pchFiles));
|
2019-06-28 14:30:32 +02:00
|
|
|
rpp.setFiles(filePathToSourceArtifact.keys(), {},
|
2019-08-28 12:23:37 +02:00
|
|
|
[filePathToSourceArtifact](const QString &filePath) {
|
2019-06-28 14:30:32 +02:00
|
|
|
// Keep this lambda thread-safe!
|
|
|
|
|
return getMimeType(filePathToSourceArtifact.value(filePath));
|
|
|
|
|
});
|
2017-02-06 16:59:53 +01:00
|
|
|
rpps.append(rpp);
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
});
|
2020-02-04 12:27:58 +01:00
|
|
|
return rpps;
|
|
|
|
|
}
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2020-02-04 12:27:58 +01:00
|
|
|
void QbsBuildSystem::updateCppCodeModel()
|
|
|
|
|
{
|
|
|
|
|
OpTimer optimer("updateCppCodeModel");
|
|
|
|
|
const QJsonObject projectData = session()->projectData();
|
|
|
|
|
if (projectData.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const QtSupport::CppKitInfo kitInfo(kit());
|
|
|
|
|
QTC_ASSERT(kitInfo.isValid(), return);
|
|
|
|
|
const auto cToolchain = std::shared_ptr<ToolChain>(kitInfo.cToolChain
|
|
|
|
|
? kitInfo.cToolChain->clone() : nullptr);
|
|
|
|
|
const auto cxxToolchain = std::shared_ptr<ToolChain>(kitInfo.cxxToolChain
|
|
|
|
|
? kitInfo.cxxToolChain->clone() : nullptr);
|
|
|
|
|
|
|
|
|
|
m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), {},
|
|
|
|
|
[projectData, kitInfo, cToolchain, cxxToolchain] {
|
|
|
|
|
return generateProjectParts(projectData, cToolchain, cxxToolchain,
|
|
|
|
|
kitInfo.projectPartQtVersion);
|
|
|
|
|
}});
|
2020-02-04 11:18:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QbsBuildSystem::updateExtraCompilers()
|
|
|
|
|
{
|
|
|
|
|
OpTimer optimer("updateExtraCompilers");
|
|
|
|
|
const QJsonObject projectData = session()->projectData();
|
|
|
|
|
if (projectData.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const QList<ExtraCompilerFactory *> factories = ExtraCompilerFactory::extraCompilerFactories();
|
|
|
|
|
QHash<QString, QStringList> sourcesForGeneratedFiles;
|
|
|
|
|
m_sourcesForGeneratedFiles.clear();
|
|
|
|
|
|
|
|
|
|
forAllProducts(projectData, [&, this](const QJsonObject &prd) {
|
|
|
|
|
const QString productName = prd.value("full-display-name").toString();
|
|
|
|
|
forAllArtifacts(prd, ArtifactType::Source, [&, this](const QJsonObject &source) {
|
|
|
|
|
const QString filePath = source.value("file-path").toString();
|
|
|
|
|
for (const QJsonValue &tag : source.value("file-tags").toArray()) {
|
|
|
|
|
for (auto i = factories.cbegin(); i != factories.cend(); ++i) {
|
|
|
|
|
if ((*i)->sourceTag() == tag.toString()) {
|
|
|
|
|
m_sourcesForGeneratedFiles[*i] << filePath;
|
|
|
|
|
sourcesForGeneratedFiles[productName] << filePath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2019-06-28 14:30:32 +02:00
|
|
|
if (!sourcesForGeneratedFiles.isEmpty())
|
|
|
|
|
session()->requestFilesGeneratedFrom(sourcesForGeneratedFiles);
|
2014-10-30 16:17:18 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::updateQmlJsCodeModel()
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer optimer("updateQmlJsCodeModel");
|
2013-02-22 11:20:33 +01:00
|
|
|
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
|
|
|
|
if (!modelManager)
|
|
|
|
|
return;
|
2012-12-06 17:20:58 +01:00
|
|
|
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
|
2019-10-25 09:55:32 +02:00
|
|
|
modelManager->defaultProjectInfoForProject(project());
|
2019-06-28 14:30:32 +02:00
|
|
|
|
|
|
|
|
const QJsonObject projectData = session()->projectData();
|
|
|
|
|
if (projectData.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
forAllProducts(projectData, [&projectInfo](const QJsonObject &product) {
|
|
|
|
|
for (const QJsonValue &path : product.value("properties").toObject()
|
|
|
|
|
.value("qmlImportPaths").toArray()) {
|
|
|
|
|
projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(path.toString()),
|
2015-08-04 15:52:22 +02:00
|
|
|
QmlJS::Dialect::Qml);
|
|
|
|
|
}
|
2019-06-28 14:30:32 +02:00
|
|
|
});
|
2013-04-10 14:45:47 +02:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
project()->setProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID,
|
2017-01-30 14:59:10 +01:00
|
|
|
!projectInfo.sourceFiles.isEmpty());
|
2019-10-25 09:55:32 +02:00
|
|
|
modelManager->updateProjectInfo(projectInfo, project());
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::updateApplicationTargets()
|
2013-09-02 10:12:37 +02:00
|
|
|
{
|
2019-05-03 17:26:49 +02:00
|
|
|
QList<BuildTargetInfo> applications;
|
2019-06-28 14:30:32 +02:00
|
|
|
forAllProducts(session()->projectData(), [this, &applications](const QJsonObject &productData) {
|
|
|
|
|
if (!productData.value("is-enabled").toBool() || !productData.value("is-runnable").toBool())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// TODO: Perhaps put this into a central location instead. Same for module properties etc
|
|
|
|
|
const auto getProp = [productData](const QString &propName) {
|
|
|
|
|
return productData.value("properties").toObject().value(propName);
|
|
|
|
|
};
|
|
|
|
|
const bool isQtcRunnable = getProp("qtcRunnable").toBool();
|
|
|
|
|
const bool usesTerminal = getProp("consoleApplication").toBool();
|
|
|
|
|
const QString projectFile = productData.value("location").toObject()
|
|
|
|
|
.value("file-path").toString();
|
2018-02-21 12:30:09 +01:00
|
|
|
QString targetFile;
|
2019-06-28 14:30:32 +02:00
|
|
|
for (const QJsonValue &v : productData.value("generated-artifacts").toArray()) {
|
|
|
|
|
const QJsonObject artifact = v.toObject();
|
|
|
|
|
if (artifact.value("is-target").toBool() && artifact.value("is-executable").toBool()) {
|
|
|
|
|
targetFile = artifact.value("file-path").toString();
|
2018-03-07 16:03:00 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
2018-02-21 12:30:09 +01:00
|
|
|
BuildTargetInfo bti;
|
2020-03-02 09:41:58 +01:00
|
|
|
bti.buildKey = buildKeyValue(productData);
|
2019-05-28 13:49:26 +02:00
|
|
|
bti.targetFilePath = FilePath::fromString(targetFile);
|
|
|
|
|
bti.projectFilePath = FilePath::fromString(projectFile);
|
2018-02-21 12:30:09 +01:00
|
|
|
bti.isQtcRunnable = isQtcRunnable; // Fixed up below.
|
|
|
|
|
bti.usesTerminal = usesTerminal;
|
2020-02-18 15:07:53 +01:00
|
|
|
bti.displayName = productData.value("full-display-name").toString();
|
2018-02-21 12:30:09 +01:00
|
|
|
bti.runEnvModifier = [targetFile, productData, this](Utils::Environment &env, bool usingLibraryPaths) {
|
2019-06-28 14:30:32 +02:00
|
|
|
const QString productName = productData.value("full-display-name").toString();
|
|
|
|
|
if (session()->projectData().isEmpty())
|
2018-11-28 13:38:11 +01:00
|
|
|
return;
|
2019-05-24 11:48:47 +02:00
|
|
|
|
|
|
|
|
const QString key = env.toStringList().join(QChar())
|
2019-06-28 14:30:32 +02:00
|
|
|
+ productName
|
2019-05-24 11:48:47 +02:00
|
|
|
+ QString::number(usingLibraryPaths);
|
|
|
|
|
const auto it = m_envCache.constFind(key);
|
|
|
|
|
if (it != m_envCache.constEnd()) {
|
|
|
|
|
env = it.value();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-21 12:30:09 +01:00
|
|
|
QProcessEnvironment procEnv = env.toProcessEnvironment();
|
2019-06-28 14:30:32 +02:00
|
|
|
procEnv.insert("QBS_RUN_FILE_PATH", targetFile);
|
2018-02-21 12:30:09 +01:00
|
|
|
QStringList setupRunEnvConfig;
|
|
|
|
|
if (!usingLibraryPaths)
|
2019-06-28 14:30:32 +02:00
|
|
|
setupRunEnvConfig << "ignore-lib-dependencies";
|
|
|
|
|
// TODO: It'd be preferable if we could somenow make this asynchronous.
|
|
|
|
|
RunEnvironmentResult result = session()->getRunEnvironment(productName, procEnv,
|
|
|
|
|
setupRunEnvConfig);
|
|
|
|
|
if (result.error().hasError()) {
|
2018-02-21 12:30:09 +01:00
|
|
|
Core::MessageManager::write(tr("Error retrieving run environment: %1")
|
2019-06-28 14:30:32 +02:00
|
|
|
.arg(result.error().toString()));
|
|
|
|
|
} else {
|
|
|
|
|
QProcessEnvironment fullEnv = result.environment();
|
|
|
|
|
QTC_ASSERT(!fullEnv.isEmpty(), fullEnv = procEnv);
|
2018-02-21 12:30:09 +01:00
|
|
|
env = Utils::Environment();
|
2019-06-28 14:30:32 +02:00
|
|
|
for (const QString &key : fullEnv.keys())
|
|
|
|
|
env.set(key, fullEnv.value(key));
|
2018-02-21 12:30:09 +01:00
|
|
|
}
|
2019-05-24 11:48:47 +02:00
|
|
|
m_envCache.insert(key, env);
|
2018-02-21 12:30:09 +01:00
|
|
|
};
|
|
|
|
|
|
2019-05-03 17:26:49 +02:00
|
|
|
applications.append(bti);
|
2019-06-28 14:30:32 +02:00
|
|
|
});
|
2019-10-25 09:55:32 +02:00
|
|
|
setApplicationTargets(applications);
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::updateDeploymentInfo()
|
2013-09-02 10:12:37 +02:00
|
|
|
{
|
2019-06-28 14:30:32 +02:00
|
|
|
if (session()->projectData().isEmpty())
|
|
|
|
|
return;
|
2015-02-03 23:56:02 +02:00
|
|
|
DeploymentData deploymentData;
|
2019-06-28 14:30:32 +02:00
|
|
|
forAllProducts(session()->projectData(), [&deploymentData](const QJsonObject &product) {
|
|
|
|
|
forAllArtifacts(product, ArtifactType::All, [&deploymentData](const QJsonObject &artifact) {
|
|
|
|
|
const QJsonObject installData = artifact.value("install-data").toObject();
|
|
|
|
|
if (installData.value("is-installable").toBool()) {
|
|
|
|
|
deploymentData.addFile(
|
|
|
|
|
artifact.value("file-path").toString(),
|
|
|
|
|
QFileInfo(installData.value("install-file-path").toString()).path(),
|
|
|
|
|
artifact.value("is-executable").toBool()
|
|
|
|
|
? DeployableFile::TypeExecutable : DeployableFile::TypeNormal);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
2018-04-16 15:57:20 +02:00
|
|
|
deploymentData.setLocalInstallRoot(installRoot());
|
2019-10-25 09:55:32 +02:00
|
|
|
setDeploymentData(deploymentData);
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
void QbsBuildSystem::updateBuildTargetData()
|
2014-07-11 12:44:12 +02:00
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer optimer("updateBuildTargetData");
|
2014-09-05 12:08:15 +02:00
|
|
|
updateApplicationTargets();
|
|
|
|
|
updateDeploymentInfo();
|
2019-11-15 15:44:45 +01:00
|
|
|
|
|
|
|
|
// This one used after a normal build.
|
|
|
|
|
emitBuildSystemUpdated();
|
2014-07-11 12:44:12 +02:00
|
|
|
}
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace QbsProjectManager
|