CMake: Fix project parsing notification

This builds on top of 08677c0b01 and
fixes one more code path to go through a common entry/exit point.

Change-Id: I1d00fa9242f247028e5d3b0ef3b5fe1d3f4cb03d
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Tobias Hunger
2017-09-28 11:32:39 +02:00
parent 1fa26bd9b3
commit 02533e61cf
24 changed files with 812 additions and 648 deletions

View File

@@ -58,18 +58,13 @@ namespace Internal {
// BuildDirManager: // BuildDirManager:
// -------------------------------------------------------------------- // --------------------------------------------------------------------
BuildDirManager::BuildDirManager(CMakeBuildConfiguration *bc) : BuildDirManager::BuildDirManager() = default;
m_buildConfiguration(bc)
{
QTC_ASSERT(bc, return);
}
BuildDirManager::~BuildDirManager() = default; BuildDirManager::~BuildDirManager() = default;
const Utils::FileName BuildDirManager::workDirectory() const Utils::FileName BuildDirManager::workDirectory(const BuildDirParameters &parameters) const
{ {
const Utils::FileName bdir = m_buildConfiguration->buildDirectory(); const Utils::FileName bdir = parameters.buildDirectory;
const CMakeTool *cmake = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit()); const CMakeTool *cmake = parameters.cmakeTool;
if (bdir.exists()) { if (bdir.exists()) {
return bdir; return bdir;
} else { } else {
@@ -102,21 +97,21 @@ void BuildDirManager::emitErrorOccured(const QString &message) const
m_isHandlingError = false; m_isHandlingError = false;
} }
void BuildDirManager::updateReaderType(std::function<void()> todo) void BuildDirManager::updateReaderType(const BuildDirParameters &p,
std::function<void()> todo)
{ {
BuildDirReader::Parameters p(m_buildConfiguration);
p.buildDirectory = workDirectory();
if (!m_reader || !m_reader->isCompatible(p)) { if (!m_reader || !m_reader->isCompatible(p)) {
m_reader.reset(BuildDirReader::createReader(p)); m_reader.reset(BuildDirReader::createReader(p));
connect(m_reader.get(), &BuildDirReader::configurationStarted, connect(m_reader.get(), &BuildDirReader::configurationStarted,
this, &BuildDirManager::configurationStarted); this, &BuildDirManager::parsingStarted);
connect(m_reader.get(), &BuildDirReader::dataAvailable, connect(m_reader.get(), &BuildDirReader::dataAvailable,
this, &BuildDirManager::emitDataAvailable); this, &BuildDirManager::emitDataAvailable);
connect(m_reader.get(), &BuildDirReader::errorOccured, connect(m_reader.get(), &BuildDirReader::errorOccured,
this, &BuildDirManager::emitErrorOccured); this, &BuildDirManager::emitErrorOccured);
connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty); connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty);
} }
QTC_ASSERT(m_reader, return);
m_reader->setParameters(p); m_reader->setParameters(p);
if (m_reader->isReady()) if (m_reader->isReady())
@@ -125,27 +120,7 @@ void BuildDirManager::updateReaderType(std::function<void()> todo)
connect(m_reader.get(), &BuildDirReader::isReadyNow, this, todo); connect(m_reader.get(), &BuildDirReader::isReadyNow, this, todo);
} }
void BuildDirManager::updateReaderData() bool BuildDirManager::hasConfigChanged()
{
BuildDirReader::Parameters p(m_buildConfiguration);
p.buildDirectory = workDirectory();
m_reader->setParameters(p);
}
void BuildDirManager::parseOnceReaderReady(bool force, bool checkForChanges)
{
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
m_buildTargets.clear();
m_cmakeCache.clear();
if (checkForChanges)
checkConfiguration();
m_reader->stop();
m_reader->parse(force);
}
void BuildDirManager::maybeForceReparseOnceReaderReady()
{ {
checkConfiguration(); checkConfiguration();
@@ -158,14 +133,13 @@ void BuildDirManager::maybeForceReparseOnceReaderReady()
const QByteArrayList criticalKeys const QByteArrayList criticalKeys
= {GENERATOR_KEY, CMAKE_COMMAND_KEY, CMAKE_C_COMPILER_KEY, CMAKE_CXX_COMPILER_KEY}; = {GENERATOR_KEY, CMAKE_COMMAND_KEY, CMAKE_C_COMPILER_KEY, CMAKE_CXX_COMPILER_KEY};
const CMakeConfig currentConfig = parsedConfiguration(); const CMakeConfig currentConfig = takeCMakeConfiguration();
Kit *k = m_buildConfiguration->target()->kit(); const CMakeTool *tool = m_parameters.cmakeTool;
const CMakeTool *tool = CMakeKitInformation::cmakeTool(k); QTC_ASSERT(tool, return false); // No cmake... we should not have ended up here in the first place
QTC_ASSERT(tool, return); // No cmake... we should not have ended up here in the first place const QString extraKitGenerator = m_parameters.extraGenerator;
const QString extraKitGenerator = CMakeGeneratorKitInformation::extraGenerator(k); const QString mainKitGenerator = m_parameters.generator;
const QString mainKitGenerator = CMakeGeneratorKitInformation::generator(k); CMakeConfig targetConfig = m_parameters.configuration;
CMakeConfig targetConfig = m_buildConfiguration->cmakeConfiguration();
targetConfig.append(CMakeConfigItem(GENERATOR_KEY, CMakeConfigItem::INTERNAL, targetConfig.append(CMakeConfigItem(GENERATOR_KEY, CMakeConfigItem::INTERNAL,
QByteArray(), mainKitGenerator.toUtf8())); QByteArray(), mainKitGenerator.toUtf8()));
if (!extraKitGenerator.isEmpty()) if (!extraKitGenerator.isEmpty())
@@ -183,8 +157,8 @@ void BuildDirManager::maybeForceReparseOnceReaderReady()
if (ccit->key == kcit->key) { if (ccit->key == kcit->key) {
if (ccit->value != kcit->value) { if (ccit->value != kcit->value) {
if (criticalKeys.contains(kcit->key)) { if (criticalKeys.contains(kcit->key)) {
clearCache(); clearCache();
return; return false; // no need to trigger a new reader, clearCache will do that
} }
mustReparse = true; mustReparse = true;
} }
@@ -204,8 +178,7 @@ void BuildDirManager::maybeForceReparseOnceReaderReady()
// //
// The critical keys *must* be set in cmake configuration, so those were already // The critical keys *must* be set in cmake configuration, so those were already
// handled above. // handled above.
if (mustReparse || kcit != targetConfig.constEnd()) return mustReparse || kcit != targetConfig.constEnd();
emit requestReparse(true);
} }
bool BuildDirManager::isParsing() const bool BuildDirManager::isParsing() const
@@ -213,83 +186,96 @@ bool BuildDirManager::isParsing() const
return m_reader && m_reader->isParsing(); return m_reader && m_reader->isParsing();
} }
void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &parameters,
int newReaderReparseOptions,
int existingReaderReparseOptions)
{
QTC_ASSERT(parameters.isValid(), return);
if (m_reader)
m_reader->stop();
BuildDirReader *old = m_reader.get();
m_parameters = parameters;
m_parameters.buildDirectory = workDirectory(parameters);
updateReaderType(m_parameters,
[this, old, newReaderReparseOptions, existingReaderReparseOptions]() {
if (old != m_reader.get())
emit requestReparse(newReaderReparseOptions);
else
emit requestReparse(existingReaderReparseOptions);
});
}
CMakeBuildConfiguration *BuildDirManager::buildConfiguration() const
{
return m_parameters.buildConfiguration;
}
void BuildDirManager::becameDirty() void BuildDirManager::becameDirty()
{ {
if (isParsing()) if (isParsing())
return; return;
Target *t = m_buildConfiguration->target()->project()->activeTarget(); if (!m_parameters.buildConfiguration || !m_parameters.buildConfiguration->isActive())
BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr;
if (bc != m_buildConfiguration)
return; return;
const CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit()); const CMakeTool *tool = m_parameters.cmakeTool;
if (!tool->isAutoRun()) if (!tool->isAutoRun())
return; return;
emit requestReparse(false); emit requestReparse(REPARSE_CHECK_CONFIGURATION);
}
void BuildDirManager::forceReparse()
{
forceReparseImpl(true);
}
void BuildDirManager::forceReparseWithoutCheckingForChanges()
{
forceReparseImpl(false);
}
void BuildDirManager::forceReparseImpl(bool checkForChanges)
{
QTC_ASSERT(!m_isHandlingError, return);
if (m_buildConfiguration->target()->activeBuildConfiguration() != m_buildConfiguration)
return;
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
QTC_ASSERT(tool, return);
m_reader.reset(); // Force reparse by forcing in a new reader
updateReaderType([this, checkForChanges]() { parseOnceReaderReady(true, checkForChanges); });
} }
void BuildDirManager::resetData() void BuildDirManager::resetData()
{ {
QTC_ASSERT(!m_isHandlingError, return);
if (m_reader) if (m_reader)
m_reader->resetData(); m_reader->resetData();
m_cmakeCache.clear();
m_reader.reset();
m_buildTargets.clear();
} }
bool BuildDirManager::persistCMakeState() bool BuildDirManager::persistCMakeState()
{ {
QTC_ASSERT(m_parameters.isValid(), return false);
if (!m_tempDir) if (!m_tempDir)
return false; return false;
const QString buildDir = m_buildConfiguration->buildDirectory().toString(); const Utils::FileName buildDir = m_parameters.buildDirectory;
QDir dir(buildDir); QDir dir(buildDir.toString());
dir.mkpath(buildDir); dir.mkpath(buildDir.toString());
m_tempDir.reset(nullptr); m_tempDir.reset(nullptr);
QTimer::singleShot(0, this, &BuildDirManager::parse); // make sure signals only happen afterwards! emit requestReparse(REPARSE_URGENT | REPARSE_FORCE_CONFIGURATION | REPARSE_CHECK_CONFIGURATION);
return true; return true;
} }
void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles) void BuildDirManager::parse(int reparseParameters)
{
QTC_ASSERT(m_parameters.isValid(), return);
QTC_ASSERT(m_reader, return);
QTC_ASSERT((reparseParameters & REPARSE_FAIL) == 0, return);
QTC_ASSERT((reparseParameters & REPARSE_IGNORE) == 0, return);
m_reader->stop();
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
if (reparseParameters & REPARSE_CHECK_CONFIGURATION) {
if (checkConfiguration())
reparseParameters |= REPARSE_FORCE_CONFIGURATION;
}
m_reader->parse(reparseParameters & REPARSE_FORCE_CONFIGURATION);
}
void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles) const
{ {
QTC_ASSERT(!m_isHandlingError, return); QTC_ASSERT(!m_isHandlingError, return);
QTC_ASSERT(m_reader, return); QTC_ASSERT(m_reader, return);
const Utils::FileName projectFile = m_buildConfiguration->target()->project()->projectFilePath();
m_reader->generateProjectTree(root, allFiles); m_reader->generateProjectTree(root, allFiles);
} }
@@ -300,17 +286,13 @@ void BuildDirManager::updateCodeModel(CppTools::RawProjectParts &rpps)
return m_reader->updateCodeModel(rpps); return m_reader->updateCodeModel(rpps);
} }
void BuildDirManager::parse()
{
updateReaderType([this]() { parseOnceReaderReady(false); });
}
void BuildDirManager::clearCache() void BuildDirManager::clearCache()
{ {
QTC_ASSERT(m_parameters.isValid(), return);
QTC_ASSERT(!m_isHandlingError, return); QTC_ASSERT(!m_isHandlingError, return);
auto cmakeCache = Utils::FileName(workDirectory()).appendPath(QLatin1String("CMakeCache.txt")); auto cmakeCache = workDirectory(m_parameters).appendPath("CMakeCache.txt");
auto cmakeFiles = Utils::FileName(workDirectory()).appendPath(QLatin1String("CMakeFiles")); auto cmakeFiles = workDirectory(m_parameters).appendPath("CMakeFiles");
const bool mustCleanUp = cmakeCache.exists() || cmakeFiles.exists(); const bool mustCleanUp = cmakeCache.exists() || cmakeFiles.exists();
if (!mustCleanUp) if (!mustCleanUp)
@@ -319,7 +301,7 @@ void BuildDirManager::clearCache()
Utils::FileUtils::removeRecursively(cmakeCache); Utils::FileUtils::removeRecursively(cmakeCache);
Utils::FileUtils::removeRecursively(cmakeFiles); Utils::FileUtils::removeRecursively(cmakeFiles);
forceReparse(); m_reader.reset();
} }
static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManager *bdm) static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManager *bdm)
@@ -334,44 +316,41 @@ static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManage
return target; return target;
} }
QList<CMakeBuildTarget> BuildDirManager::buildTargets() const QList<CMakeBuildTarget> BuildDirManager::takeBuildTargets() const
{ {
QTC_ASSERT(!m_isHandlingError, return {}); QList<CMakeBuildTarget> result = { utilityTarget(CMakeBuildStep::allTarget(), this),
utilityTarget(CMakeBuildStep::cleanTarget(), this),
utilityTarget(CMakeBuildStep::installTarget(), this),
utilityTarget(CMakeBuildStep::testTarget(), this) };
QTC_ASSERT(!m_isHandlingError, return result);
if (!m_reader) if (m_reader) {
return QList<CMakeBuildTarget>(); result.append(Utils::filtered(m_reader->takeBuildTargets(), [](const CMakeBuildTarget &bt) {
if (m_buildTargets.isEmpty()) {
m_buildTargets.append(utilityTarget(CMakeBuildStep::allTarget(), this));
m_buildTargets.append(utilityTarget(CMakeBuildStep::cleanTarget(), this));
m_buildTargets.append(utilityTarget(CMakeBuildStep::installTarget(), this));
m_buildTargets.append(utilityTarget(CMakeBuildStep::testTarget(), this));
m_buildTargets.append(Utils::filtered(m_reader->buildTargets(), [](const CMakeBuildTarget &bt) {
return bt.title != CMakeBuildStep::allTarget() return bt.title != CMakeBuildStep::allTarget()
&& bt.title != CMakeBuildStep::cleanTarget() && bt.title != CMakeBuildStep::cleanTarget()
&& bt.title != CMakeBuildStep::installTarget() && bt.title != CMakeBuildStep::installTarget()
&& bt.title != CMakeBuildStep::testTarget(); && bt.title != CMakeBuildStep::testTarget();
})); }));
} }
return m_buildTargets; return result;
} }
CMakeConfig BuildDirManager::parsedConfiguration() const CMakeConfig BuildDirManager::takeCMakeConfiguration() const
{ {
QTC_ASSERT(!m_isHandlingError, return {}); QTC_ASSERT(!m_isHandlingError, return {});
if (!m_reader) if (!m_reader)
return m_cmakeCache; return CMakeConfig();
if (m_cmakeCache.isEmpty())
m_cmakeCache = m_reader->takeParsedConfiguration();
for (auto &ci : m_cmakeCache) CMakeConfig result = m_reader->takeParsedConfiguration();
for (auto &ci : result)
ci.inCMakeCache = true; ci.inCMakeCache = true;
return m_cmakeCache; return result;
} }
CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile, QString *errorMessage) CMakeConfig BuildDirManager::parseCMakeConfiguration(const Utils::FileName &cacheFile,
QString *errorMessage)
{ {
if (!cacheFile.exists()) { if (!cacheFile.exists()) {
if (errorMessage) if (errorMessage)
@@ -384,25 +363,26 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
return result; return result;
} }
void BuildDirManager::checkConfiguration() bool BuildDirManager::checkConfiguration()
{ {
if (m_tempDir) // always throw away changes in the tmpdir! QTC_ASSERT(m_parameters.isValid(), return false);
return;
Kit *k = m_buildConfiguration->target()->kit(); if (m_tempDir) // always throw away changes in the tmpdir!
const CMakeConfig cache = parsedConfiguration(); return false;
const CMakeConfig cache = m_parameters.buildConfiguration->configurationFromCMake();
if (cache.isEmpty()) if (cache.isEmpty())
return; // No cache file yet. return false; // No cache file yet.
CMakeConfig newConfig; CMakeConfig newConfig;
QSet<QString> changedKeys; QSet<QString> changedKeys;
QSet<QString> removedKeys; QSet<QString> removedKeys;
foreach (const CMakeConfigItem &iBc, m_buildConfiguration->cmakeConfiguration()) { foreach (const CMakeConfigItem &iBc, m_parameters.configuration) {
const CMakeConfigItem &iCache const CMakeConfigItem &iCache
= Utils::findOrDefault(cache, [&iBc](const CMakeConfigItem &i) { return i.key == iBc.key; }); = Utils::findOrDefault(cache, [&iBc](const CMakeConfigItem &i) { return i.key == iBc.key; });
if (iCache.isNull()) { if (iCache.isNull()) {
removedKeys << QString::fromUtf8(iBc.key); removedKeys << QString::fromUtf8(iBc.key);
} else if (QString::fromUtf8(iCache.value) != iBc.expandedValue(k)) { } else if (QString::fromUtf8(iCache.value) != iBc.expandedValue(m_parameters.expander)) {
changedKeys << QString::fromUtf8(iBc.key); changedKeys << QString::fromUtf8(iBc.key);
newConfig.append(iCache); newConfig.append(iCache);
} else { } else {
@@ -435,22 +415,15 @@ void BuildDirManager::checkConfiguration()
box->setDefaultButton(defaultButton); box->setDefaultButton(defaultButton);
box->exec(); box->exec();
if (box->clickedButton() == applyButton) if (box->clickedButton() == applyButton) {
m_buildConfiguration->setCMakeConfiguration(newConfig); m_parameters.configuration = newConfig;
QSignalBlocker blocker(m_parameters.buildConfiguration);
m_parameters.buildConfiguration->setConfigurationForCMake(newConfig);
return false;
} else if (box->clickedButton() == defaultButton)
return true;
} }
} return false;
void BuildDirManager::maybeForceReparse()
{
if (m_isHandlingError)
return;
if (!m_reader || !m_reader->hasData()) {
emit requestReparse(true);
return;
}
updateReaderType([this]() { maybeForceReparseOnceReaderReady(); });
} }
} // namespace Internal } // namespace Internal

View File

@@ -25,9 +25,13 @@
#pragma once #pragma once
#include "builddirparameters.h"
#include "builddirreader.h" #include "builddirreader.h"
#include "cmakebuildtarget.h"
#include "cmakeconfigitem.h" #include "cmakeconfigitem.h"
#include <cpptools/cpprawprojectpart.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/temporarydirectory.h> #include <utils/temporarydirectory.h>
@@ -37,12 +41,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
namespace ProjectExplorer { namespace ProjectExplorer { class FileNode; }
class FileNode;
class IOutputParser;
class Kit;
class Task;
} // namespace ProjectExplorer
namespace CMakeProjectManager { namespace CMakeProjectManager {
@@ -50,6 +49,7 @@ class CMakeTool;
namespace Internal { namespace Internal {
class CMakeProjectNode;
class CMakeBuildConfiguration; class CMakeBuildConfiguration;
class BuildDirManager : public QObject class BuildDirManager : public QObject
@@ -57,61 +57,63 @@ class BuildDirManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
BuildDirManager(CMakeBuildConfiguration *bc); BuildDirManager();
~BuildDirManager() final; ~BuildDirManager() final;
bool isParsing() const; bool isParsing() const;
void setParametersAndRequestParse(const BuildDirParameters &parameters,
int newReaderReparseOptions, int existingReaderReparseOptions);
CMakeBuildConfiguration *buildConfiguration() const;
void clearCache(); void clearCache();
void forceReparse();
void forceReparseWithoutCheckingForChanges();
void maybeForceReparse(); // Only reparse if the configuration has changed...
void resetData(); void resetData();
bool persistCMakeState(); bool persistCMakeState();
void parse(int reparseParameters);
void generateProjectTree(CMakeProjectNode *root, void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles); const QList<const ProjectExplorer::FileNode *> &allFiles) const;
void updateCodeModel(CppTools::RawProjectParts &rpps); void updateCodeModel(CppTools::RawProjectParts &rpps);
QList<CMakeBuildTarget> buildTargets() const; QList<CMakeBuildTarget> takeBuildTargets() const;
CMakeConfig parsedConfiguration() const; CMakeConfig takeCMakeConfiguration() const;
static CMakeConfig parseConfiguration(const Utils::FileName &cacheFile, static CMakeConfig parseCMakeConfiguration(const Utils::FileName &cacheFile,
QString *errorMessage); QString *errorMessage);
CMakeBuildConfiguration *buildConfiguration() const { return m_buildConfiguration; } enum ReparseParameters { REPARSE_DEFAULT = 0, // use defaults
REPARSE_URGENT = 1, // Do not wait for more requests, start ASAP
REPARSE_FORCE_CONFIGURATION = 2, // Force configuration arguments to cmake
REPARSE_CHECK_CONFIGURATION = 4, // Check and warn if on-disk config and QtC config differ
REPARSE_IGNORE = 8, // Do not reparse:-)
REPARSE_FAIL = 16 // Do not reparse and raise a warning
};
signals: signals:
void requestReparse(bool urgent) const; void requestReparse(int reparseParameters) const;
void configurationStarted() const; void parsingStarted() const;
void dataAvailable() const; void dataAvailable() const;
void errorOccured(const QString &err) const; void errorOccured(const QString &err) const;
private: private:
void emitDataAvailable(); void emitDataAvailable();
void emitErrorOccured(const QString &message) const; void emitErrorOccured(const QString &message) const;
void checkConfiguration(); bool checkConfiguration();
const Utils::FileName workDirectory() const; Utils::FileName workDirectory(const BuildDirParameters &parameters) const;
void updateReaderType(std::function<void()> todo); void updateReaderType(const BuildDirParameters &p, std::function<void()> todo);
void updateReaderData();
void forceReparseImpl(bool checkForChanges); bool hasConfigChanged();
void parseOnceReaderReady(bool force, bool checkForChanges = true);
void maybeForceReparseOnceReaderReady();
void parse();
void becameDirty(); void becameDirty();
CMakeBuildConfiguration *m_buildConfiguration = nullptr; BuildDirParameters m_parameters;
mutable std::unique_ptr<Utils::TemporaryDirectory> m_tempDir = nullptr; mutable std::unique_ptr<Utils::TemporaryDirectory> m_tempDir = nullptr;
mutable CMakeConfig m_cmakeCache; mutable std::unique_ptr<BuildDirReader> m_reader;
std::unique_ptr<BuildDirReader> m_reader;
mutable QList<CMakeBuildTarget> m_buildTargets;
mutable bool m_isHandlingError = false; mutable bool m_isHandlingError = false;
}; };

View File

@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "builddirparameters.h"
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
using namespace ProjectExplorer;
namespace CMakeProjectManager {
namespace Internal {
BuildDirParameters::BuildDirParameters() = default;
BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
{
buildConfiguration = bc;
const Kit *k = bc->target()->kit();
projectName = bc->target()->project()->displayName();
sourceDirectory = bc->target()->project()->projectDirectory();
buildDirectory = bc->buildDirectory();
environment = bc->environment();
cmakeTool = CMakeKitInformation::cmakeTool(k);
auto tc = ToolChainKitInformation::toolChain(k, Constants::CXX_LANGUAGE_ID);
if (tc)
cxxToolChainId = tc->id();
tc = ToolChainKitInformation::toolChain(k, Constants::C_LANGUAGE_ID);
if (tc)
cToolChainId = tc->id();
sysRoot = SysRootKitInformation::sysRoot(k);
expander = k->macroExpander();
configuration = bc->configurationForCMake();
generator = CMakeGeneratorKitInformation::generator(k);
extraGenerator = CMakeGeneratorKitInformation::extraGenerator(k);
platform = CMakeGeneratorKitInformation::platform(k);
toolset = CMakeGeneratorKitInformation::toolset(k);
generatorArguments = CMakeGeneratorKitInformation::generatorArguments(k);
}
bool BuildDirParameters::isValid() const { return buildConfiguration && cmakeTool; }
BuildDirParameters::BuildDirParameters(const BuildDirParameters &) = default;
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "cmakeconfigitem.h"
#include "cmaketool.h"
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/macroexpander.h>
#include <QString>
namespace CMakeProjectManager {
namespace Internal {
class CMakeBuildConfiguration;
class BuildDirParameters {
public:
BuildDirParameters();
BuildDirParameters(CMakeBuildConfiguration *bc);
BuildDirParameters(const BuildDirParameters &other);
bool isValid() const;
CMakeBuildConfiguration *buildConfiguration = nullptr;
QString projectName;
Utils::FileName sourceDirectory;
Utils::FileName buildDirectory;
Utils::Environment environment;
CMakeTool *cmakeTool = nullptr;
QByteArray cxxToolChainId;
QByteArray cToolChainId;
Utils::FileName sysRoot;
Utils::MacroExpander *expander = nullptr;
CMakeConfig configuration;
QString generator;
QString extraGenerator;
QString platform;
QString toolset;
QStringList generatorArguments;
};
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -25,14 +25,10 @@
#include "builddirreader.h" #include "builddirreader.h"
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
#include "servermodereader.h" #include "servermodereader.h"
#include "tealeafreader.h" #include "tealeafreader.h"
#include <projectexplorer/kitinformation.h> #include <utils/qtcassert.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -43,57 +39,15 @@ namespace Internal {
// BuildDirReader: // BuildDirReader:
// -------------------------------------------------------------------- // --------------------------------------------------------------------
BuildDirReader::Parameters::Parameters() = default; BuildDirReader *BuildDirReader::createReader(const BuildDirParameters &p)
BuildDirReader::Parameters::Parameters(const CMakeBuildConfiguration *bc)
{ {
const ProjectExplorer::Kit *k = bc->target()->kit(); QTC_ASSERT(p.isValid() && p.cmakeTool, return nullptr);
if (p.cmakeTool->hasServerMode())
projectName = bc->target()->project()->displayName();
sourceDirectory = bc->target()->project()->projectDirectory();
buildDirectory = bc->buildDirectory();
environment = bc->environment();
CMakeTool *cmake = CMakeKitInformation::cmakeTool(k);
cmakeVersion = cmake->version();
cmakeHasServerMode = cmake->hasServerMode();
cmakeExecutable = cmake->cmakeExecutable();
pathMapper = cmake->pathMapper();
isAutorun = cmake->isAutoRun();
auto tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
if (tc)
cxxToolChainId = tc->id();
tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID);
if (tc)
cToolChainId = tc->id();
sysRoot = ProjectExplorer::SysRootKitInformation::sysRoot(k);
expander = k->macroExpander();
configuration = bc->cmakeConfiguration();
generator = CMakeGeneratorKitInformation::generator(k);
extraGenerator = CMakeGeneratorKitInformation::extraGenerator(k);
platform = CMakeGeneratorKitInformation::platform(k);
toolset = CMakeGeneratorKitInformation::toolset(k);
generatorArguments = CMakeGeneratorKitInformation::generatorArguments(k);
}
BuildDirReader::Parameters::Parameters(const BuildDirReader::Parameters &) = default;
BuildDirReader *BuildDirReader::createReader(const BuildDirReader::Parameters &p)
{
if (p.cmakeHasServerMode)
return new ServerModeReader; return new ServerModeReader;
return new TeaLeafReader; return new TeaLeafReader;
} }
void BuildDirReader::setParameters(const BuildDirReader::Parameters &p) void BuildDirReader::setParameters(const BuildDirParameters &p)
{ {
m_parameters = p; m_parameters = p;
} }

View File

@@ -25,8 +25,9 @@
#pragma once #pragma once
#include "builddirparameters.h"
#include "cmakebuildtarget.h"
#include "cmakeconfigitem.h" #include "cmakeconfigitem.h"
#include "cmakeproject.h"
#include "cmaketool.h" #include "cmaketool.h"
#include <cpptools/cpprawprojectpart.h> #include <cpptools/cpprawprojectpart.h>
@@ -38,6 +39,8 @@
#include <QFutureInterface> #include <QFutureInterface>
#include <QObject> #include <QObject>
namespace ProjectExplorer { class FileNode; }
namespace CMakeProjectManager { namespace CMakeProjectManager {
namespace Internal { namespace Internal {
@@ -49,52 +52,19 @@ class BuildDirReader : public QObject
Q_OBJECT Q_OBJECT
public: public:
struct Parameters { static BuildDirReader *createReader(const BuildDirParameters &p);
Parameters(); virtual void setParameters(const BuildDirParameters &p);
Parameters(const CMakeBuildConfiguration *bc);
Parameters(const Parameters &other);
QString projectName; virtual bool isCompatible(const BuildDirParameters &p) = 0;
Utils::FileName sourceDirectory;
Utils::FileName buildDirectory;
Utils::Environment environment;
Utils::FileName cmakeExecutable;
CMakeTool::Version cmakeVersion;
bool cmakeHasServerMode = false;
CMakeTool::PathMapper pathMapper;
QByteArray cxxToolChainId;
QByteArray cToolChainId;
Utils::FileName sysRoot;
Utils::MacroExpander *expander = nullptr;
CMakeConfig configuration;
QString generator;
QString extraGenerator;
QString platform;
QString toolset;
QStringList generatorArguments;
bool isAutorun = false;
};
static BuildDirReader *createReader(const BuildDirReader::Parameters &p);
virtual void setParameters(const Parameters &p);
virtual bool isCompatible(const Parameters &p) = 0;
virtual void resetData() = 0; virtual void resetData() = 0;
virtual void parse(bool force) = 0; virtual void parse(bool forceConfiguration) = 0;
virtual void stop() = 0; virtual void stop() = 0;
virtual bool isReady() const { return true; } virtual bool isReady() const { return true; }
virtual bool isParsing() const = 0; virtual bool isParsing() const = 0;
virtual bool hasData() const = 0;
virtual QList<CMakeBuildTarget> takeBuildTargets() = 0;
virtual CMakeConfig takeParsedConfiguration() = 0; virtual CMakeConfig takeParsedConfiguration() = 0;
virtual QList<CMakeBuildTarget> buildTargets() const = 0;
virtual void generateProjectTree(CMakeProjectNode *root, virtual void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) = 0; const QList<const ProjectExplorer::FileNode *> &allFiles) = 0;
virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0; virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0;
@@ -107,7 +77,7 @@ signals:
void errorOccured(const QString &message) const; void errorOccured(const QString &message) const;
protected: protected:
Parameters m_parameters; BuildDirParameters m_parameters;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -64,17 +64,11 @@ const char INITIAL_ARGUMENTS[] = "CMakeProjectManager.CMakeBuildConfiguration.In
const char CONFIGURATION_KEY[] = "CMake.Configuration"; const char CONFIGURATION_KEY[] = "CMake.Configuration";
CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent) : CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent) :
BuildConfiguration(parent, Core::Id(Constants::CMAKE_BC_ID)), BuildConfiguration(parent, Core::Id(Constants::CMAKE_BC_ID))
m_buildDirManager(new BuildDirManager(this))
{ {
ctor(); ctor();
} }
CMakeBuildConfiguration::~CMakeBuildConfiguration()
{
m_buildDirManager->deleteLater(); // Do not block while waiting for cmake...
}
bool CMakeBuildConfiguration::isEnabled() const bool CMakeBuildConfiguration::isEnabled() const
{ {
return m_error.isEmpty() && !isParsing(); return m_error.isEmpty() && !isParsing();
@@ -88,8 +82,7 @@ QString CMakeBuildConfiguration::disabledReason() const
CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent, CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent,
CMakeBuildConfiguration *source) : CMakeBuildConfiguration *source) :
BuildConfiguration(parent, source), BuildConfiguration(parent, source),
m_configuration(source->m_configuration), m_configurationForCMake(source->m_configurationForCMake)
m_buildDirManager(new BuildDirManager(this))
{ {
ctor(); ctor();
cloneSteps(source); cloneSteps(source);
@@ -99,7 +92,7 @@ QVariantMap CMakeBuildConfiguration::toMap() const
{ {
QVariantMap map(ProjectExplorer::BuildConfiguration::toMap()); QVariantMap map(ProjectExplorer::BuildConfiguration::toMap());
const QStringList config const QStringList config
= Utils::transform(m_configuration, [](const CMakeConfigItem &i) { return i.toString(); }); = Utils::transform(m_configurationForCMake, [](const CMakeConfigItem &i) { return i.toString(); });
map.insert(QLatin1String(CONFIGURATION_KEY), config); map.insert(QLatin1String(CONFIGURATION_KEY), config);
return map; return map;
} }
@@ -130,110 +123,28 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
} }
// End Legacy // End Legacy
setCMakeConfiguration(legacyConf + conf); setConfigurationForCMake(legacyConf + conf);
return true; return true;
} }
void CMakeBuildConfiguration::ctor() void CMakeBuildConfiguration::ctor()
{ {
auto project = static_cast<CMakeProject *>(target()->project()); auto p = static_cast<CMakeProject *>(project());
setBuildDirectory(shadowBuildDirectory(project->projectFilePath(), setBuildDirectory(shadowBuildDirectory(p->projectFilePath(),
target()->kit(), target()->kit(),
displayName(), BuildConfiguration::Unknown)); displayName(), BuildConfiguration::Unknown));
connect(p, &Project::parsingFinished, this, &BuildConfiguration::enabledChanged);
connect(m_buildDirManager.get(), &BuildDirManager::requestReparse,
this, [this](bool urgent) { emit requestReparse(this, urgent); });
connect(m_buildDirManager.get(), &BuildDirManager::dataAvailable,
this, [this, project]() {
clearError();
project->handleParsingSuccess(this);
});
connect(m_buildDirManager.get(), &BuildDirManager::errorOccured,
this, [this, project](const QString &msg) {
setError(msg);
project->handleParsingError(this);
});
connect(m_buildDirManager.get(), &BuildDirManager::configurationStarted,
this, [this]() {
clearError(ForceEnabledChanged::True);
emit parsingStarted(this);
});
connect(this, &CMakeBuildConfiguration::environmentChanged,
m_buildDirManager.get(), &BuildDirManager::forceReparse);
connect(this, &CMakeBuildConfiguration::buildDirectoryChanged,
m_buildDirManager.get(), &BuildDirManager::forceReparse);
}
void CMakeBuildConfiguration::maybeForceReparse()
{
clearError();
m_buildDirManager->maybeForceReparse();
} }
bool CMakeBuildConfiguration::isParsing() const bool CMakeBuildConfiguration::isParsing() const
{ {
return m_buildDirManager && m_buildDirManager->isParsing(); return project()->isParsing() && isActive();
}
void CMakeBuildConfiguration::resetData()
{
clearError();
m_buildDirManager->resetData();
}
bool CMakeBuildConfiguration::persistCMakeState()
{
return m_buildDirManager->persistCMakeState();
}
bool CMakeBuildConfiguration::updateCMakeStateBeforeBuild()
{
return static_cast<CMakeProject *>(project())->mustUpdateCMakeStateBeforeBuild();
}
void CMakeBuildConfiguration::runCMake()
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return;
clearError();
m_buildDirManager->forceReparse();
}
void CMakeBuildConfiguration::clearCache()
{
if (m_buildDirManager)
m_buildDirManager->clearCache();
} }
QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const
{ {
if (!m_buildDirManager || m_buildDirManager->isParsing()) return m_buildTargets;
return QList<CMakeBuildTarget>();
return m_buildDirManager->buildTargets();
}
CMakeProjectNode *
CMakeBuildConfiguration::generateProjectTree(const QList<const FileNode*> &allFiles) const
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return nullptr;
auto root = new CMakeProjectNode(target()->project()->projectDirectory());
m_buildDirManager->generateProjectTree(root, allFiles);
if (root->isEmpty()) {
delete root;
return nullptr;
}
return root;
}
void CMakeBuildConfiguration::updateCodeModel(CppTools::RawProjectParts &rpps)
{
m_buildDirManager->updateCodeModel(rpps);
} }
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath, FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
@@ -273,50 +184,23 @@ void CMakeBuildConfiguration::buildTarget(const QString &buildTarget)
cmBs->setBuildTarget(originalBuildTarget); cmBs->setBuildTarget(originalBuildTarget);
} }
QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration() const CMakeConfig CMakeBuildConfiguration::configurationFromCMake() const
{ {
if (!m_buildDirManager || m_buildDirManager->isParsing()) return m_configurationFromCMake;
return QList<ConfigModel::DataItem>();
return Utils::transform(m_buildDirManager->parsedConfiguration(),
[](const CMakeConfigItem &i) {
ConfigModel::DataItem j;
j.key = QString::fromUtf8(i.key);
j.value = QString::fromUtf8(i.value);
j.description = QString::fromUtf8(i.documentation);
j.values = i.values;
j.inCMakeCache = i.inCMakeCache;
j.isAdvanced = i.isAdvanced;
j.isHidden = i.type == CMakeConfigItem::INTERNAL || i.type == CMakeConfigItem::STATIC;
switch (i.type) {
case CMakeConfigItem::FILEPATH:
j.type = ConfigModel::DataItem::FILE;
break;
case CMakeConfigItem::PATH:
j.type = ConfigModel::DataItem::DIRECTORY;
break;
case CMakeConfigItem::BOOL:
j.type = ConfigModel::DataItem::BOOLEAN;
break;
case CMakeConfigItem::STRING:
j.type = ConfigModel::DataItem::STRING;
break;
default:
j.type = ConfigModel::DataItem::UNKNOWN;
break;
}
return j;
});
} }
void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items) void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &config)
{ {
if (!m_buildDirManager || m_buildDirManager->isParsing()) m_configurationFromCMake = config;
return; }
void CMakeBuildConfiguration::setBuildTargets(const QList<CMakeBuildTarget> &targets)
{
m_buildTargets = targets;
}
void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::DataItem> &items)
{
const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) { const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) {
CMakeConfigItem ni; CMakeConfigItem ni;
ni.key = i.key.toUtf8(); ni.key = i.key.toUtf8();
@@ -346,10 +230,8 @@ void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigMod
return ni; return ni;
}); });
const CMakeConfig config = cmakeConfiguration() + newConfig; const CMakeConfig config = configurationForCMake() + newConfig;
setCMakeConfiguration(config); setConfigurationForCMake(config);
m_buildDirManager->forceReparseWithoutCheckingForChanges();
} }
void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec) void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec)
@@ -383,14 +265,14 @@ static CMakeConfig removeDuplicates(const CMakeConfig &config)
return result; return result;
} }
void CMakeBuildConfiguration::setCMakeConfiguration(const CMakeConfig &config) void CMakeBuildConfiguration::setConfigurationForCMake(const CMakeConfig &config)
{ {
m_configuration = removeDuplicates(config); m_configurationForCMake = removeDuplicates(config);
const Kit *k = target()->kit(); const Kit *k = target()->kit();
CMakeConfig kitConfig = CMakeConfigurationKitInformation::configuration(k); CMakeConfig kitConfig = CMakeConfigurationKitInformation::configuration(k);
bool hasKitOverride = false; bool hasKitOverride = false;
foreach (const CMakeConfigItem &i, m_configuration) { foreach (const CMakeConfigItem &i, m_configurationForCMake) {
const QString b = CMakeConfigItem::expandedValueOf(k, i.key, kitConfig); const QString b = CMakeConfigItem::expandedValueOf(k, i.key, kitConfig);
if (!b.isNull() && i.expandedValue(k) != b) { if (!b.isNull() && i.expandedValue(k) != b) {
hasKitOverride = true; hasKitOverride = true;
@@ -402,11 +284,13 @@ void CMakeBuildConfiguration::setCMakeConfiguration(const CMakeConfig &config)
setWarning(tr("CMake configuration set by the kit was overridden in the project.")); setWarning(tr("CMake configuration set by the kit was overridden in the project."));
else else
setWarning(QString()); setWarning(QString());
emit configurationForCMakeChanged();
} }
CMakeConfig CMakeBuildConfiguration::cmakeConfiguration() const CMakeConfig CMakeBuildConfiguration::configurationForCMake() const
{ {
return removeDuplicates(CMakeConfigurationKitInformation::configuration(target()->kit()) + m_configuration); return removeDuplicates(CMakeConfigurationKitInformation::configuration(target()->kit()) + m_configurationForCMake);
} }
void CMakeBuildConfiguration::setError(const QString &message) void CMakeBuildConfiguration::setError(const QString &message)
@@ -556,7 +440,7 @@ ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(Proj
cleanSteps->insertStep(0, cleanStep); cleanSteps->insertStep(0, cleanStep);
bc->setBuildDirectory(copy.buildDirectory); bc->setBuildDirectory(copy.buildDirectory);
bc->setCMakeConfiguration(copy.configuration); bc->setConfigurationForCMake(copy.configuration);
return bc; return bc;
} }

View File

@@ -52,11 +52,9 @@ class CMakeProjectNode;
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
{ {
Q_OBJECT Q_OBJECT
friend class CMakeBuildConfigurationFactory;
public: public:
CMakeBuildConfiguration(ProjectExplorer::Target *parent); CMakeBuildConfiguration(ProjectExplorer::Target *parent);
~CMakeBuildConfiguration();
bool isEnabled() const override; bool isEnabled() const override;
QString disabledReason() const override; QString disabledReason() const override;
@@ -69,25 +67,13 @@ public:
void emitBuildTypeChanged(); void emitBuildTypeChanged();
void setCMakeConfiguration(const CMakeConfig &config); CMakeConfig configurationForCMake() const;
bool hasCMakeConfiguration() const; CMakeConfig configurationFromCMake() const;
CMakeConfig cmakeConfiguration() const;
QString error() const; QString error() const;
QString warning() const; QString warning() const;
bool isParsing() const;
void maybeForceReparse();
void resetData();
bool persistCMakeState();
bool updateCMakeStateBeforeBuild();
void runCMake();
void clearCache();
QList<CMakeBuildTarget> buildTargets() const; QList<CMakeBuildTarget> buildTargets() const;
CMakeProjectManager::Internal::CMakeProjectNode *generateProjectTree(const QList<const ProjectExplorer::FileNode *> &allFiles) const;
void updateCodeModel(CppTools::RawProjectParts &rpps);
static Utils::FileName static Utils::FileName
shadowBuildDirectory(const Utils::FileName &projectFilePath, const ProjectExplorer::Kit *k, shadowBuildDirectory(const Utils::FileName &projectFilePath, const ProjectExplorer::Kit *k,
@@ -97,12 +83,11 @@ public:
void buildTarget(const QString &buildTarget); void buildTarget(const QString &buildTarget);
signals: signals:
void requestReparse(CMakeBuildConfiguration *, bool isUrgent);
void parsingStarted(CMakeBuildConfiguration *);
void errorOccured(const QString &message); void errorOccured(const QString &message);
void warningOccured(const QString &message); void warningOccured(const QString &message);
void configurationForCMakeChanged();
protected: protected:
CMakeBuildConfiguration(ProjectExplorer::Target *parent, CMakeBuildConfiguration *source); CMakeBuildConfiguration(ProjectExplorer::Target *parent, CMakeBuildConfiguration *source);
bool fromMap(const QVariantMap &map) override; bool fromMap(const QVariantMap &map) override;
@@ -110,22 +95,30 @@ protected:
private: private:
void ctor(); void ctor();
bool isParsing() const;
enum ForceEnabledChanged : quint8 { False, True }; enum ForceEnabledChanged : quint8 { False, True };
void clearError(ForceEnabledChanged fec = ForceEnabledChanged::False); void clearError(ForceEnabledChanged fec = ForceEnabledChanged::False);
QList<ConfigModel::DataItem> completeCMakeConfiguration() const;
void setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items); void setBuildTargets(const QList<CMakeBuildTarget> &targets);
void setConfigurationFromCMake(const CMakeConfig &config);
void setConfigurationForCMake(const QList<ConfigModel::DataItem> &items);
void setConfigurationForCMake(const CMakeConfig &config);
void setError(const QString &message); void setError(const QString &message);
void setWarning(const QString &message); void setWarning(const QString &message);
CMakeConfig m_configuration; CMakeConfig m_configurationForCMake;
QString m_error; QString m_error;
QString m_warning; QString m_warning;
std::unique_ptr<BuildDirManager> m_buildDirManager; CMakeConfig m_configurationFromCMake;
QList<CMakeBuildTarget> m_buildTargets;
friend class CMakeBuildConfigurationFactory;
friend class CMakeBuildSettingsWidget; friend class CMakeBuildSettingsWidget;
friend class CMakeProjectManager::CMakeProject; friend class CMakeProjectManager::CMakeProject;
friend class BuildDirManager;
}; };
class CMakeProjectImporter; class CMakeProjectImporter;

View File

@@ -52,7 +52,7 @@ public:
QTC_ASSERT(bc->target()->project(), return); QTC_ASSERT(bc->target()->project(), return);
sourceDirectory = bc->target()->project()->projectDirectory().toString(); sourceDirectory = bc->target()->project()->projectDirectory().toString();
configuration = bc->cmakeConfiguration(); configuration = bc->configurationForCMake();
} }
bool operator==(const BuildInfo &o) const final bool operator==(const BuildInfo &o) const final

View File

@@ -227,13 +227,13 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
if (m_buildConfiguration->isParsing()) if (m_buildConfiguration->isParsing())
m_showProgressTimer.start(); m_showProgressTimer.start();
else { else {
m_configModel->setConfiguration(m_buildConfiguration->completeCMakeConfiguration()); m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
m_configView->expandAll(); m_configView->expandAll();
} }
connect(m_buildConfiguration->target()->project(), &ProjectExplorer::Project::parsingFinished, connect(project, &ProjectExplorer::Project::parsingFinished,
this, [this, buildDirChooser, stretcher]() { this, [this, buildDirChooser, stretcher]() {
m_configModel->setConfiguration(m_buildConfiguration->completeCMakeConfiguration()); m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
m_configView->expandAll(); m_configView->expandAll();
stretcher->stretch(); stretcher->stretch();
updateButtonState(); updateButtonState();
@@ -264,7 +264,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(m_resetButton, &QPushButton::clicked, m_configModel, &ConfigModel::resetAllChanges); connect(m_resetButton, &QPushButton::clicked, m_configModel, &ConfigModel::resetAllChanges);
connect(m_reconfigureButton, &QPushButton::clicked, this, [this]() { connect(m_reconfigureButton, &QPushButton::clicked, this, [this]() {
m_buildConfiguration->setCurrentCMakeConfiguration(m_configModel->configurationChanges()); m_buildConfiguration->setConfigurationForCMake(m_configModel->configurationChanges());
}); });
connect(m_editButton, &QPushButton::clicked, this, [this]() { connect(m_editButton, &QPushButton::clicked, this, [this]() {
QModelIndex idx = m_configView->currentIndex(); QModelIndex idx = m_configView->currentIndex();

View File

@@ -269,10 +269,11 @@ void CMakeBuildStep::run(QFutureInterface<bool> &fi)
QTC_ASSERT(bc, return); QTC_ASSERT(bc, return);
bool mustDelay = false; bool mustDelay = false;
if (bc->persistCMakeState()) { auto p = static_cast<CMakeProject *>(bc->project());
if (p->persistCMakeState()) {
emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage); emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage);
mustDelay = true; mustDelay = true;
} else if (bc->updateCMakeStateBeforeBuild()) { } else if (p->mustUpdateCMakeStateBeforeBuild()) {
emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage); emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage);
mustDelay = true; mustDelay = true;
} else { } else {

View File

@@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cmakebuildtarget.h"
using namespace Utils;
namespace CMakeProjectManager {
void CMakeBuildTarget::clear()
{
executable.clear();
makeCommand.clear();
workingDirectory.clear();
sourceDirectory.clear();
title.clear();
targetType = UtilityType;
includeFiles.clear();
compilerOptions.clear();
macros.clear();
files.clear();
}
} // namespace CMakeProjectManager

View File

@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "cmake_global.h"
#include <projectexplorer/projectmacro.h>
#include <utils/fileutils.h>
#include <QStringList>
namespace CMakeProjectManager {
enum TargetType {
ExecutableType = 0,
StaticLibraryType = 2,
DynamicLibraryType = 3,
UtilityType = 64
};
class CMAKE_EXPORT CMakeBuildTarget
{
public:
QString title;
Utils::FileName executable; // TODO: rename to output?
TargetType targetType = UtilityType;
Utils::FileName workingDirectory;
Utils::FileName sourceDirectory;
Utils::FileName makeCommand;
// code model
QList<Utils::FileName> includeFiles;
QStringList compilerOptions;
ProjectExplorer::Macros macros;
QList<Utils::FileName> files;
void clear();
};
} // namespace CMakeProjectManager

View File

@@ -42,6 +42,7 @@
#include <projectexplorer/deploymentdata.h> #include <projectexplorer/deploymentdata.h>
#include <projectexplorer/headerpath.h> #include <projectexplorer/headerpath.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h> #include <projectexplorer/toolchain.h>
@@ -66,6 +67,11 @@ namespace CMakeProjectManager {
using namespace Internal; using namespace Internal;
static CMakeBuildConfiguration *activeBc(const CMakeProject *p)
{
return qobject_cast<CMakeBuildConfiguration *>(p->activeTarget() ? p->activeTarget()->activeBuildConfiguration() : nullptr);
}
// QtCreator CMake Generator wishlist: // QtCreator CMake Generator wishlist:
// Which make targets we need to build to get all executables // Which make targets we need to build to get all executables
// What is the actual compiler executable // What is the actual compiler executable
@@ -77,27 +83,129 @@ using namespace Internal;
CMakeProject::CMakeProject(const FileName &fileName) : Project(Constants::CMAKEMIMETYPE, fileName), CMakeProject::CMakeProject(const FileName &fileName) : Project(Constants::CMAKEMIMETYPE, fileName),
m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)) m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this))
{ {
m_delayedParsingTimer.setSingleShot(true);
connect(&m_delayedParsingTimer, &QTimer::timeout,
this, [this]() { startParsingProject(PARSE); });
setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID); setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT)); setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(projectDirectory().fileName()); setDisplayName(projectDirectory().fileName());
connect(this, &Project::activeProjectConfigurationChanged, // Timer:
this, &CMakeProject::handleActiveProjectConfigurationChanged); m_delayedParsingTimer.setSingleShot(true);
subscribeSignal(&CMakeBuildConfiguration::requestReparse, connect(&m_delayedParsingTimer, &QTimer::timeout,
this, [this](CMakeBuildConfiguration *bc, bool isUrgent) { this, [this]() { startParsing(m_delayedParsingParameters); });
if (bc->isActive()) {
m_delayedParsingTimer.setInterval(isUrgent ? 0 : 1000); // BuildDirManager:
m_delayedParsingTimer.start(); connect(&m_buildDirManager, &BuildDirManager::requestReparse,
this, &CMakeProject::handleReparseRequest);
connect(&m_buildDirManager, &BuildDirManager::dataAvailable,
this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
if (bc && bc == m_buildDirManager.buildConfiguration()) {
bc->clearError();
handleParsingSuccess(bc);
}
});
connect(&m_buildDirManager, &BuildDirManager::errorOccured,
this, [this](const QString &msg) {
CMakeBuildConfiguration *bc = activeBc(this);
if (bc && bc == m_buildDirManager.buildConfiguration()) {
bc->setError(msg);
handleParsingError(bc);
}
});
connect(&m_buildDirManager, &BuildDirManager::parsingStarted,
this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
if (bc && bc == m_buildDirManager.buildConfiguration())
bc->clearError(CMakeBuildConfiguration::ForceEnabledChanged::True);
});
// Kit changed:
connect(KitManager::instance(), &KitManager::kitUpdated,
this, [this](Kit *k) {
CMakeBuildConfiguration *bc = activeBc(this);
if (!bc || k != bc->target()->kit())
return; // not for us...
// Build configuration has not changed, but Kit settings might have:
// reparse and check the configuration, independent of whether the reader has changed
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(bc),
BuildDirManager::REPARSE_CHECK_CONFIGURATION,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
});
// Target switched:
connect(this, &Project::activeTargetChanged, this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
// Target has switched, so the kit has changed, too.
// * run cmake with configuration arguments if the reader needs to be switched
// * run cmake without configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(bc),
BuildDirManager::REPARSE_CHECK_CONFIGURATION,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
});
// BuildConfiguration switched:
subscribeSignal(&Target::activeBuildConfigurationChanged, this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
// Build configuration has switched:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake without configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(bc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
});
// BuildConfiguration changed:
subscribeSignal(&CMakeBuildConfiguration::environmentChanged, this, [this]() {
auto senderBc = qobject_cast<CMakeBuildConfiguration *>(sender());
if (senderBc && senderBc->isActive()) {
// The environment on our BC has changed:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake without configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(senderBc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
}
});
subscribeSignal(&CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() {
auto senderBc = qobject_cast<CMakeBuildConfiguration *>(sender());
if (senderBc && senderBc->isActive() && senderBc == m_buildDirManager.buildConfiguration()) {
// The build directory of our BC has changed:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake without configuration arguments if the reader stays
// If no configuration exists, then the arguments will get added automatically by
// the reader.
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(senderBc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
}
});
subscribeSignal(&CMakeBuildConfiguration::configurationForCMakeChanged, this, [this]() {
auto senderBc = qobject_cast<CMakeBuildConfiguration *>(sender());
if (senderBc && senderBc->isActive() && senderBc == m_buildDirManager.buildConfiguration()) {
// The CMake configuration has changed on our BC:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake with configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(senderBc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_FORCE_CONFIGURATION);
} }
}); });
// TreeScanner:
connect(&m_treeScanner, &TreeScanner::finished, this, &CMakeProject::handleTreeScanningFinished); connect(&m_treeScanner, &TreeScanner::finished, this, &CMakeProject::handleTreeScanningFinished);
m_treeScanner.setFilter([this](const Utils::MimeType &mimeType, const Utils::FileName &fn) { m_treeScanner.setFilter([this](const Utils::MimeType &mimeType, const Utils::FileName &fn) {
@@ -148,15 +256,19 @@ CMakeProject::~CMakeProject()
void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc) void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
{ {
Target *const t = activeTarget(); const CMakeBuildConfiguration *aBc = activeBc(this);
QTC_ASSERT(bc, return); QTC_ASSERT(bc, return);
QTC_ASSERT(bc == (t ? t->activeBuildConfiguration() : nullptr), return); QTC_ASSERT(bc == aBc, return);
QTC_ASSERT(m_treeScanner.isFinished() && !bc->isParsing(), return); QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return);
Target *t = bc->target();
Kit *k = t->kit(); Kit *k = t->kit();
auto newRoot = bc->generateProjectTree(m_allFiles); bc->setBuildTargets(m_buildDirManager.takeBuildTargets());
bc->setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration());
auto newRoot = generateProjectTree(m_allFiles);
if (newRoot) { if (newRoot) {
setDisplayName(newRoot->displayName()); setDisplayName(newRoot->displayName());
setRootProjectNode(newRoot); setRootProjectNode(newRoot);
@@ -184,7 +296,7 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
} }
CppTools::RawProjectParts rpps; CppTools::RawProjectParts rpps;
bc->updateCodeModel(rpps); m_buildDirManager.updateCodeModel(rpps);
for (CppTools::RawProjectPart &rpp : rpps) { for (CppTools::RawProjectPart &rpp : rpps) {
// TODO: Set the Qt version only if target actually depends on Qt. // TODO: Set the Qt version only if target actually depends on Qt.
@@ -197,6 +309,8 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
updateQmlJSCodeModel(); updateQmlJSCodeModel();
m_buildDirManager.resetData();
emit fileListChanged(); emit fileListChanged();
emit bc->emitBuildTypeChanged(); emit bc->emitBuildTypeChanged();
@@ -220,10 +334,10 @@ void CMakeProject::updateQmlJSCodeModel()
if (!bc) if (!bc)
return; return;
const QList<ConfigModel::DataItem> &cm = bc->completeCMakeConfiguration(); const CMakeConfig &cm = bc->configurationFromCMake();
foreach (const ConfigModel::DataItem &di, cm) { foreach (const CMakeConfigItem &di, cm) {
if (di.key.contains(QStringLiteral("QML_IMPORT_PATH"))) { if (di.key.contains("QML_IMPORT_PATH")) {
cmakeImports = di.value; cmakeImports = QString::fromUtf8(di.value);
break; break;
} }
} }
@@ -234,6 +348,16 @@ void CMakeProject::updateQmlJSCodeModel()
modelManager->updateProjectInfo(projectInfo, this); modelManager->updateProjectInfo(projectInfo, this);
} }
CMakeProjectNode *CMakeProject::generateProjectTree(const QList<const FileNode *> &allFiles) const
{
if (m_buildDirManager.isParsing())
return nullptr;
auto root = std::make_unique<CMakeProjectNode>(projectDirectory());
m_buildDirManager.generateProjectTree(root.get(), allFiles);
return root ? root.release() : nullptr;
}
bool CMakeProject::needsConfiguration() const bool CMakeProject::needsConfiguration() const
{ {
return targets().isEmpty(); return targets().isEmpty();
@@ -264,53 +388,28 @@ void CMakeProject::runCMake()
if (isParsing()) if (isParsing())
return; return;
startParsingProject(PARSE); CMakeBuildConfiguration *bc = activeBc(this);
if (bc) {
BuildDirParameters parameters(bc);
m_buildDirManager.setParametersAndRequestParse(parameters,
BuildDirManager::REPARSE_CHECK_CONFIGURATION,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
}
} }
void CMakeProject::runCMakeAndScanProjectTree() void CMakeProject::runCMakeAndScanProjectTree()
{ {
if (isParsing()) if (!m_treeScanner.isFinished())
return; return;
startParsingProject(static_cast<DataCollectionAction>(PARSE | SCAN)); m_waitingForScan = true;
} runCMake();
void CMakeProject::startParsingProject(const CMakeProject::DataCollectionAction action)
{
const bool runParse = action & PARSE;
const bool runScan = action & SCAN;
CMakeBuildConfiguration *bc = activeTarget()
? qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration())
: nullptr;
if (!bc)
return;
if (!m_treeScanner.isFinished() || m_waitingForScan)
return;
emitParsingStarted();
m_waitingForParse = runParse;
m_waitingForScan = runScan;
m_combinedScanAndParseResult = true;
if (runParse)
bc->runCMake();
if (runScan) {
m_treeScanner.asyncScanForFiles(projectDirectory());
Core::ProgressManager::addTask(m_treeScanner.future(),
tr("Scan \"%1\" project tree").arg(displayName()),
"CMake.Scan.Tree");
}
} }
void CMakeProject::buildCMakeTarget(const QString &buildTarget) void CMakeProject::buildCMakeTarget(const QString &buildTarget)
{ {
QTC_ASSERT(!buildTarget.isEmpty(), return); QTC_ASSERT(!buildTarget.isEmpty(), return);
Target *t = activeTarget(); CMakeBuildConfiguration *bc = activeBc(this);
auto bc = qobject_cast<CMakeBuildConfiguration *>(t ? t->activeBuildConfiguration() : nullptr);
if (bc) if (bc)
bc->buildTarget(buildTarget); bc->buildTarget(buildTarget);
} }
@@ -322,15 +421,60 @@ ProjectImporter *CMakeProject::projectImporter() const
return m_projectImporter.get(); return m_projectImporter.get();
} }
bool CMakeProject::persistCMakeState()
{
return m_buildDirManager.persistCMakeState();
}
void CMakeProject::clearCMakeCache()
{
m_buildDirManager.clearCache();
}
QList<CMakeBuildTarget> CMakeProject::buildTargets() const QList<CMakeBuildTarget> CMakeProject::buildTargets() const
{ {
CMakeBuildConfiguration *bc = nullptr; CMakeBuildConfiguration *bc = activeBc(this);
if (activeTarget())
bc = qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
return bc ? bc->buildTargets() : QList<CMakeBuildTarget>(); return bc ? bc->buildTargets() : QList<CMakeBuildTarget>();
} }
void CMakeProject::handleReparseRequest(int reparseParameters)
{
QTC_ASSERT(!(reparseParameters & BuildDirManager::REPARSE_FAIL), return);
if (reparseParameters & BuildDirManager::REPARSE_IGNORE)
return;
m_delayedParsingTimer.setInterval((reparseParameters & BuildDirManager::REPARSE_URGENT) ? 0 : 1000);
m_delayedParsingTimer.start();
m_delayedParsingParameters = m_delayedParsingParameters | reparseParameters;
}
void CMakeProject::startParsing(int reparseParameters)
{
m_delayedParsingParameters = BuildDirManager::REPARSE_DEFAULT;
QTC_ASSERT((reparseParameters & BuildDirManager::REPARSE_FAIL) == 0, return);
if (reparseParameters & BuildDirManager::REPARSE_IGNORE)
return;
QTC_ASSERT(activeBc(this), return);
emitParsingStarted();
m_waitingForParse = true;
m_combinedScanAndParseResult = true;
if (m_waitingForScan) {
QTC_CHECK(m_treeScanner.isFinished());
m_treeScanner.asyncScanForFiles(projectDirectory());
Core::ProgressManager::addTask(m_treeScanner.future(),
tr("Scan \"%1\" project tree").arg(displayName()),
"CMake.Scan.Tree");
}
m_buildDirManager.parse(reparseParameters);
}
QStringList CMakeProject::buildTargetTitles(bool runnable) const QStringList CMakeProject::buildTargetTitles(bool runnable) const
{ {
const QList<CMakeBuildTarget> targets const QList<CMakeBuildTarget> targets
@@ -361,33 +505,9 @@ bool CMakeProject::setupTarget(Target *t)
if (t->buildConfigurations().isEmpty()) if (t->buildConfigurations().isEmpty())
return false; return false;
t->updateDefaultDeployConfigurations(); t->updateDefaultDeployConfigurations();
return true; return true;
} }
void CMakeProject::handleActiveProjectConfigurationChanged(ProjectConfiguration *pc)
{
if (auto bc = qobject_cast<CMakeBuildConfiguration *>(pc)) {
if (!bc->isActive())
return;
} else if (!qobject_cast<Target *>(pc)) {
return;
}
for (Target *t : targets()) {
for (BuildConfiguration *bc : t->buildConfigurations()) {
auto i = qobject_cast<CMakeBuildConfiguration *>(bc);
QTC_ASSERT(i, continue);
if (i->isActive()) {
m_waitingForParse = true;
i->maybeForceReparse();
} else {
i->resetData();
}
}
}
}
void CMakeProject::handleTreeScanningFinished() void CMakeProject::handleTreeScanningFinished()
{ {
QTC_CHECK(m_waitingForScan); QTC_CHECK(m_waitingForScan);
@@ -395,8 +515,7 @@ void CMakeProject::handleTreeScanningFinished()
qDeleteAll(m_allFiles); qDeleteAll(m_allFiles);
m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; }); m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; });
auto t = activeTarget(); CMakeBuildConfiguration *bc = activeBc(this);
auto bc = qobject_cast<CMakeBuildConfiguration*>(t ? t->activeBuildConfiguration() : nullptr);
QTC_ASSERT(bc, return); QTC_ASSERT(bc, return);
m_combinedScanAndParseResult = m_combinedScanAndParseResult && true; m_combinedScanAndParseResult = m_combinedScanAndParseResult && true;
@@ -407,7 +526,7 @@ void CMakeProject::handleTreeScanningFinished()
void CMakeProject::handleParsingSuccess(CMakeBuildConfiguration *bc) void CMakeProject::handleParsingSuccess(CMakeBuildConfiguration *bc)
{ {
QTC_CHECK(m_waitingForParse); QTC_ASSERT(m_waitingForParse, return);
if (!bc || !bc->isActive()) if (!bc || !bc->isActive())
return; return;
@@ -626,18 +745,4 @@ void CMakeProject::createGeneratedCodeModelSupport()
CppTools::GeneratedCodeModelSupport::update(m_extraCompilers); CppTools::GeneratedCodeModelSupport::update(m_extraCompilers);
} }
void CMakeBuildTarget::clear()
{
executable.clear();
makeCommand.clear();
workingDirectory.clear();
sourceDirectory.clear();
title.clear();
targetType = UtilityType;
includeFiles.clear();
compilerOptions.clear();
macros.clear();
files.clear();
}
} // namespace CMakeProjectManager } // namespace CMakeProjectManager

View File

@@ -26,8 +26,11 @@
#pragma once #pragma once
#include "cmake_global.h" #include "cmake_global.h"
#include "builddirmanager.h"
#include "cmakebuildtarget.h"
#include "cmakeprojectimporter.h" #include "cmakeprojectimporter.h"
#include "treescanner.h" #include "treescanner.h"
#include "builddirmanager.h"
#include <projectexplorer/extracompiler.h> #include <projectexplorer/extracompiler.h>
#include <projectexplorer/projectmacro.h> #include <projectexplorer/projectmacro.h>
@@ -42,40 +45,16 @@
#include <memory> #include <memory>
namespace CppTools { class CppProjectUpdater; } namespace CppTools { class CppProjectUpdater; }
namespace ProjectExplorer { class FileNode; }
namespace CMakeProjectManager { namespace CMakeProjectManager {
namespace Internal { namespace Internal {
class CMakeBuildConfiguration; class CMakeBuildConfiguration;
class CMakeBuildSettingsWidget; class CMakeBuildSettingsWidget;
class CMakeProjectNode;
} // namespace Internal } // namespace Internal
enum TargetType {
ExecutableType = 0,
StaticLibraryType = 2,
DynamicLibraryType = 3,
UtilityType = 64
};
class CMAKE_EXPORT CMakeBuildTarget
{
public:
QString title;
Utils::FileName executable; // TODO: rename to output?
TargetType targetType = UtilityType;
Utils::FileName workingDirectory;
Utils::FileName sourceDirectory;
Utils::FileName makeCommand;
// code model
QList<Utils::FileName> includeFiles;
QStringList compilerOptions;
ProjectExplorer::Macros macros;
QList<Utils::FileName> files;
void clear();
};
class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project
{ {
Q_OBJECT Q_OBJECT
@@ -103,6 +82,10 @@ public:
ProjectExplorer::ProjectImporter *projectImporter() const final; ProjectExplorer::ProjectImporter *projectImporter() const final;
bool persistCMakeState();
void clearCMakeCache();
bool mustUpdateCMakeStateBeforeBuild();
protected: protected:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final;
bool setupTarget(ProjectExplorer::Target *t) final; bool setupTarget(ProjectExplorer::Target *t) final;
@@ -110,10 +93,10 @@ protected:
private: private:
QList<CMakeBuildTarget> buildTargets() const; QList<CMakeBuildTarget> buildTargets() const;
enum DataCollectionAction { PARSE = 1, SCAN = 2 }; void handleReparseRequest(int reparseParameters);
void startParsingProject(const DataCollectionAction a);
void startParsing(int reparseParameters);
void handleActiveProjectConfigurationChanged(ProjectExplorer::ProjectConfiguration *pc);
void handleTreeScanningFinished(); void handleTreeScanningFinished();
void handleParsingSuccess(Internal::CMakeBuildConfiguration *bc); void handleParsingSuccess(Internal::CMakeBuildConfiguration *bc);
void handleParsingError(Internal::CMakeBuildConfiguration *bc); void handleParsingError(Internal::CMakeBuildConfiguration *bc);
@@ -121,19 +104,21 @@ private:
void updateProjectData(Internal::CMakeBuildConfiguration *bc); void updateProjectData(Internal::CMakeBuildConfiguration *bc);
void updateQmlJSCodeModel(); void updateQmlJSCodeModel();
Internal::CMakeProjectNode *
generateProjectTree(const QList<const ProjectExplorer::FileNode*> &allFiles) const;
void createGeneratedCodeModelSupport(); void createGeneratedCodeModelSupport();
QStringList filesGeneratedFrom(const QString &sourceFile) const final; QStringList filesGeneratedFrom(const QString &sourceFile) const final;
void updateTargetRunConfigurations(ProjectExplorer::Target *t); void updateTargetRunConfigurations(ProjectExplorer::Target *t);
void updateApplicationAndDeploymentTargets(); void updateApplicationAndDeploymentTargets();
bool mustUpdateCMakeStateBeforeBuild();
// TODO probably need a CMake specific node structure // TODO probably need a CMake specific node structure
QList<CMakeBuildTarget> m_buildTargets; QList<CMakeBuildTarget> m_buildTargets;
CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr;
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers; QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
Internal::TreeScanner m_treeScanner; Internal::TreeScanner m_treeScanner;
Internal::BuildDirManager m_buildDirManager;
bool m_waitingForScan = false; bool m_waitingForScan = false;
bool m_waitingForParse = false; bool m_waitingForParse = false;
@@ -144,6 +129,7 @@ private:
mutable std::unique_ptr<Internal::CMakeProjectImporter> m_projectImporter; mutable std::unique_ptr<Internal::CMakeProjectImporter> m_projectImporter;
QTimer m_delayedParsingTimer; QTimer m_delayedParsingTimer;
int m_delayedParsingParameters = 0;
friend class Internal::CMakeBuildConfiguration; friend class Internal::CMakeBuildConfiguration;
friend class Internal::CMakeBuildSettingsWidget; friend class Internal::CMakeBuildSettingsWidget;

View File

@@ -243,7 +243,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const Utils::FileName &impo
} }
QString errorMessage; QString errorMessage;
const CMakeConfig config = BuildDirManager::parseConfiguration(cacheFile, &errorMessage); const CMakeConfig config = BuildDirManager::parseCMakeConfiguration(cacheFile, &errorMessage);
if (config.isEmpty() || !errorMessage.isEmpty()) { if (config.isEmpty() || !errorMessage.isEmpty()) {
qCDebug(cmInputLog()) << "Failed to read configuration from" << cacheFile << errorMessage; qCDebug(cmInputLog()) << "Failed to read configuration from" << cacheFile << errorMessage;
return { }; return { };

View File

@@ -24,7 +24,6 @@
****************************************************************************/ ****************************************************************************/
#include "cmakeprojectmanager.h" #include "cmakeprojectmanager.h"
#include "builddirmanager.h"
#include "cmakebuildconfiguration.h" #include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h" #include "cmakekitinformation.h"
#include "cmakeprojectconstants.h" #include "cmakeprojectconstants.h"
@@ -43,9 +42,6 @@
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <QAction> #include <QAction>
#include <QDateTime> #include <QDateTime>
#include <QIcon> #include <QIcon>
@@ -121,19 +117,15 @@ void CMakeManager::updateCmakeActions()
void CMakeManager::clearCMakeCache(Project *project) void CMakeManager::clearCMakeCache(Project *project)
{ {
if (!project || !project->activeTarget()) CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project);
return; if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
auto bc = qobject_cast<CMakeBuildConfiguration *>(project->activeTarget()->activeBuildConfiguration());
if (!bc)
return; return;
bc->clearCache(); cmakeProject->clearCMakeCache();
} }
void CMakeManager::runCMake(Project *project) void CMakeManager::runCMake(Project *project)
{ {
if (!project)
return;
CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project); CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project);
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration()) if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
return; return;
@@ -146,8 +138,6 @@ void CMakeManager::runCMake(Project *project)
void CMakeManager::rescanProject(Project *project) void CMakeManager::rescanProject(Project *project)
{ {
if (!project)
return;
CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project); CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project);
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration()) if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
return; return;

View File

@@ -2,9 +2,11 @@ DEFINES += CMAKEPROJECTMANAGER_LIBRARY
include(../../qtcreatorplugin.pri) include(../../qtcreatorplugin.pri)
HEADERS = builddirmanager.h \ HEADERS = builddirmanager.h \
builddirparameters.h \
builddirreader.h \ builddirreader.h \
cmakebuildinfo.h \ cmakebuildinfo.h \
cmakebuildstep.h \ cmakebuildstep.h \
cmakebuildtarget.h \
cmakeconfigitem.h \ cmakeconfigitem.h \
cmakeproject.h \ cmakeproject.h \
cmakeprojectimporter.h \ cmakeprojectimporter.h \
@@ -36,8 +38,10 @@ HEADERS = builddirmanager.h \
treescanner.h treescanner.h
SOURCES = builddirmanager.cpp \ SOURCES = builddirmanager.cpp \
builddirparameters.cpp \
builddirreader.cpp \ builddirreader.cpp \
cmakebuildstep.cpp \ cmakebuildstep.cpp \
cmakebuildtarget.cpp \
cmakeconfigitem.cpp \ cmakeconfigitem.cpp \
cmakeproject.cpp \ cmakeproject.cpp \
cmakeprojectimporter.cpp \ cmakeprojectimporter.cpp \

View File

@@ -200,6 +200,42 @@ QList<ConfigModel::DataItem> ConfigModel::configurationChanges() const
}); });
} }
void ConfigModel::setConfiguration(const CMakeConfig &config)
{
setConfiguration(Utils::transform(config, [](const CMakeConfigItem &i) {
ConfigModel::DataItem j;
j.key = QString::fromUtf8(i.key);
j.value = QString::fromUtf8(i.value);
j.description = QString::fromUtf8(i.documentation);
j.values = i.values;
j.inCMakeCache = i.inCMakeCache;
j.isAdvanced = i.isAdvanced;
j.isHidden = i.type == CMakeConfigItem::INTERNAL || i.type == CMakeConfigItem::STATIC;
switch (i.type) {
case CMakeConfigItem::FILEPATH:
j.type = ConfigModel::DataItem::FILE;
break;
case CMakeConfigItem::PATH:
j.type = ConfigModel::DataItem::DIRECTORY;
break;
case CMakeConfigItem::BOOL:
j.type = ConfigModel::DataItem::BOOLEAN;
break;
case CMakeConfigItem::STRING:
j.type = ConfigModel::DataItem::STRING;
break;
default:
j.type = ConfigModel::DataItem::UNKNOWN;
break;
}
return j;
}));
}
void ConfigModel::setConfiguration(const QList<ConfigModel::InternalDataItem> &config) void ConfigModel::setConfiguration(const QList<ConfigModel::InternalDataItem> &config)
{ {
QList<InternalDataItem> tmp = config; QList<InternalDataItem> tmp = config;

View File

@@ -25,6 +25,8 @@
#pragma once #pragma once
#include "cmakeconfigitem.h"
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <utils/treemodel.h> #include <utils/treemodel.h>
@@ -65,6 +67,7 @@ public:
const DataItem::Type type = DataItem::UNKNOWN, const DataItem::Type type = DataItem::UNKNOWN,
const QString &description = QString(), const QString &description = QString(),
const QStringList &values = QStringList()); const QStringList &values = QStringList());
void setConfiguration(const CMakeConfig &config);
void setConfiguration(const QList<DataItem> &config); void setConfiguration(const QList<DataItem> &config);
void setKitConfiguration(const QHash<QString, QString> &kitConfig); void setKitConfiguration(const QHash<QString, QString> &kitConfig);
void flush(); void flush();
@@ -80,6 +83,7 @@ public:
QList<DataItem> configurationChanges() const; QList<DataItem> configurationChanges() const;
private: private:
class InternalDataItem : public DataItem class InternalDataItem : public DataItem
{ {
@@ -97,9 +101,9 @@ private:
QString kitValue; QString kitValue;
}; };
void setConfiguration(const QList<InternalDataItem> &config);
void generateTree(); void generateTree();
void setConfiguration(const QList<InternalDataItem> &config);
QList<InternalDataItem> m_configuration; QList<InternalDataItem> m_configuration;
QHash<QString, QString> m_kitConfiguration; QHash<QString, QString> m_kitConfiguration;

View File

@@ -97,12 +97,15 @@ ServerModeReader::~ServerModeReader()
stop(); stop();
} }
void ServerModeReader::setParameters(const BuildDirReader::Parameters &p) void ServerModeReader::setParameters(const BuildDirParameters &p)
{ {
QTC_ASSERT(p.cmakeTool, return);
BuildDirReader::setParameters(p); BuildDirReader::setParameters(p);
if (!m_cmakeServer) { if (!m_cmakeServer) {
m_cmakeServer.reset(new ServerMode(p.environment, m_cmakeServer.reset(new ServerMode(p.environment,
p.sourceDirectory, p.buildDirectory, p.cmakeExecutable, p.sourceDirectory, p.buildDirectory,
p.cmakeTool->cmakeExecutable(),
p.generator, p.extraGenerator, p.platform, p.toolset, p.generator, p.extraGenerator, p.platform, p.toolset,
true, 1)); true, 1));
connect(m_cmakeServer.get(), &ServerMode::errorOccured, connect(m_cmakeServer.get(), &ServerMode::errorOccured,
@@ -135,14 +138,17 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
} }
} }
bool ServerModeReader::isCompatible(const BuildDirReader::Parameters &p) bool ServerModeReader::isCompatible(const BuildDirParameters &p)
{ {
// Server mode connection got lost, reset... if (!p.cmakeTool)
if (!m_parameters.cmakeExecutable.isEmpty() && !m_cmakeServer)
return false; return false;
return p.cmakeHasServerMode // Server mode connection got lost, reset...
&& p.cmakeExecutable == m_parameters.cmakeExecutable if (!m_parameters.cmakeTool->cmakeExecutable().isEmpty() && !m_cmakeServer)
return false;
return p.cmakeTool->hasServerMode()
&& p.cmakeTool->cmakeExecutable() == m_parameters.cmakeTool->cmakeExecutable()
&& p.environment == m_parameters.environment && p.environment == m_parameters.environment
&& p.generator == m_parameters.generator && p.generator == m_parameters.generator
&& p.extraGenerator == m_parameters.extraGenerator && p.extraGenerator == m_parameters.extraGenerator
@@ -154,16 +160,22 @@ bool ServerModeReader::isCompatible(const BuildDirReader::Parameters &p)
void ServerModeReader::resetData() void ServerModeReader::resetData()
{ {
m_hasData = false; m_cmakeConfiguration.clear();
// m_cmakeFiles: Keep these!
m_cmakeInputsFileNodes.clear();
qDeleteAll(m_projects); // Also deletes targets and filegroups that are its children!
m_projects.clear();
m_targets.clear();
m_fileGroups.clear();
} }
void ServerModeReader::parse(bool force) void ServerModeReader::parse(bool forceConfiguration)
{ {
emit configurationStarted(); emit configurationStarted();
QTC_ASSERT(m_cmakeServer, return); QTC_ASSERT(m_cmakeServer, return);
QVariantMap extra; QVariantMap extra;
if (force || !QDir(m_parameters.buildDirectory.toString()).exists("CMakeCache.txt")) { if (forceConfiguration || !QDir(m_parameters.buildDirectory.toString()).exists("CMakeCache.txt")) {
QStringList cacheArguments = transform(m_parameters.configuration, QStringList cacheArguments = transform(m_parameters.configuration,
[this](const CMakeConfigItem &i) { [this](const CMakeConfigItem &i) {
return i.toArgument(m_parameters.expander); return i.toArgument(m_parameters.expander);
@@ -208,12 +220,7 @@ bool ServerModeReader::isParsing() const
return static_cast<bool>(m_future); return static_cast<bool>(m_future);
} }
bool ServerModeReader::hasData() const QList<CMakeBuildTarget> ServerModeReader::takeBuildTargets()
{
return m_hasData;
}
QList<CMakeBuildTarget> ServerModeReader::buildTargets() const
{ {
const QList<CMakeBuildTarget> result = transform(m_targets, [](const Target *t) -> CMakeBuildTarget { const QList<CMakeBuildTarget> result = transform(m_targets, [](const Target *t) -> CMakeBuildTarget {
CMakeBuildTarget ct; CMakeBuildTarget ct;
@@ -246,8 +253,8 @@ QList<CMakeBuildTarget> ServerModeReader::buildTargets() const
CMakeConfig ServerModeReader::takeParsedConfiguration() CMakeConfig ServerModeReader::takeParsedConfiguration()
{ {
CMakeConfig config = m_cmakeCache; CMakeConfig config = m_cmakeConfiguration;
m_cmakeCache.clear(); m_cmakeConfiguration.clear();
return config; return config;
} }
@@ -372,11 +379,6 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps)
: CppTools::ProjectPart::Library); : CppTools::ProjectPart::Library);
rpps.append(rpp); rpps.append(rpp);
} }
qDeleteAll(m_projects); // Not used anymore!
m_projects.clear();
m_targets.clear();
m_fileGroups.clear();
} }
void ServerModeReader::handleReply(const QVariantMap &data, const QString &inReplyTo) void ServerModeReader::handleReply(const QVariantMap &data, const QString &inReplyTo)
@@ -415,7 +417,6 @@ void ServerModeReader::handleReply(const QVariantMap &data, const QString &inRep
m_future->reportFinished(); m_future->reportFinished();
m_future.reset(); m_future.reset();
} }
m_hasData = true;
Core::MessageManager::write(tr("CMake Project was parsed successfully.")); Core::MessageManager::write(tr("CMake Project was parsed successfully."));
emit dataAvailable(); emit dataAvailable();
} }
@@ -672,7 +673,7 @@ void ServerModeReader::extractCacheData(const QVariantMap &data)
item.values = CMakeConfigItem::cmakeSplitValue(properties.value("STRINGS").toString(), true); item.values = CMakeConfigItem::cmakeSplitValue(properties.value("STRINGS").toString(), true);
config.append(item); config.append(item);
} }
m_cmakeCache = config; m_cmakeConfiguration = config;
} }
void ServerModeReader::fixTarget(ServerModeReader::Target *target) const void ServerModeReader::fixTarget(ServerModeReader::Target *target) const

View File

@@ -33,10 +33,11 @@
#include <memory> #include <memory>
namespace ProjectExplorer { class ProjectNode; }
namespace CMakeProjectManager { namespace CMakeProjectManager {
namespace Internal { namespace Internal {
class ServerModeReader : public BuildDirReader class ServerModeReader : public BuildDirReader
{ {
Q_OBJECT Q_OBJECT
@@ -45,18 +46,17 @@ public:
ServerModeReader(); ServerModeReader();
~ServerModeReader() final; ~ServerModeReader() final;
void setParameters(const Parameters &p) final; void setParameters(const BuildDirParameters &p) final;
bool isCompatible(const Parameters &p) final; bool isCompatible(const BuildDirParameters &p) final;
void resetData() final; void resetData() final;
void parse(bool force) final; void parse(bool forceConfiguration) final;
void stop() final; void stop() final;
bool isReady() const final; bool isReady() const final;
bool isParsing() const final; bool isParsing() const final;
bool hasData() const final;
QList<CMakeBuildTarget> buildTargets() const final; QList<CMakeBuildTarget> takeBuildTargets() final;
CMakeConfig takeParsedConfiguration() final; CMakeConfig takeParsedConfiguration() final;
void generateProjectTree(CMakeProjectNode *root, void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) final; const QList<const ProjectExplorer::FileNode *> &allFiles) final;
@@ -160,21 +160,19 @@ private:
const QList<ProjectExplorer::FileNode *> knownHeaders, const QList<ProjectExplorer::FileNode *> knownHeaders,
const QList<const ProjectExplorer::FileNode *> &allFiles); const QList<const ProjectExplorer::FileNode *> &allFiles);
bool m_hasData = false;
std::unique_ptr<ServerMode> m_cmakeServer; std::unique_ptr<ServerMode> m_cmakeServer;
std::unique_ptr<QFutureInterface<void>> m_future; std::unique_ptr<QFutureInterface<void>> m_future;
int m_progressStepMinimum = 0; int m_progressStepMinimum = 0;
int m_progressStepMaximum = 1000; int m_progressStepMaximum = 1000;
CMakeConfig m_cmakeCache; CMakeConfig m_cmakeConfiguration;
QSet<Utils::FileName> m_cmakeFiles; QSet<Utils::FileName> m_cmakeFiles;
QList<ProjectExplorer::FileNode *> m_cmakeInputsFileNodes; QList<ProjectExplorer::FileNode *> m_cmakeInputsFileNodes;
QList<Project *> m_projects; QList<Project *> m_projects;
mutable QList<Target *> m_targets; QList<Target *> m_targets;
QList<FileGroup *> m_fileGroups; QList<FileGroup *> m_fileGroups;
CMakeParser m_parser; CMakeParser m_parser;

View File

@@ -130,7 +130,9 @@ TeaLeafReader::TeaLeafReader()
{ {
connect(EditorManager::instance(), &EditorManager::aboutToSave, connect(EditorManager::instance(), &EditorManager::aboutToSave,
this, [this](const IDocument *document) { this, [this](const IDocument *document) {
if (m_cmakeFiles.contains(document->filePath()) || !m_parameters.isAutorun) if (m_cmakeFiles.contains(document->filePath())
|| !m_parameters.cmakeTool
|| !m_parameters.cmakeTool->isAutoRun())
emit dirty(); emit dirty();
}); });
@@ -150,15 +152,15 @@ TeaLeafReader::~TeaLeafReader()
resetData(); resetData();
} }
bool TeaLeafReader::isCompatible(const BuildDirReader::Parameters &p) bool TeaLeafReader::isCompatible(const BuildDirParameters &p)
{ {
return !p.cmakeHasServerMode; if (!p.cmakeTool)
return false;
return !p.cmakeTool->hasServerMode();
} }
void TeaLeafReader::resetData() void TeaLeafReader::resetData()
{ {
m_hasData = false;
qDeleteAll(m_watchedFiles); qDeleteAll(m_watchedFiles);
m_watchedFiles.clear(); m_watchedFiles.clear();
@@ -188,11 +190,11 @@ static QString findCbpFile(const QDir &directory)
return file; return file;
} }
void TeaLeafReader::parse(bool force) void TeaLeafReader::parse(bool forceConfiguration)
{ {
const QString cbpFile = findCbpFile(QDir(m_parameters.buildDirectory.toString())); const QString cbpFile = findCbpFile(QDir(m_parameters.buildDirectory.toString()));
const QFileInfo cbpFileFi = cbpFile.isEmpty() ? QFileInfo() : QFileInfo(cbpFile); const QFileInfo cbpFileFi = cbpFile.isEmpty() ? QFileInfo() : QFileInfo(cbpFile);
if (!cbpFileFi.exists() || force) { if (!cbpFileFi.exists() || forceConfiguration) {
// Initial create: // Initial create:
startCMake(toArguments(m_parameters.configuration, m_parameters.expander)); startCMake(toArguments(m_parameters.configuration, m_parameters.expander));
return; return;
@@ -206,7 +208,6 @@ void TeaLeafReader::parse(bool force)
startCMake(QStringList()); startCMake(QStringList());
} else { } else {
extractData(); extractData();
m_hasData = true;
emit dataAvailable(); emit dataAvailable();
} }
} }
@@ -228,12 +229,7 @@ bool TeaLeafReader::isParsing() const
return m_cmakeProcess && m_cmakeProcess->state() != QProcess::NotRunning; return m_cmakeProcess && m_cmakeProcess->state() != QProcess::NotRunning;
} }
bool TeaLeafReader::hasData() const QList<CMakeBuildTarget> TeaLeafReader::takeBuildTargets()
{
return m_hasData;
}
QList<CMakeBuildTarget> TeaLeafReader::buildTargets() const
{ {
return m_buildTargets; return m_buildTargets;
} }
@@ -247,7 +243,7 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration()
return { }; return { };
QString errorMessage; QString errorMessage;
CMakeConfig result = BuildDirManager::parseConfiguration(cacheFile, &errorMessage); CMakeConfig result = BuildDirManager::parseCMakeConfiguration(cacheFile, &errorMessage);
if (!errorMessage.isEmpty()) { if (!errorMessage.isEmpty()) {
emit errorOccured(errorMessage); emit errorOccured(errorMessage);
@@ -412,6 +408,8 @@ void TeaLeafReader::cleanUpProcess()
void TeaLeafReader::extractData() void TeaLeafReader::extractData()
{ {
QTC_ASSERT(m_parameters.isValid() && m_parameters.cmakeTool, return);
const FileName srcDir = m_parameters.sourceDirectory; const FileName srcDir = m_parameters.sourceDirectory;
const FileName bldDir = m_parameters.buildDirectory; const FileName bldDir = m_parameters.buildDirectory;
const FileName topCMake = Utils::FileName(srcDir).appendPath("CMakeLists.txt"); const FileName topCMake = Utils::FileName(srcDir).appendPath("CMakeLists.txt");
@@ -437,7 +435,7 @@ void TeaLeafReader::extractData()
// setFolderName // setFolderName
CMakeCbpParser cbpparser; CMakeCbpParser cbpparser;
// Parsing // Parsing
if (!cbpparser.parseCbpFile(m_parameters.pathMapper, cbpFile, srcDir)) if (!cbpparser.parseCbpFile(m_parameters.cmakeTool->pathMapper(), cbpFile, srcDir))
return; return;
m_projectName = cbpparser.projectName(); m_projectName = cbpparser.projectName();
@@ -460,6 +458,8 @@ void TeaLeafReader::extractData()
void TeaLeafReader::startCMake(const QStringList &configurationArguments) void TeaLeafReader::startCMake(const QStringList &configurationArguments)
{ {
QTC_ASSERT(m_parameters.isValid() && m_parameters.cmakeTool, return);
const FileName buildDirectory = m_parameters.buildDirectory; const FileName buildDirectory = m_parameters.buildDirectory;
QTC_ASSERT(!m_cmakeProcess, return); QTC_ASSERT(!m_cmakeProcess, return);
QTC_ASSERT(!m_parser, return); QTC_ASSERT(!m_parser, return);
@@ -503,7 +503,7 @@ void TeaLeafReader::startCMake(const QStringList &configurationArguments)
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
MessageManager::write(tr("Running \"%1 %2\" in %3.") MessageManager::write(tr("Running \"%1 %2\" in %3.")
.arg(m_parameters.cmakeExecutable.toUserOutput()) .arg(m_parameters.cmakeTool->cmakeExecutable().toUserOutput())
.arg(args) .arg(args)
.arg(buildDirectory.toUserOutput())); .arg(buildDirectory.toUserOutput()));
@@ -513,7 +513,7 @@ void TeaLeafReader::startCMake(const QStringList &configurationArguments)
tr("Configuring \"%1\"").arg(m_parameters.projectName), tr("Configuring \"%1\"").arg(m_parameters.projectName),
"CMake.Configure"); "CMake.Configure");
m_cmakeProcess->setCommand(m_parameters.cmakeExecutable.toString(), args); m_cmakeProcess->setCommand(m_parameters.cmakeTool->cmakeExecutable().toString(), args);
emit configurationStarted(); emit configurationStarted();
m_cmakeProcess->start(); m_cmakeProcess->start();
} }
@@ -549,7 +549,6 @@ void TeaLeafReader::cmakeFinished(int code, QProcess::ExitStatus status)
delete m_future; delete m_future;
m_future = nullptr; m_future = nullptr;
m_hasData = true;
emit dataAvailable(); emit dataAvailable();
} }
@@ -663,7 +662,7 @@ bool TeaLeafReader::extractFlagsFromNinja(const CMakeBuildTarget &buildTarget,
// found // found
// Get "all" target's working directory // Get "all" target's working directory
QByteArray ninjaFile; QByteArray ninjaFile;
QString buildNinjaFile = buildTargets().at(0).workingDirectory.toString(); QString buildNinjaFile = takeBuildTargets().at(0).workingDirectory.toString();
buildNinjaFile += "/build.ninja"; buildNinjaFile += "/build.ninja";
QFile buildNinja(buildNinjaFile); QFile buildNinja(buildNinjaFile);
if (buildNinja.exists()) { if (buildNinja.exists()) {

View File

@@ -46,15 +46,14 @@ public:
TeaLeafReader(); TeaLeafReader();
~TeaLeafReader() final; ~TeaLeafReader() final;
bool isCompatible(const Parameters &p) final; bool isCompatible(const BuildDirParameters &p) final;
void resetData() final; void resetData() final;
void parse(bool force) final; void parse(bool forceConfiguration) final;
void stop() final; void stop() final;
bool isParsing() const final; bool isParsing() const final;
bool hasData() const final;
QList<CMakeBuildTarget> buildTargets() const final; QList<CMakeBuildTarget> takeBuildTargets() final;
CMakeConfig takeParsedConfiguration() final; CMakeConfig takeParsedConfiguration() final;
void generateProjectTree(CMakeProjectNode *root, void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) final; const QList<const ProjectExplorer::FileNode *> &allFiles) final;
@@ -80,8 +79,6 @@ private:
ProjectExplorer::IOutputParser *m_parser = nullptr; ProjectExplorer::IOutputParser *m_parser = nullptr;
QFutureInterface<void> *m_future = nullptr; QFutureInterface<void> *m_future = nullptr;
bool m_hasData = false;
QSet<Utils::FileName> m_cmakeFiles; QSet<Utils::FileName> m_cmakeFiles;
QString m_projectName; QString m_projectName;
QList<CMakeBuildTarget> m_buildTargets; QList<CMakeBuildTarget> m_buildTargets;