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"
|
2013-02-06 11:28:33 +01:00
|
|
|
#include "qbslogsink.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"
|
|
|
|
|
#include "qbsnodes.h"
|
2017-02-20 13:33:11 +01:00
|
|
|
#include "qbsnodetreebuilder.h"
|
2013-01-30 18:19:31 +01:00
|
|
|
|
|
|
|
|
#include <coreplugin/documentmanager.h>
|
|
|
|
|
#include <coreplugin/icontext.h>
|
|
|
|
|
#include <coreplugin/id.h>
|
2014-08-18 16:30:43 +02:00
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/iversioncontrol.h>
|
|
|
|
|
#include <coreplugin/vcsmanager.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>
|
2014-09-15 00:12:27 +02:00
|
|
|
#include <cpptools/cppmodelmanager.h>
|
2017-02-06 16:59:53 +01:00
|
|
|
#include <cpptools/cppprojectupdater.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>
|
|
|
|
|
#include <projectexplorer/deploymentdata.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>
|
2013-03-27 09:15:01 +01:00
|
|
|
#include <projectexplorer/headerpath.h>
|
2013-01-30 18:19:31 +01:00
|
|
|
#include <qtsupport/qtkitinformation.h>
|
2016-01-15 16:12:54 +01:00
|
|
|
#include <cpptools/generatedcodemodelsupport.h>
|
2012-12-06 17:20:58 +01:00
|
|
|
#include <qmljstools/qmljsmodelmanager.h>
|
2013-01-30 18:19:31 +01:00
|
|
|
#include <qmljs/qmljsmodelmanagerinterface.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>
|
2013-01-30 18:19:31 +01:00
|
|
|
|
|
|
|
|
#include <qbs.h>
|
|
|
|
|
|
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>
|
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:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
2013-02-20 17:40:52 +01:00
|
|
|
static const char CONFIG_CPP_MODULE[] = "cpp";
|
|
|
|
|
static const char CONFIG_DEFINES[] = "defines";
|
|
|
|
|
static const char CONFIG_INCLUDEPATHS[] = "includePaths";
|
2014-07-23 10:48:29 +02:00
|
|
|
static const char CONFIG_SYSTEM_INCLUDEPATHS[] = "systemIncludePaths";
|
2013-02-20 17:40:52 +01:00
|
|
|
static const char CONFIG_FRAMEWORKPATHS[] = "frameworkPaths";
|
2014-07-23 10:48:29 +02:00
|
|
|
static const char CONFIG_SYSTEM_FRAMEWORKPATHS[] = "systemFrameworkPaths";
|
2013-01-30 18:19:31 +01:00
|
|
|
|
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:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
2017-03-03 18:16:34 +01:00
|
|
|
QbsProject::QbsProject(const FileName &fileName) :
|
2018-07-30 22:45:53 +03:00
|
|
|
Project(Constants::MIME_TYPE, fileName, [this] { delayParsing(); }),
|
|
|
|
|
m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this))
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2013-06-11 18:10:42 +02:00
|
|
|
m_parsingDelay.setInterval(1000); // delay parsing by 1s.
|
2013-06-06 18:45:53 +02: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));
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2017-04-27 11:46:56 +02:00
|
|
|
rebuildProjectTree();
|
2017-04-07 14:35:49 +02:00
|
|
|
|
2016-06-28 23:29:21 +03:00
|
|
|
connect(this, &Project::activeTargetChanged, this, &QbsProject::changeActiveTarget);
|
2018-02-21 12:30:09 +01:00
|
|
|
connect(this, &Project::addedTarget, this, [this](Target *t) {
|
|
|
|
|
m_qbsProjects.insert(t, qbs::Project());
|
|
|
|
|
});
|
|
|
|
|
connect(this, &Project::removedTarget, this, [this](Target *t) {
|
|
|
|
|
const auto it = m_qbsProjects.find(t);
|
|
|
|
|
QTC_ASSERT(it != m_qbsProjects.end(), return);
|
|
|
|
|
if (it.value() == m_qbsProject) {
|
|
|
|
|
m_qbsProject = qbs::Project();
|
|
|
|
|
m_projectData = qbs::ProjectData();
|
|
|
|
|
}
|
|
|
|
|
m_qbsProjects.erase(it);
|
|
|
|
|
});
|
2017-09-29 11:14:09 +02:00
|
|
|
auto delayedParsing = [this]() {
|
2018-01-09 15:53:17 +01:00
|
|
|
if (static_cast<ProjectConfiguration *>(sender())->isActive())
|
2017-09-25 19:08:47 +02:00
|
|
|
delayParsing();
|
2017-09-29 11:14:09 +02:00
|
|
|
};
|
|
|
|
|
subscribeSignal(&BuildConfiguration::environmentChanged, this, delayedParsing);
|
|
|
|
|
subscribeSignal(&BuildConfiguration::buildDirectoryChanged, this, delayedParsing);
|
2018-01-04 14:50:05 +01:00
|
|
|
subscribeSignal(&QbsBuildConfiguration::qbsConfigurationChanged, this, delayedParsing);
|
2017-09-29 11:14:09 +02:00
|
|
|
subscribeSignal(&Target::activeBuildConfigurationChanged, this, delayedParsing);
|
2013-06-06 18:45:53 +02:00
|
|
|
|
2016-06-28 23:29:21 +03:00
|
|
|
connect(&m_parsingDelay, &QTimer::timeout, this, &QbsProject::startParsing);
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QbsProject::~QbsProject()
|
|
|
|
|
{
|
2017-02-06 16:59:53 +01:00
|
|
|
delete m_cppCodeModelUpdater;
|
2014-06-16 14:42:21 +02:00
|
|
|
delete m_qbsProjectParser;
|
2017-06-07 18:35:51 +02:00
|
|
|
delete m_importer;
|
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);
|
2017-06-13 16:43:12 +02:00
|
|
|
std::for_each(m_qbsDocuments.cbegin(), m_qbsDocuments.cend(),
|
|
|
|
|
[](Core::IDocument *doc) { doc->deleteLater(); });
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-02 10:20:43 +02:00
|
|
|
void QbsProject::projectLoaded()
|
|
|
|
|
{
|
|
|
|
|
m_parsingDelay.start(0);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-07 18:35:51 +02:00
|
|
|
ProjectImporter *QbsProject::projectImporter() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_importer)
|
|
|
|
|
m_importer = new QbsProjectImporter(projectFilePath());
|
|
|
|
|
return m_importer;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-20 14:48:02 +02:00
|
|
|
QVariant QbsProject::additionalData(Id id, const Target *target) const
|
|
|
|
|
{
|
|
|
|
|
if (id == "QmlDesignerImportPath") {
|
|
|
|
|
const qbs::Project qbsProject = m_qbsProjects.value(const_cast<Target *>(target));
|
|
|
|
|
const qbs::ProjectData projectData = qbsProject.isValid()
|
|
|
|
|
? qbsProject.projectData() : qbs::ProjectData();
|
|
|
|
|
QStringList designerImportPaths;
|
|
|
|
|
foreach (const qbs::ProductData &product, projectData.allProducts()) {
|
|
|
|
|
designerImportPaths << product.properties()
|
|
|
|
|
.value("qmlDesignerImportPaths").toStringList();
|
|
|
|
|
}
|
|
|
|
|
return designerImportPaths;
|
|
|
|
|
}
|
|
|
|
|
return Project::additionalData(id, target);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-01 16:03:58 +01:00
|
|
|
QStringList QbsProject::filesGeneratedFrom(const QString &sourceFile) const
|
|
|
|
|
{
|
|
|
|
|
QStringList generated;
|
|
|
|
|
foreach (const qbs::ProductData &data, m_projectData.allProducts())
|
|
|
|
|
generated << m_qbsProject.generatedFiles(data, sourceFile, false);
|
|
|
|
|
return generated;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 12:18:29 +02:00
|
|
|
bool QbsProject::isProjectEditable() const
|
|
|
|
|
{
|
2015-02-03 23:56:02 +02:00
|
|
|
return m_qbsProject.isValid() && !isParsing() && !BuildManager::isBuilding();
|
2014-07-24 12:18:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-18 15:46:24 +02:00
|
|
|
class ChangeExpector
|
|
|
|
|
{
|
|
|
|
|
public:
|
2015-02-03 23:56:02 +02:00
|
|
|
ChangeExpector(const QString &filePath, const QSet<IDocument *> &documents)
|
2018-07-27 12:10:20 +02:00
|
|
|
: m_document(nullptr)
|
2014-07-18 15:46:24 +02:00
|
|
|
{
|
2015-02-03 23:56:02 +02:00
|
|
|
foreach (IDocument * const doc, documents) {
|
2014-12-21 21:54:30 +02:00
|
|
|
if (doc->filePath().toString() == filePath) {
|
2014-07-18 15:46:24 +02:00
|
|
|
m_document = doc;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QTC_ASSERT(m_document, return);
|
2015-02-03 23:56:02 +02:00
|
|
|
DocumentManager::expectFileChange(filePath);
|
|
|
|
|
m_wasInDocumentManager = DocumentManager::removeDocument(m_document);
|
2014-07-18 15:46:24 +02:00
|
|
|
QTC_CHECK(m_wasInDocumentManager);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~ChangeExpector()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_document, return);
|
2015-02-03 23:56:02 +02:00
|
|
|
DocumentManager::addDocument(m_document);
|
|
|
|
|
DocumentManager::unexpectFileChange(m_document->filePath().toString());
|
2014-07-18 15:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2015-02-03 23:56:02 +02:00
|
|
|
IDocument *m_document;
|
2014-07-18 15:46:24 +02:00
|
|
|
bool m_wasInDocumentManager;
|
|
|
|
|
};
|
|
|
|
|
|
2014-08-18 16:30:43 +02:00
|
|
|
bool QbsProject::ensureWriteableQbsFile(const QString &file)
|
|
|
|
|
{
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 13:20:26 +01:00
|
|
|
bool QbsProject::addFilesToProduct(const QStringList &filePaths,
|
2017-06-26 12:39:52 +02:00
|
|
|
const qbs::ProductData productData,
|
|
|
|
|
const qbs::GroupData groupData, QStringList *notAdded)
|
2014-07-18 15:46:24 +02:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_qbsProject.isValid(), return false);
|
|
|
|
|
QStringList allPaths = groupData.allFilePaths();
|
2014-11-07 13:40:49 +01:00
|
|
|
const QString productFilePath = productData.location().filePath();
|
2014-07-18 15:46:24 +02:00
|
|
|
ChangeExpector expector(productFilePath, m_qbsDocuments);
|
2014-08-18 16:30:43 +02:00
|
|
|
ensureWriteableQbsFile(productFilePath);
|
2014-07-18 15:46:24 +02:00
|
|
|
foreach (const QString &path, filePaths) {
|
|
|
|
|
qbs::ErrorInfo err = m_qbsProject.addFiles(productData, groupData, QStringList() << path);
|
|
|
|
|
if (err.hasError()) {
|
2015-02-03 23:56:02 +02:00
|
|
|
MessageManager::write(err.toString());
|
2014-07-18 15:46:24 +02:00
|
|
|
*notAdded += path;
|
|
|
|
|
} else {
|
|
|
|
|
allPaths += path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (notAdded->count() != filePaths.count()) {
|
|
|
|
|
m_projectData = m_qbsProject.projectData();
|
2017-11-14 14:19:52 +01:00
|
|
|
delayedUpdateAfterParse();
|
2014-07-18 15:46:24 +02:00
|
|
|
}
|
|
|
|
|
return notAdded->isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 13:20:26 +01:00
|
|
|
bool QbsProject::removeFilesFromProduct(const QStringList &filePaths,
|
2017-06-26 12:39:52 +02:00
|
|
|
const qbs::ProductData productData,
|
|
|
|
|
const qbs::GroupData groupData,
|
2017-02-17 13:20:26 +01:00
|
|
|
QStringList *notRemoved)
|
2014-07-18 15:46:24 +02:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_qbsProject.isValid(), return false);
|
|
|
|
|
QStringList allPaths = groupData.allFilePaths();
|
2014-11-07 13:40:49 +01:00
|
|
|
const QString productFilePath = productData.location().filePath();
|
2014-07-18 15:46:24 +02:00
|
|
|
ChangeExpector expector(productFilePath, m_qbsDocuments);
|
2014-08-18 16:30:43 +02:00
|
|
|
ensureWriteableQbsFile(productFilePath);
|
2014-07-18 15:46:24 +02:00
|
|
|
foreach (const QString &path, filePaths) {
|
|
|
|
|
qbs::ErrorInfo err
|
|
|
|
|
= m_qbsProject.removeFiles(productData, groupData, QStringList() << path);
|
|
|
|
|
if (err.hasError()) {
|
2015-02-03 23:56:02 +02:00
|
|
|
MessageManager::write(err.toString());
|
2014-07-18 15:46:24 +02:00
|
|
|
*notRemoved += path;
|
|
|
|
|
} else {
|
|
|
|
|
allPaths.removeOne(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (notRemoved->count() != filePaths.count()) {
|
|
|
|
|
m_projectData = m_qbsProject.projectData();
|
2017-11-14 14:19:52 +01:00
|
|
|
delayedUpdateAfterParse();
|
2014-07-18 15:46:24 +02:00
|
|
|
}
|
|
|
|
|
return notRemoved->isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 13:20:26 +01:00
|
|
|
bool QbsProject::renameFileInProduct(const QString &oldPath, const QString &newPath,
|
2017-06-26 12:39:52 +02:00
|
|
|
const qbs::ProductData productData,
|
|
|
|
|
const qbs::GroupData groupData)
|
2014-09-11 17:12:03 +02:00
|
|
|
{
|
|
|
|
|
if (newPath.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
QStringList dummy;
|
2017-02-17 13:20:26 +01:00
|
|
|
if (!removeFilesFromProduct(QStringList(oldPath), productData, groupData, &dummy))
|
2014-09-11 17:12:03 +02:00
|
|
|
return false;
|
|
|
|
|
qbs::ProductData newProductData;
|
|
|
|
|
foreach (const qbs::ProductData &p, m_projectData.allProducts()) {
|
|
|
|
|
if (uniqueProductName(p) == uniqueProductName(productData)) {
|
|
|
|
|
newProductData = p;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!newProductData.isValid())
|
|
|
|
|
return false;
|
|
|
|
|
qbs::GroupData newGroupData;
|
|
|
|
|
foreach (const qbs::GroupData &g, newProductData.groups()) {
|
|
|
|
|
if (g.name() == groupData.name()) {
|
|
|
|
|
newGroupData = g;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!newGroupData.isValid())
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-02-17 13:20:26 +01:00
|
|
|
return addFilesToProduct(QStringList() << newPath, newProductData, newGroupData, &dummy);
|
2014-09-11 17:12:03 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-07 13:46:50 +02:00
|
|
|
static qbs::AbstractJob *doBuildOrClean(const qbs::Project &project,
|
|
|
|
|
const QList<qbs::ProductData> &products,
|
|
|
|
|
const qbs::BuildOptions &options)
|
|
|
|
|
{
|
|
|
|
|
if (products.isEmpty())
|
|
|
|
|
return project.buildAllProducts(options);
|
|
|
|
|
return project.buildSomeProducts(products, options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static qbs::AbstractJob *doBuildOrClean(const qbs::Project &project,
|
|
|
|
|
const QList<qbs::ProductData> &products,
|
|
|
|
|
const qbs::CleanOptions &options)
|
|
|
|
|
{
|
|
|
|
|
if (products.isEmpty())
|
|
|
|
|
return project.cleanAllProducts(options);
|
|
|
|
|
return project.cleanSomeProducts(products, options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Options>
|
|
|
|
|
qbs::AbstractJob *QbsProject::buildOrClean(const Options &opts, const QStringList &productNames,
|
|
|
|
|
QString &error)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2018-07-27 12:10:20 +02:00
|
|
|
QTC_ASSERT(qbsProject().isValid(), return nullptr);
|
|
|
|
|
QTC_ASSERT(!isParsing(), return nullptr);
|
2014-11-17 16:26:23 +01:00
|
|
|
|
|
|
|
|
QList<qbs::ProductData> products;
|
|
|
|
|
foreach (const QString &productName, productNames) {
|
|
|
|
|
bool found = false;
|
|
|
|
|
foreach (const qbs::ProductData &data, qbsProjectData().allProducts()) {
|
|
|
|
|
if (uniqueProductName(data) == productName) {
|
|
|
|
|
found = true;
|
|
|
|
|
products.append(data);
|
|
|
|
|
break;
|
2013-06-10 15:40:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-11-17 16:26:23 +01:00
|
|
|
if (!found) {
|
2017-04-07 13:46:50 +02:00
|
|
|
const bool cleaningRequested = std::is_same<Options, qbs::CleanOptions>::value;
|
|
|
|
|
error = tr("%1: Selected products do not exist anymore.")
|
|
|
|
|
.arg(cleaningRequested ? tr("Cannot clean") : tr("Cannot build"));
|
|
|
|
|
return nullptr;
|
2014-11-17 16:26:23 +01:00
|
|
|
}
|
2013-06-10 15:40:18 +02:00
|
|
|
}
|
2017-04-07 13:46:50 +02:00
|
|
|
return doBuildOrClean(qbsProject(), products, opts);
|
|
|
|
|
}
|
2014-11-17 16:26:23 +01:00
|
|
|
|
2017-04-07 13:46:50 +02:00
|
|
|
qbs::BuildJob *QbsProject::build(const qbs::BuildOptions &opts, QStringList productNames,
|
|
|
|
|
QString &error)
|
|
|
|
|
{
|
|
|
|
|
return static_cast<qbs::BuildJob *>(buildOrClean(opts, productNames, error));
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2017-04-07 13:46:50 +02:00
|
|
|
qbs::CleanJob *QbsProject::clean(const qbs::CleanOptions &opts, const QStringList &productNames,
|
|
|
|
|
QString &error)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2017-04-07 13:46:50 +02:00
|
|
|
return static_cast<qbs::CleanJob *>(buildOrClean(opts, productNames, error));
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-12 16:19:52 +02:00
|
|
|
qbs::InstallJob *QbsProject::install(const qbs::InstallOptions &opts)
|
|
|
|
|
{
|
2013-09-06 18:02:46 +02:00
|
|
|
if (!qbsProject().isValid())
|
2018-07-27 12:10:20 +02:00
|
|
|
return nullptr;
|
2013-09-06 18:02:46 +02:00
|
|
|
return qbsProject().installAllProducts(opts);
|
2013-04-12 16:19:52 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 18:25:59 +02:00
|
|
|
QString QbsProject::profileForTarget(const Target *t) const
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2017-02-28 18:41:02 +01:00
|
|
|
return QbsManager::profileForKit(t->kit());
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QbsProject::hasParseResult() const
|
|
|
|
|
{
|
2013-09-06 18:02:46 +02:00
|
|
|
return qbsProject().isValid();
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-06 18:02:46 +02:00
|
|
|
qbs::Project QbsProject::qbsProject() const
|
2013-04-16 13:14:07 +02:00
|
|
|
{
|
2014-07-10 17:01:54 +02:00
|
|
|
return m_qbsProject;
|
2013-04-16 13:14:07 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-22 09:49:51 +02:00
|
|
|
qbs::ProjectData QbsProject::qbsProjectData() const
|
2013-04-16 13:14:07 +02:00
|
|
|
{
|
2014-07-22 09:49:51 +02:00
|
|
|
return m_projectData;
|
2013-04-16 13:14:07 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-06 11:16:41 +02:00
|
|
|
bool QbsProject::needsSpecialDeployment() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 11:21:11 +01:00
|
|
|
bool QbsProject::checkCancelStatus()
|
|
|
|
|
{
|
|
|
|
|
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;
|
2017-09-25 19:08:47 +02:00
|
|
|
emitParsingFinished(false);
|
2016-03-11 11:21:11 +01:00
|
|
|
parseCurrentBuildConfiguration();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 11:32:39 +02:00
|
|
|
static QSet<QString> toQStringSet(const std::set<QString> &src)
|
|
|
|
|
{
|
|
|
|
|
QSet<QString> result;
|
2017-04-02 07:52:18 +03:00
|
|
|
result.reserve(int(src.size()));
|
2017-03-31 11:32:39 +02:00
|
|
|
std::copy(src.begin(), src.end(), Utils::inserter(result));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 17:53:26 +01:00
|
|
|
void QbsProject::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");
|
|
|
|
|
updateProjectNodes();
|
2017-03-31 11:32:39 +02:00
|
|
|
updateDocuments(toQStringSet(m_qbsProject.buildSystemFiles()));
|
2016-03-11 17:53:26 +01:00
|
|
|
updateBuildTargetData();
|
2016-03-11 11:21:11 +01:00
|
|
|
updateCppCodeModel();
|
|
|
|
|
updateQmlJsCodeModel();
|
|
|
|
|
emit fileListChanged();
|
2018-04-06 12:21:34 +02:00
|
|
|
emit dataChanged();
|
2016-03-08 14:00:56 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-14 14:19:52 +01:00
|
|
|
void QbsProject::delayedUpdateAfterParse()
|
|
|
|
|
{
|
|
|
|
|
QTimer::singleShot(0, this, &QbsProject::updateAfterParse);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-24 18:13:48 +01:00
|
|
|
void QbsProject::updateProjectNodes()
|
|
|
|
|
{
|
|
|
|
|
OpTimer opTimer("updateProjectNodes");
|
2017-04-27 11:46:56 +02:00
|
|
|
rebuildProjectTree();
|
2017-01-24 18:13:48 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-16 15:57:20 +02:00
|
|
|
FileName QbsProject::installRoot()
|
|
|
|
|
{
|
|
|
|
|
if (!activeTarget())
|
|
|
|
|
return FileName();
|
|
|
|
|
const auto * const bc
|
|
|
|
|
= qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
|
|
|
|
|
if (!bc)
|
|
|
|
|
return FileName();
|
|
|
|
|
const QbsBuildStep * const buildStep = bc->qbsStep();
|
|
|
|
|
return buildStep && buildStep->install() ? buildStep->installRoot() : FileName();
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
void QbsProject::handleQbsParsingDone(bool success)
|
|
|
|
|
{
|
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
|
|
|
m_qbsProject = m_qbsProjectParser->qbsProject();
|
2016-07-15 11:02:10 +02:00
|
|
|
m_qbsProjects.insert(activeTarget(), m_qbsProject);
|
2016-03-11 17:53:26 +01:00
|
|
|
bool dataChanged = false;
|
2014-07-10 17:01:54 +02:00
|
|
|
if (success) {
|
2016-03-08 14:00:56 +01:00
|
|
|
QTC_ASSERT(m_qbsProject.isValid(), return);
|
2016-03-11 17:53:26 +01:00
|
|
|
const qbs::ProjectData &projectData = m_qbsProject.projectData();
|
|
|
|
|
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
|
|
|
|
2016-03-11 17:53:26 +01:00
|
|
|
if (dataChanged)
|
|
|
|
|
updateAfterParse();
|
2017-07-13 10:51:15 +02:00
|
|
|
emitParsingFinished(success);
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2017-04-27 11:46:56 +02:00
|
|
|
void QbsProject::rebuildProjectTree()
|
|
|
|
|
{
|
2018-04-26 14:41:46 +02:00
|
|
|
std::unique_ptr<QbsRootProjectNode> newRoot = Internal::QbsNodeTreeBuilder::buildTree(this);
|
2017-04-27 11:46:56 +02:00
|
|
|
setDisplayName(newRoot ? newRoot->displayName() : projectFilePath().toFileInfo().completeBaseName());
|
2018-04-26 14:41:46 +02:00
|
|
|
setRootProjectNode(std::move(newRoot));
|
2017-04-27 11:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-11 17:53:26 +01:00
|
|
|
void QbsProject::handleRuleExecutionDone()
|
|
|
|
|
{
|
|
|
|
|
qCDebug(qbsPmLog) << "Rule execution done";
|
|
|
|
|
|
|
|
|
|
if (checkCancelStatus())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_qbsProjectParser->deleteLater();
|
2018-07-27 12:10:20 +02:00
|
|
|
m_qbsProjectParser = nullptr;
|
2016-03-11 17:53:26 +01:00
|
|
|
m_qbsUpdateFutureInterface->reportFinished();
|
|
|
|
|
delete m_qbsUpdateFutureInterface;
|
2018-07-27 12:10:20 +02:00
|
|
|
m_qbsUpdateFutureInterface = nullptr;
|
2016-03-11 17:53:26 +01:00
|
|
|
|
|
|
|
|
QTC_ASSERT(m_qbsProject.isValid(), return);
|
|
|
|
|
m_projectData = m_qbsProject.projectData();
|
|
|
|
|
updateAfterParse();
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 18:25:59 +02:00
|
|
|
void QbsProject::changeActiveTarget(Target *t)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2018-08-30 10:53:50 +02:00
|
|
|
bool targetFound = false;
|
|
|
|
|
for (auto it = m_qbsProjects.begin(); it != m_qbsProjects.end(); ++it) {
|
|
|
|
|
qbs::Project &qbsProjectForTarget = it.value();
|
|
|
|
|
if (it.key() == t) {
|
|
|
|
|
m_qbsProject = qbsProjectForTarget;
|
|
|
|
|
targetFound = true;
|
|
|
|
|
} else if (qbsProjectForTarget.isValid() && !BuildManager::isBuilding(it.key())) {
|
|
|
|
|
qbsProjectForTarget = qbs::Project();
|
|
|
|
|
}
|
2018-01-09 15:53:17 +01:00
|
|
|
}
|
2018-08-30 10:53:50 +02:00
|
|
|
QTC_ASSERT(targetFound || !t, m_qbsProject = qbs::Project());
|
|
|
|
|
if (t && t->isActive())
|
|
|
|
|
delayParsing();
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-26 16:19:43 +01:00
|
|
|
void QbsProject::startParsing()
|
|
|
|
|
{
|
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.
|
2015-02-03 23:56:02 +02:00
|
|
|
if (BuildManager::isBuilding(this)) {
|
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
|
|
|
}
|
|
|
|
|
|
2013-06-06 18:45:53 +02:00
|
|
|
void QbsProject::delayParsing()
|
|
|
|
|
{
|
|
|
|
|
m_parsingDelay.start();
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-17 12:02:56 +02:00
|
|
|
void QbsProject::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);
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
if (!activeTarget())
|
|
|
|
|
return;
|
2018-07-27 12:10:20 +02:00
|
|
|
auto bc = qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
|
2013-01-30 18:19:31 +01:00
|
|
|
if (!bc)
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-12 14:59:48 +02:00
|
|
|
parse(bc->qbsConfiguration(), bc->environment(), bc->buildDirectory().toString(),
|
|
|
|
|
bc->configurationName());
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2014-07-14 14:22:27 +02:00
|
|
|
void QbsProject::cancelParsing()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_qbsProjectParser, return);
|
|
|
|
|
m_cancelStatus = CancelStatusCancelingAltoghether;
|
|
|
|
|
m_qbsProjectParser->cancel();
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-11 12:44:12 +02:00
|
|
|
void QbsProject::updateAfterBuild()
|
|
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer opTimer("updateAfterBuild");
|
2014-07-28 09:53:06 +02:00
|
|
|
QTC_ASSERT(m_qbsProject.isValid(), return);
|
2016-10-06 15:59:23 +02:00
|
|
|
const qbs::ProjectData &projectData = m_qbsProject.projectData();
|
2018-04-16 15:57:20 +02:00
|
|
|
if (projectData == m_projectData) {
|
|
|
|
|
if (activeTarget()) {
|
|
|
|
|
DeploymentData deploymentData = activeTarget()->deploymentData();
|
|
|
|
|
deploymentData.setLocalInstallRoot(installRoot());
|
|
|
|
|
activeTarget()->setDeploymentData(deploymentData);
|
|
|
|
|
}
|
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;
|
2017-01-24 18:13:48 +01:00
|
|
|
updateProjectNodes();
|
2014-07-11 12:44:12 +02:00
|
|
|
updateBuildTargetData();
|
2016-03-02 13:04:48 +01:00
|
|
|
if (m_extraCompilersPending) {
|
|
|
|
|
m_extraCompilersPending = false;
|
|
|
|
|
updateCppCodeModel();
|
|
|
|
|
}
|
2018-04-06 12:21:34 +02:00
|
|
|
emit dataChanged();
|
2014-07-11 12:44:12 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-16 14:42:21 +02:00
|
|
|
void QbsProject::registerQbsProjectParser(QbsProjectParser *p)
|
|
|
|
|
{
|
|
|
|
|
m_parsingDelay.stop();
|
|
|
|
|
|
|
|
|
|
if (m_qbsProjectParser) {
|
|
|
|
|
m_qbsProjectParser->disconnect(this);
|
|
|
|
|
m_qbsProjectParser->deleteLater();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_qbsProjectParser = p;
|
|
|
|
|
|
2016-03-08 14:00:56 +01:00
|
|
|
if (p) {
|
2016-03-11 17:53:26 +01:00
|
|
|
connect(m_qbsProjectParser, &QbsProjectParser::ruleExecutionDone,
|
|
|
|
|
this, &QbsProject::handleRuleExecutionDone);
|
2016-06-28 23:29:21 +03:00
|
|
|
connect(m_qbsProjectParser, &QbsProjectParser::done,
|
|
|
|
|
this, &QbsProject::handleQbsParsingDone);
|
2016-03-08 14:00:56 +01:00
|
|
|
}
|
2014-06-16 14:42:21 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-18 12:06:11 +02:00
|
|
|
void QbsProject::generateErrors(const qbs::ErrorInfo &e)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2013-06-18 12:06:11 +02:00
|
|
|
foreach (const qbs::ErrorItem &item, e.items())
|
2013-08-29 18:25:59 +02:00
|
|
|
TaskHub::addTask(Task::Error, item.description(),
|
|
|
|
|
ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM,
|
2014-11-07 13:40:49 +01:00
|
|
|
FileName::fromString(item.codeLocation().filePath()),
|
2013-08-29 18:25:59 +02:00
|
|
|
item.codeLocation().line());
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2014-09-05 12:08:15 +02:00
|
|
|
QString QbsProject::uniqueProductName(const qbs::ProductData &product)
|
|
|
|
|
{
|
2018-02-09 17:18:29 +01:00
|
|
|
return product.name() + QLatin1Char('.') + product.multiplexConfigurationId();
|
2014-09-05 12:08:15 +02:00
|
|
|
}
|
|
|
|
|
|
2017-07-27 10:10:51 +02:00
|
|
|
void QbsProject::configureAsExampleProject(const QSet<Id> &platforms)
|
|
|
|
|
{
|
|
|
|
|
QList<const BuildInfo *> infoList;
|
|
|
|
|
QList<Kit *> kits = KitManager::kits();
|
|
|
|
|
const auto qtVersionMatchesPlatform = [platforms](const QtSupport::BaseQtVersion *version) {
|
|
|
|
|
return platforms.isEmpty() || platforms.intersects(version->targetDeviceTypes());
|
|
|
|
|
};
|
|
|
|
|
foreach (Kit *k, kits) {
|
|
|
|
|
const QtSupport::BaseQtVersion * const qtVersion
|
|
|
|
|
= QtSupport::QtKitInformation::qtVersion(k);
|
|
|
|
|
if (!qtVersion || !qtVersionMatchesPlatform(qtVersion))
|
|
|
|
|
continue;
|
|
|
|
|
const IBuildConfigurationFactory * const factory
|
|
|
|
|
= IBuildConfigurationFactory::find(k, projectFilePath().toString());
|
|
|
|
|
if (!factory)
|
|
|
|
|
continue;
|
2017-10-19 13:46:45 +02:00
|
|
|
const auto &buildInfos = factory->availableSetups(k, projectFilePath().toString());
|
|
|
|
|
for (BuildInfo * const info : buildInfos)
|
2017-07-27 10:10:51 +02:00
|
|
|
infoList << info;
|
|
|
|
|
}
|
|
|
|
|
setup(infoList);
|
|
|
|
|
qDeleteAll(infoList);
|
|
|
|
|
prepareForParsing();
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-12 14:59:48 +02:00
|
|
|
void QbsProject::parse(const QVariantMap &config, const Environment &env, const QString &dir,
|
|
|
|
|
const QString &configName)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2013-06-11 18:10:42 +02:00
|
|
|
prepareForParsing();
|
2014-06-16 14:42:21 +02:00
|
|
|
QTC_ASSERT(!m_qbsProjectParser, return);
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2014-06-16 14:42:21 +02:00
|
|
|
registerQbsProjectParser(new QbsProjectParser(this, m_qbsUpdateFutureInterface));
|
2013-05-30 14:14:42 +02:00
|
|
|
|
2018-02-01 17:25:14 +01:00
|
|
|
QbsManager::updateProfileIfNecessary(activeTarget()->kit());
|
2017-06-12 14:59:48 +02:00
|
|
|
m_qbsProjectParser->parse(config, env, dir, configName);
|
2017-07-13 10:51:15 +02:00
|
|
|
emitParsingStarted();
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QbsProject::prepareForParsing()
|
|
|
|
|
{
|
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(),
|
2014-04-17 15:14:14 +02:00
|
|
|
tr("Reading Project \"%1\"").arg(displayName()), "Qbs.QbsEvaluate");
|
2013-01-30 18:19:31 +01:00
|
|
|
m_qbsUpdateFutureInterface->reportStarted();
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-18 15:52:29 +02:00
|
|
|
void QbsProject::updateDocuments(const QSet<QString> &files)
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer opTimer("updateDocuments");
|
2013-01-30 18:19:31 +01:00
|
|
|
// Update documents:
|
2013-06-18 15:52:29 +02:00
|
|
|
QSet<QString> newFiles = files;
|
2016-01-08 12:12:27 +01:00
|
|
|
QTC_ASSERT(!newFiles.isEmpty(), newFiles << projectFilePath().toString());
|
2013-01-30 18:19:31 +01:00
|
|
|
QSet<QString> oldFiles;
|
2013-08-29 17:56:28 +02:00
|
|
|
foreach (IDocument *doc, m_qbsDocuments)
|
2014-12-21 21:54:30 +02:00
|
|
|
oldFiles.insert(doc->filePath().toString());
|
2013-01-30 18:19:31 +01:00
|
|
|
|
|
|
|
|
QSet<QString> filesToAdd = newFiles;
|
|
|
|
|
filesToAdd.subtract(oldFiles);
|
|
|
|
|
QSet<QString> filesToRemove = oldFiles;
|
|
|
|
|
filesToRemove.subtract(newFiles);
|
|
|
|
|
|
2013-08-29 17:56:28 +02:00
|
|
|
QSet<IDocument *> currentDocuments = m_qbsDocuments;
|
|
|
|
|
foreach (IDocument *doc, currentDocuments) {
|
2014-12-21 21:54:30 +02:00
|
|
|
if (filesToRemove.contains(doc->filePath().toString())) {
|
2013-01-30 18:19:31 +01:00
|
|
|
m_qbsDocuments.remove(doc);
|
2017-05-09 12:18:34 +02:00
|
|
|
doc->deleteLater();
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
2013-08-29 17:56:28 +02:00
|
|
|
QSet<IDocument *> toAdd;
|
2013-01-30 18:19:31 +01:00
|
|
|
foreach (const QString &f, filesToAdd)
|
2017-03-29 11:11:49 +02:00
|
|
|
toAdd.insert(new ProjectDocument(Constants::MIME_TYPE, FileName::fromString(f),
|
|
|
|
|
[this]() { delayParsing(); }));
|
2013-01-30 18:19:31 +01:00
|
|
|
|
|
|
|
|
m_qbsDocuments.unite(toAdd);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 10:54:15 +02:00
|
|
|
static CppTools::ProjectFile::Kind cppFileType(const qbs::ArtifactData &sourceFile)
|
2016-02-22 15:47:39 +01:00
|
|
|
{
|
2017-01-24 15:37:28 +01:00
|
|
|
if (sourceFile.fileTags().contains(QLatin1String("hpp"))) {
|
|
|
|
|
if (CppTools::ProjectFile::isAmbiguousHeader(sourceFile.filePath()))
|
|
|
|
|
return CppTools::ProjectFile::AmbiguousHeader;
|
2016-02-22 15:47:39 +01:00
|
|
|
return CppTools::ProjectFile::CXXHeader;
|
2017-01-24 15:37:28 +01:00
|
|
|
}
|
2016-02-22 15:47:39 +01:00
|
|
|
if (sourceFile.fileTags().contains(QLatin1String("cpp")))
|
|
|
|
|
return CppTools::ProjectFile::CXXSource;
|
|
|
|
|
if (sourceFile.fileTags().contains(QLatin1String("c")))
|
|
|
|
|
return CppTools::ProjectFile::CSource;
|
|
|
|
|
if (sourceFile.fileTags().contains(QLatin1String("objc")))
|
|
|
|
|
return CppTools::ProjectFile::ObjCSource;
|
|
|
|
|
if (sourceFile.fileTags().contains(QLatin1String("objcpp")))
|
|
|
|
|
return CppTools::ProjectFile::ObjCXXSource;
|
2017-02-01 09:48:58 +01:00
|
|
|
return CppTools::ProjectFile::Unsupported;
|
2016-02-22 15:47:39 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-27 14:37:41 +01:00
|
|
|
static QString groupLocationToCallGroupId(const qbs::CodeLocation &location)
|
2016-04-11 13:13:07 +02:00
|
|
|
{
|
|
|
|
|
return QString::fromLatin1("%1:%2:%3")
|
|
|
|
|
.arg(location.filePath())
|
|
|
|
|
.arg(location.line())
|
|
|
|
|
.arg(location.column());
|
|
|
|
|
}
|
|
|
|
|
|
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,
|
|
|
|
|
const qbs::PropertyMap &properties)
|
|
|
|
|
{
|
|
|
|
|
const auto getCppProp = [properties](const char *propertyName) {
|
|
|
|
|
return properties.getModuleProperty("cpp", QLatin1String(propertyName));
|
|
|
|
|
};
|
|
|
|
|
const QVariant &enableExceptions = getCppProp("enableExceptions");
|
|
|
|
|
const QVariant &enableRtti = getCppProp("enableRtti");
|
|
|
|
|
QStringList commonFlags = getCppProp("platformCommonCompilerFlags").toStringList();
|
|
|
|
|
commonFlags << getCppProp("commonCompilerFlags").toStringList()
|
|
|
|
|
<< getCppProp("platformDriverFlags").toStringList()
|
|
|
|
|
<< getCppProp("driverFlags").toStringList();
|
|
|
|
|
const QStringList toolchain = properties.getModulePropertiesAsStringList("qbs", "toolchain");
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
const QStringList targetOS = properties.getModulePropertiesAsStringList(
|
|
|
|
|
"qbs", "targetOS");
|
|
|
|
|
if (targetOS.contains("unix")) {
|
|
|
|
|
const QVariant positionIndependentCode = getCppProp("positionIndependentCode");
|
|
|
|
|
if (!positionIndependentCode.isValid() || positionIndependentCode.toBool())
|
|
|
|
|
commonFlags << "-fPIC";
|
|
|
|
|
}
|
|
|
|
|
cFlags = cxxFlags = commonFlags;
|
|
|
|
|
|
2018-08-06 16:49:12 +02:00
|
|
|
const auto cxxLanguageVersion = getCppProp("cxxLanguageVersion").toStringList();
|
|
|
|
|
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);
|
|
|
|
|
if (enableExceptions.isValid()) {
|
|
|
|
|
cxxFlags << QLatin1String(enableExceptions.toBool()
|
|
|
|
|
? "-fexceptions" : "-fno-exceptions");
|
|
|
|
|
}
|
|
|
|
|
if (enableRtti.isValid())
|
|
|
|
|
cxxFlags << QLatin1String(enableRtti.toBool() ? "-frtti" : "-fno-rtti");
|
|
|
|
|
|
2018-08-06 16:49:12 +02:00
|
|
|
const auto cLanguageVersion = getCppProp("cLanguageVersion").toStringList();
|
|
|
|
|
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());
|
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";
|
|
|
|
|
if (enableRtti.isValid())
|
|
|
|
|
cxxFlags << QLatin1String(enableRtti.toBool() ? "/GR" : "/GR-");
|
2018-08-06 16:49:12 +02:00
|
|
|
if (getCppProp("cxxLanguageVersion").toStringList().contains("c++17"))
|
|
|
|
|
cxxFlags << "/std:c++17";
|
2016-11-04 15:49:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-11 13:58:47 +02:00
|
|
|
void QbsProject::updateCppCodeModel()
|
2013-01-30 18:19:31 +01:00
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer optimer("updateCppCodeModel");
|
2014-09-11 13:58:47 +02:00
|
|
|
if (!m_projectData.isValid())
|
2013-01-30 18:19:31 +01:00
|
|
|
return;
|
|
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
const Kit *k = nullptr;
|
|
|
|
|
if (Target *target = activeTarget())
|
|
|
|
|
k = target->kit();
|
|
|
|
|
else
|
|
|
|
|
k = KitManager::defaultKit();
|
|
|
|
|
QTC_ASSERT(k, return);
|
|
|
|
|
|
|
|
|
|
ToolChain *cToolChain
|
|
|
|
|
= ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID);
|
|
|
|
|
ToolChain *cxxToolChain
|
|
|
|
|
= ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
|
|
|
|
|
2014-08-19 12:01:47 +02:00
|
|
|
QtSupport::BaseQtVersion *qtVersion =
|
|
|
|
|
QtSupport::QtKitInformation::qtVersion(activeTarget()->kit());
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2017-02-17 16:17:01 +01:00
|
|
|
CppTools::ProjectPart::QtVersion qtVersionFromKit = CppTools::ProjectPart::NoQt;
|
2013-01-30 18:19:31 +01:00
|
|
|
if (qtVersion) {
|
2018-09-27 10:18:44 +02:00
|
|
|
if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
|
|
|
|
|
qtVersionFromKit = CppTools::ProjectPart::Qt4;
|
2013-01-30 18:19:31 +01:00
|
|
|
else
|
2017-02-17 16:17:01 +01:00
|
|
|
qtVersionFromKit = CppTools::ProjectPart::Qt5;
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-01-15 16:12:54 +01:00
|
|
|
QList<ProjectExplorer::ExtraCompilerFactory *> factories =
|
|
|
|
|
ProjectExplorer::ExtraCompilerFactory::extraCompilerFactories();
|
|
|
|
|
const auto factoriesBegin = factories.constBegin();
|
|
|
|
|
const auto factoriesEnd = factories.constEnd();
|
|
|
|
|
|
|
|
|
|
qDeleteAll(m_extraCompilers);
|
|
|
|
|
m_extraCompilers.clear();
|
2017-02-06 16:59:53 +01:00
|
|
|
|
|
|
|
|
CppTools::RawProjectParts rpps;
|
2014-09-11 13:58:47 +02:00
|
|
|
foreach (const qbs::ProductData &prd, m_projectData.allProducts()) {
|
2016-11-23 12:17:02 +01:00
|
|
|
QString cPch;
|
|
|
|
|
QString cxxPch;
|
|
|
|
|
QString objcPch;
|
|
|
|
|
QString objcxxPch;
|
|
|
|
|
const auto &pchFinder = [&cPch, &cxxPch, &objcPch, &objcxxPch](const qbs::ArtifactData &a) {
|
2018-10-17 11:25:36 +03:00
|
|
|
const QStringList fileTags = a.fileTags();
|
|
|
|
|
if (fileTags.contains("c_pch_src"))
|
2016-11-23 12:17:02 +01:00
|
|
|
cPch = a.filePath();
|
2018-10-17 11:25:36 +03:00
|
|
|
if (fileTags.contains("cpp_pch_src"))
|
2016-11-23 12:17:02 +01:00
|
|
|
cxxPch = a.filePath();
|
2018-10-17 11:25:36 +03:00
|
|
|
if (fileTags.contains("objc_pch_src"))
|
2016-11-23 12:17:02 +01:00
|
|
|
objcPch = a.filePath();
|
2018-10-17 11:25:36 +03:00
|
|
|
if (fileTags.contains("objcpp_pch_src"))
|
2016-11-23 12:17:02 +01:00
|
|
|
objcxxPch = a.filePath();
|
|
|
|
|
};
|
2016-11-24 10:10:56 +01:00
|
|
|
const QList<qbs::ArtifactData> &generatedArtifacts = prd.generatedArtifacts();
|
|
|
|
|
std::for_each(generatedArtifacts.cbegin(), generatedArtifacts.cend(), pchFinder);
|
2016-11-23 12:17:02 +01:00
|
|
|
foreach (const qbs::GroupData &grp, prd.groups()) {
|
2016-11-24 10:10:56 +01:00
|
|
|
const QList<qbs::ArtifactData> &sourceArtifacts = grp.allSourceArtifacts();
|
|
|
|
|
std::for_each(sourceArtifacts.cbegin(), sourceArtifacts.cend(), pchFinder);
|
2016-11-23 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-17 16:17:01 +01:00
|
|
|
const CppTools::ProjectPart::QtVersion qtVersionForPart =
|
|
|
|
|
prd.moduleProperties().getModuleProperty("Qt.core", "version").isValid()
|
|
|
|
|
? qtVersionFromKit
|
|
|
|
|
: CppTools::ProjectPart::NoQt;
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
foreach (const qbs::GroupData &grp, prd.groups()) {
|
2017-02-06 16:59:53 +01:00
|
|
|
CppTools::RawProjectPart rpp;
|
|
|
|
|
rpp.setQtVersion(qtVersionForPart);
|
2013-02-20 17:40:52 +01:00
|
|
|
const qbs::PropertyMap &props = grp.properties();
|
2017-02-27 14:37:41 +01:00
|
|
|
rpp.setCallGroupId(groupLocationToCallGroupId(grp.location()));
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2016-11-04 15:49:34 +01:00
|
|
|
QStringList cFlags;
|
|
|
|
|
QStringList cxxFlags;
|
|
|
|
|
getExpandedCompilerFlags(cFlags, cxxFlags, props);
|
2017-02-06 16:59:53 +01:00
|
|
|
rpp.setFlagsForC({cToolChain, cFlags});
|
|
|
|
|
rpp.setFlagsForCxx({cxxToolChain, cxxFlags});
|
2013-04-28 17:18:50 +04:00
|
|
|
|
2013-02-20 17:40:52 +01:00
|
|
|
QStringList list = props.getModulePropertiesAsStringList(
|
|
|
|
|
QLatin1String(CONFIG_CPP_MODULE),
|
|
|
|
|
QLatin1String(CONFIG_DEFINES));
|
2017-02-07 15:00:38 +01:00
|
|
|
rpp.setMacros(Utils::transform<QVector>(list, [](const QString &s) { return ProjectExplorer::Macro::fromKeyValue(s); }));
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2013-02-20 17:40:52 +01:00
|
|
|
list = props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE),
|
|
|
|
|
QLatin1String(CONFIG_INCLUDEPATHS));
|
2014-07-23 10:48:29 +02:00
|
|
|
list.append(props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE),
|
|
|
|
|
QLatin1String(CONFIG_SYSTEM_INCLUDEPATHS)));
|
2017-01-20 11:30:49 +01:00
|
|
|
list.removeDuplicates();
|
2018-09-03 16:10:43 +02:00
|
|
|
ProjectExplorer::HeaderPaths grpHeaderPaths;
|
2014-06-25 17:23:19 +02:00
|
|
|
foreach (const QString &p, list)
|
2018-09-13 11:44:43 +02:00
|
|
|
grpHeaderPaths += {FileName::fromUserInput(p).toString(), HeaderPathType::User};
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2013-02-20 17:40:52 +01:00
|
|
|
list = props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE),
|
|
|
|
|
QLatin1String(CONFIG_FRAMEWORKPATHS));
|
2014-07-23 10:48:29 +02:00
|
|
|
list.append(props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE),
|
|
|
|
|
QLatin1String(CONFIG_SYSTEM_FRAMEWORKPATHS)));
|
2017-01-20 11:30:49 +01:00
|
|
|
list.removeDuplicates();
|
2014-06-25 17:23:19 +02:00
|
|
|
foreach (const QString &p, list)
|
2018-09-13 11:44:43 +02:00
|
|
|
grpHeaderPaths += {FileName::fromUserInput(p).toString(), HeaderPathType::Framework};
|
2013-01-30 18:19:31 +01:00
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
rpp.setHeaderPaths(grpHeaderPaths);
|
2014-08-19 12:01:47 +02:00
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
rpp.setDisplayName(grp.name());
|
2017-03-09 14:13:22 +01:00
|
|
|
rpp.setProjectFileLocation(grp.location().filePath(),
|
|
|
|
|
grp.location().line(), grp.location().column());
|
2018-04-09 12:33:10 +02:00
|
|
|
rpp.setBuildSystemTarget(uniqueProductName(prd));
|
2017-08-29 12:11:27 +02:00
|
|
|
rpp.setBuildTargetType(prd.isRunnable() ? CppTools::ProjectPart::Executable
|
|
|
|
|
: CppTools::ProjectPart::Library);
|
2016-02-22 15:47:39 +01:00
|
|
|
|
2016-08-10 10:54:15 +02:00
|
|
|
QHash<QString, qbs::ArtifactData> filePathToSourceArtifact;
|
2016-11-23 12:17:02 +01:00
|
|
|
bool hasCFiles = false;
|
|
|
|
|
bool hasCxxFiles = false;
|
|
|
|
|
bool hasObjcFiles = false;
|
|
|
|
|
bool hasObjcxxFiles = false;
|
2016-08-10 10:54:15 +02:00
|
|
|
foreach (const qbs::ArtifactData &source, grp.allSourceArtifacts()) {
|
2016-02-22 15:47:39 +01:00
|
|
|
filePathToSourceArtifact.insert(source.filePath(), source);
|
|
|
|
|
|
2016-01-15 16:12:54 +01:00
|
|
|
foreach (const QString &tag, source.fileTags()) {
|
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;
|
2016-01-15 16:12:54 +01:00
|
|
|
for (auto i = factoriesBegin; i != factoriesEnd; ++i) {
|
|
|
|
|
if ((*i)->sourceTag() != tag)
|
|
|
|
|
continue;
|
2016-03-01 16:03:58 +01:00
|
|
|
QStringList generated = m_qbsProject.generatedFiles(prd, source.filePath(),
|
|
|
|
|
false);
|
2016-03-02 13:04:48 +01:00
|
|
|
if (generated.isEmpty()) {
|
|
|
|
|
// We don't know the target files until we build for the first time.
|
|
|
|
|
m_extraCompilersPending = true;
|
2016-01-15 16:12:54 +01:00
|
|
|
continue;
|
2016-03-02 13:04:48 +01:00
|
|
|
}
|
2016-01-15 16:12:54 +01:00
|
|
|
|
|
|
|
|
const FileNameList fileNames = Utils::transform(generated,
|
|
|
|
|
[](const QString &s) {
|
|
|
|
|
return Utils::FileName::fromString(s);
|
|
|
|
|
});
|
|
|
|
|
m_extraCompilers.append((*i)->create(
|
|
|
|
|
this, FileName::fromString(source.filePath()), fileNames));
|
|
|
|
|
}
|
2013-08-07 12:29:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-08-19 12:01:47 +02:00
|
|
|
|
2018-10-17 11:25:36 +03:00
|
|
|
QSet<QString> pchFiles;
|
2016-11-23 12:17:02 +01:00
|
|
|
if (hasCFiles && props.getModuleProperty("cpp", "useCPrecompiledHeader").toBool()
|
|
|
|
|
&& !cPch.isEmpty()) {
|
|
|
|
|
pchFiles << cPch;
|
|
|
|
|
}
|
|
|
|
|
if (hasCxxFiles && props.getModuleProperty("cpp", "useCxxPrecompiledHeader").toBool()
|
|
|
|
|
&& !cxxPch.isEmpty()) {
|
|
|
|
|
pchFiles << cxxPch;
|
|
|
|
|
}
|
|
|
|
|
if (hasObjcFiles && props.getModuleProperty("cpp", "useObjcPrecompiledHeader").toBool()
|
|
|
|
|
&& !objcPch.isEmpty()) {
|
|
|
|
|
pchFiles << objcPch;
|
|
|
|
|
}
|
|
|
|
|
if (hasObjcxxFiles
|
|
|
|
|
&& props.getModuleProperty("cpp", "useObjcxxPrecompiledHeader").toBool()
|
|
|
|
|
&& !objcxxPch.isEmpty()) {
|
|
|
|
|
pchFiles << objcxxPch;
|
|
|
|
|
}
|
|
|
|
|
if (pchFiles.count() > 1) {
|
|
|
|
|
qCWarning(qbsPmLog) << "More than one pch file enabled for source files in group"
|
|
|
|
|
<< grp.name() << "in product" << prd.name();
|
|
|
|
|
qCWarning(qbsPmLog) << "Expect problems with code model";
|
|
|
|
|
}
|
2018-10-17 11:25:36 +03:00
|
|
|
rpp.setPreCompiledHeaders(pchFiles.toList());
|
2017-02-06 16:59:53 +01:00
|
|
|
rpp.setFiles(grp.allFilePaths(), [filePathToSourceArtifact](const QString &filePath) {
|
|
|
|
|
// Keep this lambda thread-safe!
|
|
|
|
|
return cppFileType(filePathToSourceArtifact.value(filePath));
|
2016-02-22 15:47:39 +01:00
|
|
|
});
|
|
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
rpps.append(rpp);
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-15 16:12:54 +01:00
|
|
|
CppTools::GeneratedCodeModelSupport::update(m_extraCompilers);
|
2017-02-06 16:59:53 +01:00
|
|
|
m_cppCodeModelUpdater->update({this, cToolChain, cxxToolChain, k, rpps});
|
2014-10-30 16:17:18 +01:00
|
|
|
}
|
|
|
|
|
|
2014-09-11 13:58:47 +02:00
|
|
|
void QbsProject::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 =
|
2014-07-24 11:48:30 +02:00
|
|
|
modelManager->defaultProjectInfoForProject(this);
|
2015-08-04 15:52:22 +02:00
|
|
|
foreach (const qbs::ProductData &product, m_projectData.allProducts()) {
|
|
|
|
|
static const QString propertyName = QLatin1String("qmlImportPaths");
|
|
|
|
|
foreach (const QString &path, product.properties().value(propertyName).toStringList()) {
|
|
|
|
|
projectInfo.importPaths.maybeInsert(Utils::FileName::fromString(path),
|
|
|
|
|
QmlJS::Dialect::Qml);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-10 14:45:47 +02:00
|
|
|
|
2017-01-30 14:59:10 +01:00
|
|
|
setProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID,
|
|
|
|
|
!projectInfo.sourceFiles.isEmpty());
|
2014-01-23 14:28:31 +01:00
|
|
|
modelManager->updateProjectInfo(projectInfo, this);
|
2013-01-30 18:19:31 +01:00
|
|
|
}
|
|
|
|
|
|
2014-09-05 12:08:15 +02:00
|
|
|
void QbsProject::updateApplicationTargets()
|
2013-09-02 10:12:37 +02:00
|
|
|
{
|
2015-02-03 23:56:02 +02:00
|
|
|
BuildTargetInfoList applications;
|
2014-09-05 12:08:15 +02:00
|
|
|
foreach (const qbs::ProductData &productData, m_projectData.allProducts()) {
|
2014-08-07 15:38:38 +02:00
|
|
|
if (!productData.isEnabled() || !productData.isRunnable())
|
|
|
|
|
continue;
|
2018-02-21 12:30:09 +01:00
|
|
|
const bool isQtcRunnable = productData.properties().value("qtcRunnable").toBool();
|
|
|
|
|
const bool usesTerminal = productData.properties().value("consoleApplication").toBool();
|
|
|
|
|
const QString projectFile = productData.location().filePath();
|
|
|
|
|
QString targetFile;
|
2016-08-10 10:54:15 +02:00
|
|
|
foreach (const qbs::ArtifactData &ta, productData.targetArtifacts()) {
|
2013-09-02 10:12:37 +02:00
|
|
|
QTC_ASSERT(ta.isValid(), continue);
|
2018-03-07 16:03:00 +01:00
|
|
|
if (ta.isExecutable()) {
|
2018-02-21 12:30:09 +01:00
|
|
|
targetFile = ta.filePath();
|
2018-03-07 16:03:00 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
2018-04-16 15:57:20 +02:00
|
|
|
|
2018-02-21 12:30:09 +01:00
|
|
|
BuildTargetInfo bti;
|
2018-04-09 12:33:10 +02:00
|
|
|
bti.buildKey = QbsProject::uniqueProductName(productData);
|
2018-02-21 12:30:09 +01:00
|
|
|
bti.targetFilePath = FileName::fromString(targetFile);
|
|
|
|
|
bti.projectFilePath = FileName::fromString(projectFile);
|
|
|
|
|
bti.isQtcRunnable = isQtcRunnable; // Fixed up below.
|
|
|
|
|
bti.usesTerminal = usesTerminal;
|
|
|
|
|
bti.displayName = productData.fullDisplayName();
|
|
|
|
|
bti.runEnvModifier = [targetFile, productData, this](Utils::Environment &env, bool usingLibraryPaths) {
|
2018-11-28 13:38:11 +01:00
|
|
|
if (!qbsProject().isValid())
|
|
|
|
|
return;
|
2018-02-21 12:30:09 +01:00
|
|
|
QProcessEnvironment procEnv = env.toProcessEnvironment();
|
|
|
|
|
procEnv.insert(QLatin1String("QBS_RUN_FILE_PATH"), targetFile);
|
|
|
|
|
QStringList setupRunEnvConfig;
|
|
|
|
|
if (!usingLibraryPaths)
|
|
|
|
|
setupRunEnvConfig << QLatin1String("ignore-lib-dependencies");
|
|
|
|
|
qbs::RunEnvironment qbsRunEnv = qbsProject().getRunEnvironment(productData,
|
|
|
|
|
qbs::InstallOptions(), procEnv, setupRunEnvConfig, QbsManager::settings());
|
|
|
|
|
qbs::ErrorInfo error;
|
|
|
|
|
procEnv = qbsRunEnv.runEnvironment(&error);
|
|
|
|
|
if (error.hasError()) {
|
|
|
|
|
Core::MessageManager::write(tr("Error retrieving run environment: %1")
|
|
|
|
|
.arg(error.toString()));
|
|
|
|
|
}
|
|
|
|
|
if (!procEnv.isEmpty()) {
|
|
|
|
|
env = Utils::Environment();
|
|
|
|
|
foreach (const QString &key, procEnv.keys())
|
|
|
|
|
env.set(key, procEnv.value(key));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
applications.list.append(bti);
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
2018-02-21 12:30:09 +01:00
|
|
|
if (activeTarget())
|
|
|
|
|
activeTarget()->setApplicationTargets(applications);
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-05 12:08:15 +02:00
|
|
|
void QbsProject::updateDeploymentInfo()
|
2013-09-02 10:12:37 +02:00
|
|
|
{
|
2015-02-03 23:56:02 +02:00
|
|
|
DeploymentData deploymentData;
|
2014-09-05 12:08:15 +02:00
|
|
|
if (m_qbsProject.isValid()) {
|
2016-08-10 10:54:15 +02:00
|
|
|
foreach (const qbs::ArtifactData &f, m_projectData.installableArtifacts()) {
|
|
|
|
|
deploymentData.addFile(f.filePath(), f.installData().installDir(),
|
2015-08-28 10:51:33 +02:00
|
|
|
f.isExecutable() ? DeployableFile::TypeExecutable : DeployableFile::TypeNormal);
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-04-16 15:57:20 +02:00
|
|
|
deploymentData.setLocalInstallRoot(installRoot());
|
2018-02-21 12:30:09 +01:00
|
|
|
if (activeTarget())
|
|
|
|
|
activeTarget()->setDeploymentData(deploymentData);
|
2013-09-02 10:12:37 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-11 12:44:12 +02:00
|
|
|
void QbsProject::updateBuildTargetData()
|
|
|
|
|
{
|
2017-01-24 18:13:48 +01:00
|
|
|
OpTimer optimer("updateBuildTargetData");
|
2014-09-05 12:08:15 +02:00
|
|
|
updateApplicationTargets();
|
|
|
|
|
updateDeploymentInfo();
|
2016-02-09 12:03:37 +01:00
|
|
|
if (activeTarget())
|
|
|
|
|
activeTarget()->updateDefaultRunConfigurations();
|
2014-07-11 12:44:12 +02:00
|
|
|
}
|
|
|
|
|
|
2013-01-30 18:19:31 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace QbsProjectManager
|