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

View File

@@ -25,9 +25,13 @@
#pragma once
#include "builddirparameters.h"
#include "builddirreader.h"
#include "cmakebuildtarget.h"
#include "cmakeconfigitem.h"
#include <cpptools/cpprawprojectpart.h>
#include <utils/fileutils.h>
#include <utils/temporarydirectory.h>
@@ -37,12 +41,7 @@
#include <functional>
#include <memory>
namespace ProjectExplorer {
class FileNode;
class IOutputParser;
class Kit;
class Task;
} // namespace ProjectExplorer
namespace ProjectExplorer { class FileNode; }
namespace CMakeProjectManager {
@@ -50,6 +49,7 @@ class CMakeTool;
namespace Internal {
class CMakeProjectNode;
class CMakeBuildConfiguration;
class BuildDirManager : public QObject
@@ -57,61 +57,63 @@ class BuildDirManager : public QObject
Q_OBJECT
public:
BuildDirManager(CMakeBuildConfiguration *bc);
BuildDirManager();
~BuildDirManager() final;
bool isParsing() const;
void setParametersAndRequestParse(const BuildDirParameters &parameters,
int newReaderReparseOptions, int existingReaderReparseOptions);
CMakeBuildConfiguration *buildConfiguration() const;
void clearCache();
void forceReparse();
void forceReparseWithoutCheckingForChanges();
void maybeForceReparse(); // Only reparse if the configuration has changed...
void resetData();
bool persistCMakeState();
void parse(int reparseParameters);
void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles);
const QList<const ProjectExplorer::FileNode *> &allFiles) const;
void updateCodeModel(CppTools::RawProjectParts &rpps);
QList<CMakeBuildTarget> buildTargets() const;
CMakeConfig parsedConfiguration() const;
QList<CMakeBuildTarget> takeBuildTargets() const;
CMakeConfig takeCMakeConfiguration() const;
static CMakeConfig parseConfiguration(const Utils::FileName &cacheFile,
static CMakeConfig parseCMakeConfiguration(const Utils::FileName &cacheFile,
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:
void requestReparse(bool urgent) const;
void configurationStarted() const;
void requestReparse(int reparseParameters) const;
void parsingStarted() const;
void dataAvailable() const;
void errorOccured(const QString &err) const;
private:
void emitDataAvailable();
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 updateReaderData();
void updateReaderType(const BuildDirParameters &p, std::function<void()> todo);
void forceReparseImpl(bool checkForChanges);
void parseOnceReaderReady(bool force, bool checkForChanges = true);
void maybeForceReparseOnceReaderReady();
bool hasConfigChanged();
void parse();
void becameDirty();
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
BuildDirParameters m_parameters;
mutable std::unique_ptr<Utils::TemporaryDirectory> m_tempDir = nullptr;
mutable CMakeConfig m_cmakeCache;
std::unique_ptr<BuildDirReader> m_reader;
mutable QList<CMakeBuildTarget> m_buildTargets;
mutable std::unique_ptr<BuildDirReader> m_reader;
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 "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
#include "servermodereader.h"
#include "tealeafreader.h"
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <utils/qtcassert.h>
using namespace ProjectExplorer;
@@ -43,57 +39,15 @@ namespace Internal {
// BuildDirReader:
// --------------------------------------------------------------------
BuildDirReader::Parameters::Parameters() = default;
BuildDirReader::Parameters::Parameters(const CMakeBuildConfiguration *bc)
BuildDirReader *BuildDirReader::createReader(const BuildDirParameters &p)
{
const ProjectExplorer::Kit *k = bc->target()->kit();
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)
QTC_ASSERT(p.isValid() && p.cmakeTool, return nullptr);
if (p.cmakeTool->hasServerMode())
return new ServerModeReader;
return new TeaLeafReader;
}
void BuildDirReader::setParameters(const BuildDirReader::Parameters &p)
void BuildDirReader::setParameters(const BuildDirParameters &p)
{
m_parameters = p;
}

View File

@@ -25,8 +25,9 @@
#pragma once
#include "builddirparameters.h"
#include "cmakebuildtarget.h"
#include "cmakeconfigitem.h"
#include "cmakeproject.h"
#include "cmaketool.h"
#include <cpptools/cpprawprojectpart.h>
@@ -38,6 +39,8 @@
#include <QFutureInterface>
#include <QObject>
namespace ProjectExplorer { class FileNode; }
namespace CMakeProjectManager {
namespace Internal {
@@ -49,52 +52,19 @@ class BuildDirReader : public QObject
Q_OBJECT
public:
struct Parameters {
Parameters();
Parameters(const CMakeBuildConfiguration *bc);
Parameters(const Parameters &other);
static BuildDirReader *createReader(const BuildDirParameters &p);
virtual void setParameters(const BuildDirParameters &p);
QString projectName;
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 bool isCompatible(const BuildDirParameters &p) = 0;
virtual void resetData() = 0;
virtual void parse(bool force) = 0;
virtual void parse(bool forceConfiguration) = 0;
virtual void stop() = 0;
virtual bool isReady() const { return true; }
virtual bool isParsing() const = 0;
virtual bool hasData() const = 0;
virtual QList<CMakeBuildTarget> takeBuildTargets() = 0;
virtual CMakeConfig takeParsedConfiguration() = 0;
virtual QList<CMakeBuildTarget> buildTargets() const = 0;
virtual void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) = 0;
virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0;
@@ -107,7 +77,7 @@ signals:
void errorOccured(const QString &message) const;
protected:
Parameters m_parameters;
BuildDirParameters m_parameters;
};
} // namespace Internal

View File

@@ -64,17 +64,11 @@ const char INITIAL_ARGUMENTS[] = "CMakeProjectManager.CMakeBuildConfiguration.In
const char CONFIGURATION_KEY[] = "CMake.Configuration";
CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent) :
BuildConfiguration(parent, Core::Id(Constants::CMAKE_BC_ID)),
m_buildDirManager(new BuildDirManager(this))
BuildConfiguration(parent, Core::Id(Constants::CMAKE_BC_ID))
{
ctor();
}
CMakeBuildConfiguration::~CMakeBuildConfiguration()
{
m_buildDirManager->deleteLater(); // Do not block while waiting for cmake...
}
bool CMakeBuildConfiguration::isEnabled() const
{
return m_error.isEmpty() && !isParsing();
@@ -88,8 +82,7 @@ QString CMakeBuildConfiguration::disabledReason() const
CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent,
CMakeBuildConfiguration *source) :
BuildConfiguration(parent, source),
m_configuration(source->m_configuration),
m_buildDirManager(new BuildDirManager(this))
m_configurationForCMake(source->m_configurationForCMake)
{
ctor();
cloneSteps(source);
@@ -99,7 +92,7 @@ QVariantMap CMakeBuildConfiguration::toMap() const
{
QVariantMap map(ProjectExplorer::BuildConfiguration::toMap());
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);
return map;
}
@@ -130,110 +123,28 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
}
// End Legacy
setCMakeConfiguration(legacyConf + conf);
setConfigurationForCMake(legacyConf + conf);
return true;
}
void CMakeBuildConfiguration::ctor()
{
auto project = static_cast<CMakeProject *>(target()->project());
setBuildDirectory(shadowBuildDirectory(project->projectFilePath(),
auto p = static_cast<CMakeProject *>(project());
setBuildDirectory(shadowBuildDirectory(p->projectFilePath(),
target()->kit(),
displayName(), BuildConfiguration::Unknown));
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();
connect(p, &Project::parsingFinished, this, &BuildConfiguration::enabledChanged);
}
bool CMakeBuildConfiguration::isParsing() const
{
return m_buildDirManager && m_buildDirManager->isParsing();
}
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();
return project()->isParsing() && isActive();
}
QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
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);
return m_buildTargets;
}
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
@@ -273,50 +184,23 @@ void CMakeBuildConfiguration::buildTarget(const QString &buildTarget)
cmBs->setBuildTarget(originalBuildTarget);
}
QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration() const
CMakeConfig CMakeBuildConfiguration::configurationFromCMake() const
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
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 m_configurationFromCMake;
}
return j;
});
void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &config)
{
m_configurationFromCMake = config;
}
void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items)
void CMakeBuildConfiguration::setBuildTargets(const QList<CMakeBuildTarget> &targets)
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return;
m_buildTargets = targets;
}
void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::DataItem> &items)
{
const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) {
CMakeConfigItem ni;
ni.key = i.key.toUtf8();
@@ -346,10 +230,8 @@ void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigMod
return ni;
});
const CMakeConfig config = cmakeConfiguration() + newConfig;
setCMakeConfiguration(config);
m_buildDirManager->forceReparseWithoutCheckingForChanges();
const CMakeConfig config = configurationForCMake() + newConfig;
setConfigurationForCMake(config);
}
void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec)
@@ -383,14 +265,14 @@ static CMakeConfig removeDuplicates(const CMakeConfig &config)
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();
CMakeConfig kitConfig = CMakeConfigurationKitInformation::configuration(k);
bool hasKitOverride = false;
foreach (const CMakeConfigItem &i, m_configuration) {
foreach (const CMakeConfigItem &i, m_configurationForCMake) {
const QString b = CMakeConfigItem::expandedValueOf(k, i.key, kitConfig);
if (!b.isNull() && i.expandedValue(k) != b) {
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."));
else
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)
@@ -556,7 +440,7 @@ ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(Proj
cleanSteps->insertStep(0, cleanStep);
bc->setBuildDirectory(copy.buildDirectory);
bc->setCMakeConfiguration(copy.configuration);
bc->setConfigurationForCMake(copy.configuration);
return bc;
}

View File

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

View File

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

View File

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

View File

@@ -269,10 +269,11 @@ void CMakeBuildStep::run(QFutureInterface<bool> &fi)
QTC_ASSERT(bc, return);
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);
mustDelay = true;
} else if (bc->updateCMakeStateBeforeBuild()) {
} else if (p->mustUpdateCMakeStateBeforeBuild()) {
emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage);
mustDelay = true;
} 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/headerpath.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
@@ -66,6 +67,11 @@ namespace CMakeProjectManager {
using namespace Internal;
static CMakeBuildConfiguration *activeBc(const CMakeProject *p)
{
return qobject_cast<CMakeBuildConfiguration *>(p->activeTarget() ? p->activeTarget()->activeBuildConfiguration() : nullptr);
}
// QtCreator CMake Generator wishlist:
// Which make targets we need to build to get all executables
// What is the actual compiler executable
@@ -77,27 +83,129 @@ using namespace Internal;
CMakeProject::CMakeProject(const FileName &fileName) : Project(Constants::CMAKEMIMETYPE, fileName),
m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this))
{
m_delayedParsingTimer.setSingleShot(true);
connect(&m_delayedParsingTimer, &QTimer::timeout,
this, [this]() { startParsingProject(PARSE); });
setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(projectDirectory().fileName());
connect(this, &Project::activeProjectConfigurationChanged,
this, &CMakeProject::handleActiveProjectConfigurationChanged);
// Timer:
m_delayedParsingTimer.setSingleShot(true);
subscribeSignal(&CMakeBuildConfiguration::requestReparse,
this, [this](CMakeBuildConfiguration *bc, bool isUrgent) {
if (bc->isActive()) {
m_delayedParsingTimer.setInterval(isUrgent ? 0 : 1000);
m_delayedParsingTimer.start();
connect(&m_delayedParsingTimer, &QTimer::timeout,
this, [this]() { startParsing(m_delayedParsingParameters); });
// BuildDirManager:
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);
m_treeScanner.setFilter([this](const Utils::MimeType &mimeType, const Utils::FileName &fn) {
@@ -148,15 +256,19 @@ CMakeProject::~CMakeProject()
void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
{
Target *const t = activeTarget();
const CMakeBuildConfiguration *aBc = activeBc(this);
QTC_ASSERT(bc, return);
QTC_ASSERT(bc == (t ? t->activeBuildConfiguration() : nullptr), return);
QTC_ASSERT(m_treeScanner.isFinished() && !bc->isParsing(), return);
QTC_ASSERT(bc == aBc, return);
QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return);
Target *t = bc->target();
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) {
setDisplayName(newRoot->displayName());
setRootProjectNode(newRoot);
@@ -184,7 +296,7 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
}
CppTools::RawProjectParts rpps;
bc->updateCodeModel(rpps);
m_buildDirManager.updateCodeModel(rpps);
for (CppTools::RawProjectPart &rpp : rpps) {
// TODO: Set the Qt version only if target actually depends on Qt.
@@ -197,6 +309,8 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
updateQmlJSCodeModel();
m_buildDirManager.resetData();
emit fileListChanged();
emit bc->emitBuildTypeChanged();
@@ -220,10 +334,10 @@ void CMakeProject::updateQmlJSCodeModel()
if (!bc)
return;
const QList<ConfigModel::DataItem> &cm = bc->completeCMakeConfiguration();
foreach (const ConfigModel::DataItem &di, cm) {
if (di.key.contains(QStringLiteral("QML_IMPORT_PATH"))) {
cmakeImports = di.value;
const CMakeConfig &cm = bc->configurationFromCMake();
foreach (const CMakeConfigItem &di, cm) {
if (di.key.contains("QML_IMPORT_PATH")) {
cmakeImports = QString::fromUtf8(di.value);
break;
}
}
@@ -234,6 +348,16 @@ void CMakeProject::updateQmlJSCodeModel()
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
{
return targets().isEmpty();
@@ -264,53 +388,28 @@ void CMakeProject::runCMake()
if (isParsing())
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()
{
if (isParsing())
if (!m_treeScanner.isFinished())
return;
startParsingProject(static_cast<DataCollectionAction>(PARSE | SCAN));
}
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");
}
m_waitingForScan = true;
runCMake();
}
void CMakeProject::buildCMakeTarget(const QString &buildTarget)
{
QTC_ASSERT(!buildTarget.isEmpty(), return);
Target *t = activeTarget();
auto bc = qobject_cast<CMakeBuildConfiguration *>(t ? t->activeBuildConfiguration() : nullptr);
CMakeBuildConfiguration *bc = activeBc(this);
if (bc)
bc->buildTarget(buildTarget);
}
@@ -322,15 +421,60 @@ ProjectImporter *CMakeProject::projectImporter() const
return m_projectImporter.get();
}
bool CMakeProject::persistCMakeState()
{
return m_buildDirManager.persistCMakeState();
}
void CMakeProject::clearCMakeCache()
{
m_buildDirManager.clearCache();
}
QList<CMakeBuildTarget> CMakeProject::buildTargets() const
{
CMakeBuildConfiguration *bc = nullptr;
if (activeTarget())
bc = qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
CMakeBuildConfiguration *bc = activeBc(this);
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
{
const QList<CMakeBuildTarget> targets
@@ -361,33 +505,9 @@ bool CMakeProject::setupTarget(Target *t)
if (t->buildConfigurations().isEmpty())
return false;
t->updateDefaultDeployConfigurations();
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()
{
QTC_CHECK(m_waitingForScan);
@@ -395,8 +515,7 @@ void CMakeProject::handleTreeScanningFinished()
qDeleteAll(m_allFiles);
m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; });
auto t = activeTarget();
auto bc = qobject_cast<CMakeBuildConfiguration*>(t ? t->activeBuildConfiguration() : nullptr);
CMakeBuildConfiguration *bc = activeBc(this);
QTC_ASSERT(bc, return);
m_combinedScanAndParseResult = m_combinedScanAndParseResult && true;
@@ -407,7 +526,7 @@ void CMakeProject::handleTreeScanningFinished()
void CMakeProject::handleParsingSuccess(CMakeBuildConfiguration *bc)
{
QTC_CHECK(m_waitingForParse);
QTC_ASSERT(m_waitingForParse, return);
if (!bc || !bc->isActive())
return;
@@ -626,18 +745,4 @@ void CMakeProject::createGeneratedCodeModelSupport()
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

View File

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

View File

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

View File

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

View File

@@ -2,9 +2,11 @@ DEFINES += CMAKEPROJECTMANAGER_LIBRARY
include(../../qtcreatorplugin.pri)
HEADERS = builddirmanager.h \
builddirparameters.h \
builddirreader.h \
cmakebuildinfo.h \
cmakebuildstep.h \
cmakebuildtarget.h \
cmakeconfigitem.h \
cmakeproject.h \
cmakeprojectimporter.h \
@@ -36,8 +38,10 @@ HEADERS = builddirmanager.h \
treescanner.h
SOURCES = builddirmanager.cpp \
builddirparameters.cpp \
builddirreader.cpp \
cmakebuildstep.cpp \
cmakebuildtarget.cpp \
cmakeconfigitem.cpp \
cmakeproject.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)
{
QList<InternalDataItem> tmp = config;

View File

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

View File

@@ -97,12 +97,15 @@ ServerModeReader::~ServerModeReader()
stop();
}
void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
void ServerModeReader::setParameters(const BuildDirParameters &p)
{
QTC_ASSERT(p.cmakeTool, return);
BuildDirReader::setParameters(p);
if (!m_cmakeServer) {
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,
true, 1));
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 (!m_parameters.cmakeExecutable.isEmpty() && !m_cmakeServer)
if (!p.cmakeTool)
return false;
return p.cmakeHasServerMode
&& p.cmakeExecutable == m_parameters.cmakeExecutable
// Server mode connection got lost, reset...
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.generator == m_parameters.generator
&& p.extraGenerator == m_parameters.extraGenerator
@@ -154,16 +160,22 @@ bool ServerModeReader::isCompatible(const BuildDirReader::Parameters &p)
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();
QTC_ASSERT(m_cmakeServer, return);
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,
[this](const CMakeConfigItem &i) {
return i.toArgument(m_parameters.expander);
@@ -208,12 +220,7 @@ bool ServerModeReader::isParsing() const
return static_cast<bool>(m_future);
}
bool ServerModeReader::hasData() const
{
return m_hasData;
}
QList<CMakeBuildTarget> ServerModeReader::buildTargets() const
QList<CMakeBuildTarget> ServerModeReader::takeBuildTargets()
{
const QList<CMakeBuildTarget> result = transform(m_targets, [](const Target *t) -> CMakeBuildTarget {
CMakeBuildTarget ct;
@@ -246,8 +253,8 @@ QList<CMakeBuildTarget> ServerModeReader::buildTargets() const
CMakeConfig ServerModeReader::takeParsedConfiguration()
{
CMakeConfig config = m_cmakeCache;
m_cmakeCache.clear();
CMakeConfig config = m_cmakeConfiguration;
m_cmakeConfiguration.clear();
return config;
}
@@ -372,11 +379,6 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps)
: CppTools::ProjectPart::Library);
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)
@@ -415,7 +417,6 @@ void ServerModeReader::handleReply(const QVariantMap &data, const QString &inRep
m_future->reportFinished();
m_future.reset();
}
m_hasData = true;
Core::MessageManager::write(tr("CMake Project was parsed successfully."));
emit dataAvailable();
}
@@ -672,7 +673,7 @@ void ServerModeReader::extractCacheData(const QVariantMap &data)
item.values = CMakeConfigItem::cmakeSplitValue(properties.value("STRINGS").toString(), true);
config.append(item);
}
m_cmakeCache = config;
m_cmakeConfiguration = config;
}
void ServerModeReader::fixTarget(ServerModeReader::Target *target) const

View File

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

View File

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

View File

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