CMake: Move BuildDirManager from the project into the buildconfiguration

Change-Id: I90126ff22dd394eba4145db142b3914d211af476
Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
This commit is contained in:
Tobias Hunger
2016-02-24 18:00:24 +01:00
parent 34fd32565a
commit 76a050cb83
9 changed files with 386 additions and 338 deletions

View File

@@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
#include "builddirmanager.h" #include "builddirmanager.h"
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h" #include "cmakekitinformation.h"
#include "cmakeparser.h" #include "cmakeparser.h"
#include "cmakeprojectmanager.h" #include "cmakeprojectmanager.h"
@@ -32,8 +33,10 @@
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <projectexplorer/kit.h> #include <projectexplorer/kit.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h> #include <projectexplorer/projectnodes.h>
#include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h> #include <projectexplorer/taskhub.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -88,43 +91,49 @@ static QStringList toArguments(const CMakeConfig &config) {
// BuildDirManager: // BuildDirManager:
// -------------------------------------------------------------------- // --------------------------------------------------------------------
BuildDirManager::BuildDirManager(const Utils::FileName &sourceDir, const ProjectExplorer::Kit *k, BuildDirManager::BuildDirManager(const CMakeBuildConfiguration *bc) :
const CMakeConfig &inputConfig, const Utils::Environment &env, m_buildConfiguration(bc),
const Utils::FileName &buildDir) :
m_sourceDir(sourceDir),
m_buildDir(buildDir),
m_kit(k),
m_environment(env),
m_inputConfig(inputConfig),
m_watcher(new QFileSystemWatcher(this)) m_watcher(new QFileSystemWatcher(this))
{ {
QTC_CHECK(!sourceDir.isEmpty()); QTC_ASSERT(bc, return);
m_projectName = m_sourceDir.fileName(); m_projectName = sourceDirectory().fileName();
if (m_buildDir.isEmpty()) {
m_tempDir = new QTemporaryDir(QLatin1String("cmake-tmp-XXXXXX"));
m_buildDir = Utils::FileName::fromString(m_tempDir->path());
}
QTC_CHECK(!m_buildDir.isEmpty());
QTC_CHECK(k);
m_reparseTimer.setSingleShot(true); m_reparseTimer.setSingleShot(true);
m_reparseTimer.setInterval(500); m_reparseTimer.setInterval(500);
connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::forceReparse); connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::forceReparse);
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this]() { connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this]() {
if (!isBusy()) if (!isParsing())
m_reparseTimer.start(); m_reparseTimer.start();
}); });
QTimer::singleShot(0, this, &BuildDirManager::parse);
} }
BuildDirManager::~BuildDirManager() BuildDirManager::~BuildDirManager()
{ {
delete m_tempDir; resetData();
} }
bool BuildDirManager::isBusy() const const ProjectExplorer::Kit *BuildDirManager::kit() const
{
return m_buildConfiguration->target()->kit();
}
const Utils::FileName BuildDirManager::buildDirectory() const
{
return m_buildConfiguration->buildDirectory();
}
const Utils::FileName BuildDirManager::sourceDirectory() const
{
return m_buildConfiguration->target()->project()->projectDirectory();
}
const CMakeConfig BuildDirManager::cmakeConfiguration() const
{
return m_buildConfiguration->cmakeConfiguration();
}
bool BuildDirManager::isParsing() const
{ {
if (m_cmakeProcess) if (m_cmakeProcess)
return m_cmakeProcess->state() != QProcess::NotRunning; return m_cmakeProcess->state() != QProcess::NotRunning;
@@ -133,53 +142,59 @@ bool BuildDirManager::isBusy() const
void BuildDirManager::forceReparse() void BuildDirManager::forceReparse()
{ {
if (isBusy()) { stopProcess();
m_cmakeProcess->disconnect();
m_cmakeProcess->deleteLater();
m_cmakeProcess = nullptr;
}
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit); CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
const QString generator = CMakeGeneratorKitInformation::generator(m_kit); const QString generator = CMakeGeneratorKitInformation::generator(kit());
QTC_ASSERT(tool, return); QTC_ASSERT(tool, return);
QTC_ASSERT(!generator.isEmpty(), return); QTC_ASSERT(!generator.isEmpty(), return);
startCMake(tool, generator, m_inputConfig); startCMake(tool, generator, cmakeConfiguration());
} }
void BuildDirManager::setInputConfiguration(const CMakeConfig &config) void BuildDirManager::resetData()
{ {
m_inputConfig = config; m_hasData = false;
forceReparse();
m_projectName.clear();
m_buildTargets.clear();
m_watchedFiles.clear();
qDeleteAll(m_files);
m_files.clear();
const QStringList watchedFiles = m_watcher->files();
if (!watchedFiles.isEmpty())
m_watcher->removePaths(watchedFiles);
} }
void BuildDirManager::parse() void BuildDirManager::parse()
{ {
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit); CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
const QString generator = CMakeGeneratorKitInformation::generator(m_kit); const QString generator = CMakeGeneratorKitInformation::generator(kit());
QTC_ASSERT(tool, return); QTC_ASSERT(tool, return);
QTC_ASSERT(!generator.isEmpty(), return); QTC_ASSERT(!generator.isEmpty(), return);
// Pop up a dialog asking the user to rerun cmake // Pop up a dialog asking the user to rerun cmake
QString cbpFile = CMakeManager::findCbpFile(QDir(m_buildDir.toString())); QString cbpFile = CMakeManager::findCbpFile(QDir(buildDirectory().toString()));
QFileInfo cbpFileFi(cbpFile); QFileInfo cbpFileFi(cbpFile);
if (!cbpFileFi.exists()) { if (!cbpFileFi.exists()) {
// Initial create: // Initial create:
startCMake(tool, generator, m_inputConfig); startCMake(tool, generator, cmakeConfiguration());
return; return;
} }
const bool mustUpdate const bool mustUpdate = m_watchedFiles.isEmpty()
= Utils::anyOf(m_watchedFiles, [&cbpFileFi](const Utils::FileName &f) { || Utils::anyOf(m_watchedFiles, [&cbpFileFi](const Utils::FileName &f) {
return f.toFileInfo().lastModified() > cbpFileFi.lastModified(); return f.toFileInfo().lastModified() > cbpFileFi.lastModified();
}); });
if (mustUpdate) { if (mustUpdate) {
startCMake(tool, generator, CMakeConfig()); startCMake(tool, generator, CMakeConfig());
} else { } else {
extractData(); extractData();
m_hasData = true;
emit dataAvailable(); emit dataAvailable();
} }
} }
@@ -199,7 +214,7 @@ QList<CMakeBuildTarget> BuildDirManager::buildTargets() const
return m_buildTargets; return m_buildTargets;
} }
QList<ProjectExplorer::FileNode *> BuildDirManager::files() const QList<ProjectExplorer::FileNode *> BuildDirManager::files()
{ {
return m_files; return m_files;
} }
@@ -211,25 +226,45 @@ void BuildDirManager::clearFiles()
CMakeConfig BuildDirManager::configuration() const CMakeConfig BuildDirManager::configuration() const
{ {
if (!m_hasData)
return CMakeConfig();
return parseConfiguration(); return parseConfiguration();
} }
void BuildDirManager::stopProcess()
{
if (m_cmakeProcess) {
m_cmakeProcess->disconnect();
if (m_cmakeProcess->state() == QProcess::Running) {
m_cmakeProcess->terminate();
if (!m_cmakeProcess->waitForFinished(500))
m_cmakeProcess->kill();
}
delete m_cmakeProcess;
m_cmakeProcess = nullptr;
// Delete issue parser:
m_parser->flush();
delete m_parser;
m_parser = nullptr;
}
}
void BuildDirManager::extractData() void BuildDirManager::extractData()
{ {
const Utils::FileName topCMake const Utils::FileName topCMake
= Utils::FileName::fromString(m_sourceDir.toString() + QLatin1String("/CMakeLists.txt")); = Utils::FileName::fromString(sourceDirectory().toString() + QLatin1String("/CMakeLists.txt"));
m_projectName = m_sourceDir.fileName(); resetData();
m_buildTargets.clear();
m_watchedFiles.clear(); m_projectName = sourceDirectory().fileName();
m_files.clear();
m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false)); m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false));
m_watchedFiles.insert(topCMake); m_watchedFiles.insert(topCMake);
m_watcher->removePaths(m_watcher->files());
// Find cbp file // Find cbp file
QString cbpFile = CMakeManager::findCbpFile(m_buildDir.toString()); QString cbpFile = CMakeManager::findCbpFile(buildDirectory().toString());
if (cbpFile.isEmpty()) if (cbpFile.isEmpty())
return; return;
@@ -238,7 +273,7 @@ void BuildDirManager::extractData()
// setFolderName // setFolderName
CMakeCbpParser cbpparser; CMakeCbpParser cbpparser;
// Parsing // Parsing
if (!cbpparser.parseCbpFile(m_kit, cbpFile, m_sourceDir.toString())) if (!cbpparser.parseCbpFile(kit(), cbpFile, sourceDirectory().toString()))
return; return;
m_projectName = cbpparser.projectName(); m_projectName = cbpparser.projectName();
@@ -271,12 +306,12 @@ void BuildDirManager::startCMake(CMakeTool *tool, const QString &generator,
QTC_ASSERT(!m_future, return); QTC_ASSERT(!m_future, return);
// Make sure m_buildDir exists: // Make sure m_buildDir exists:
const QString buildDirStr = m_buildDir.toString(); const QString buildDirStr = buildDirectory().toString();
QDir bDir = QDir(buildDirStr); QDir bDir = QDir(buildDirStr);
bDir.mkpath(buildDirStr); bDir.mkpath(buildDirStr);
m_parser = new CMakeParser; m_parser = new CMakeParser;
QDir source = QDir(m_sourceDir.toString()); QDir source = QDir(sourceDirectory().toString());
connect(m_parser, &ProjectExplorer::IOutputParser::addTask, m_parser, connect(m_parser, &ProjectExplorer::IOutputParser::addTask, m_parser,
[source](const ProjectExplorer::Task &task) { [source](const ProjectExplorer::Task &task) {
if (task.file.isEmpty() || task.file.toFileInfo().isAbsolute()) { if (task.file.isEmpty() || task.file.toFileInfo().isAbsolute()) {
@@ -290,11 +325,11 @@ void BuildDirManager::startCMake(CMakeTool *tool, const QString &generator,
// Always use the sourceDir: If we are triggered because the build directory is getting deleted // Always use the sourceDir: If we are triggered because the build directory is getting deleted
// then we are racing against CMakeCache.txt also getting deleted. // then we are racing against CMakeCache.txt also getting deleted.
const QString srcDir = m_sourceDir.toString(); const QString srcDir = sourceDirectory().toString();
m_cmakeProcess = new Utils::QtcProcess(this); m_cmakeProcess = new Utils::QtcProcess(this);
m_cmakeProcess->setWorkingDirectory(buildDirStr); m_cmakeProcess->setWorkingDirectory(buildDirStr);
m_cmakeProcess->setEnvironment(m_environment); m_cmakeProcess->setEnvironment(m_buildConfiguration->environment());
connect(m_cmakeProcess, &QProcess::readyReadStandardOutput, connect(m_cmakeProcess, &QProcess::readyReadStandardOutput,
this, &BuildDirManager::processCMakeOutput); this, &BuildDirManager::processCMakeOutput);
@@ -314,17 +349,17 @@ void BuildDirManager::startCMake(CMakeTool *tool, const QString &generator,
Core::MessageManager::write(tr("Running '%1 %2' in %3.") Core::MessageManager::write(tr("Running '%1 %2' in %3.")
.arg(tool->cmakeExecutable().toUserOutput()) .arg(tool->cmakeExecutable().toUserOutput())
.arg(args) .arg(args)
.arg(m_buildDir.toUserOutput())); .arg(buildDirectory().toUserOutput()));
m_future = new QFutureInterface<void>(); m_future = new QFutureInterface<void>();
m_future->setProgressRange(0, 1); m_future->setProgressRange(0, 1);
Core::ProgressManager::addTask(m_future->future(), Core::ProgressManager::addTask(m_future->future(),
tr("Configuring \"%1\"").arg(projectName()), tr("Configuring \"%1\"").arg(m_buildConfiguration->target()->project()->displayName()),
"CMake.Configure"); "CMake.Configure");
m_cmakeProcess->setCommand(tool->cmakeExecutable().toString(), args); m_cmakeProcess->setCommand(tool->cmakeExecutable().toString(), args);
m_cmakeProcess->start(); m_cmakeProcess->start();
emit parsingStarted(); emit configurationStarted();
} }
void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status) void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status)
@@ -335,12 +370,7 @@ void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status)
processCMakeOutput(); processCMakeOutput();
processCMakeError(); processCMakeError();
m_parser->flush(); stopProcess();
delete m_parser;
m_parser = nullptr;
m_cmakeProcess->deleteLater();
m_cmakeProcess = nullptr;
extractData(); // try even if cmake failed... extractData(); // try even if cmake failed...
@@ -363,6 +393,7 @@ void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status)
delete m_future; delete m_future;
m_future = 0; m_future = 0;
m_hasData = true;
emit dataAvailable(); emit dataAvailable();
} }
@@ -433,7 +464,7 @@ static CMakeConfigItem::Type fromByteArray(const QByteArray &type) {
CMakeConfig BuildDirManager::parseConfiguration() const CMakeConfig BuildDirManager::parseConfiguration() const
{ {
CMakeConfig result; CMakeConfig result;
const QString cacheFile = QDir(m_buildDir.toString()).absoluteFilePath(QLatin1String("CMakeCache.txt")); const QString cacheFile = QDir(buildDirectory().toString()).absoluteFilePath(QLatin1String("CMakeCache.txt"));
QFile cache(cacheFile); QFile cache(cacheFile);
if (!cache.open(QIODevice::ReadOnly | QIODevice::Text)) if (!cache.open(QIODevice::ReadOnly | QIODevice::Text))
return CMakeConfig(); return CMakeConfig();
@@ -470,7 +501,7 @@ CMakeConfig BuildDirManager::parseConfiguration() const
// Sanity checks: // Sanity checks:
if (key == "CMAKE_HOME_DIRECTORY") { if (key == "CMAKE_HOME_DIRECTORY") {
const Utils::FileName actualSourceDir = Utils::FileName::fromUserInput(QString::fromUtf8(value)); const Utils::FileName actualSourceDir = Utils::FileName::fromUserInput(QString::fromUtf8(value));
if (actualSourceDir != m_sourceDir) if (actualSourceDir != sourceDirectory())
emit errorOccured(tr("Build directory contains a build of the wrong project (%1).") emit errorOccured(tr("Build directory contains a build of the wrong project (%1).")
.arg(actualSourceDir.toUserOutput())); .arg(actualSourceDir.toUserOutput()));
} }

View File

@@ -57,39 +57,40 @@ class CMakeTool;
namespace Internal { namespace Internal {
class CMakeBuildConfiguration;
class BuildDirManager : public QObject class BuildDirManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
BuildDirManager(const Utils::FileName &sourceDir, const ProjectExplorer::Kit *k, BuildDirManager(const CMakeBuildConfiguration *bc);
const CMakeConfig &inputConfig, const Utils::Environment &env,
const Utils::FileName &buildDir);
~BuildDirManager() override; ~BuildDirManager() override;
const ProjectExplorer::Kit *kit() const { return m_kit; } const ProjectExplorer::Kit *kit() const;
const Utils::FileName buildDirectory() const { return m_buildDir; } const Utils::FileName buildDirectory() const;
const Utils::FileName sourceDirectory() const { return m_sourceDir; } const Utils::FileName sourceDirectory() const;
bool isBusy() const; const CMakeConfig cmakeConfiguration() const;
bool isParsing() const;
void parse(); void parse();
void forceReparse(); void forceReparse();
void resetData();
void setInputConfiguration(const CMakeConfig &config);
bool isProjectFile(const Utils::FileName &fileName) const; bool isProjectFile(const Utils::FileName &fileName) const;
QString projectName() const; QString projectName() const;
QList<CMakeBuildTarget> buildTargets() const; QList<CMakeBuildTarget> buildTargets() const;
QList<ProjectExplorer::FileNode *> files() const; QList<ProjectExplorer::FileNode *> files();
void clearFiles(); void clearFiles();
CMakeConfig configuration() const; CMakeConfig configuration() const;
signals: signals:
void parsingStarted() const; void configurationStarted() const;
void dataAvailable() const; void dataAvailable() const;
void errorOccured(const QString &err) const; void errorOccured(const QString &err) const;
private: private:
void stopProcess();
void extractData(); void extractData();
void startCMake(CMakeTool *tool, const QString &generator, const CMakeConfig &config); void startCMake(CMakeTool *tool, const QString &generator, const CMakeConfig &config);
@@ -100,14 +101,9 @@ private:
CMakeConfig parseConfiguration() const; CMakeConfig parseConfiguration() const;
const Utils::FileName m_sourceDir; bool m_hasData = false;
Utils::FileName m_buildDir;
Utils::FileName m_parsedSourceDir;
const ProjectExplorer::Kit *const m_kit;
Utils::Environment m_environment;
CMakeConfig m_inputConfig;
QTemporaryDir *m_tempDir = nullptr; const CMakeBuildConfiguration *m_buildConfiguration = nullptr;
Utils::QtcProcess *m_cmakeProcess = nullptr; Utils::QtcProcess *m_cmakeProcess = nullptr;
QSet<Utils::FileName> m_watchedFiles; QSet<Utils::FileName> m_watchedFiles;

View File

@@ -25,6 +25,7 @@
#include "cmakebuildconfiguration.h" #include "cmakebuildconfiguration.h"
#include "builddirmanager.h"
#include "cmakebuildinfo.h" #include "cmakebuildinfo.h"
#include "cmakebuildstep.h" #include "cmakebuildstep.h"
#include "cmakekitinformation.h" #include "cmakekitinformation.h"
@@ -75,10 +76,32 @@ static FileName shadowBuildDirectory(const FileName &projectFilePath, const Kit
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))
{ {
CMakeProject *project = static_cast<CMakeProject *>(parent->project()); auto project = static_cast<CMakeProject *>(parent->project());
setBuildDirectory(shadowBuildDirectory(project->projectFilePath(), setBuildDirectory(shadowBuildDirectory(project->projectFilePath(),
parent->kit(), parent->kit(),
displayName(), BuildConfiguration::Unknown)); displayName(), BuildConfiguration::Unknown));
m_buildDirManager = new BuildDirManager(this);
connect(m_buildDirManager, &BuildDirManager::dataAvailable,
this, &CMakeBuildConfiguration::dataAvailable);
connect(m_buildDirManager, &BuildDirManager::errorOccured,
this, &CMakeBuildConfiguration::setError);
connect(m_buildDirManager, &BuildDirManager::configurationStarted,
this, [this]() { m_completeConfigurationCache.clear(); emit parsingStarted(); });
connect(this, &CMakeBuildConfiguration::environmentChanged,
m_buildDirManager, &BuildDirManager::forceReparse);
connect(this, &CMakeBuildConfiguration::buildDirectoryChanged,
m_buildDirManager, &BuildDirManager::parse);
connect(target(), &Target::kitChanged, m_buildDirManager, &BuildDirManager::forceReparse);
connect(this, &CMakeBuildConfiguration::parsingStarted, project, &CMakeProject::handleParsingStarted);
connect(this, &CMakeBuildConfiguration::dataAvailable, project, &CMakeProject::parseCMakeOutput);
}
CMakeBuildConfiguration::~CMakeBuildConfiguration()
{
m_buildDirManager->deleteLater(); // Do not block while waiting for cmake...
} }
bool CMakeBuildConfiguration::isEnabled() const bool CMakeBuildConfiguration::isEnabled() const
@@ -139,6 +162,102 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
return true; return true;
} }
BuildDirManager *CMakeBuildConfiguration::buildDirManager() const
{
return m_buildDirManager;
}
bool CMakeBuildConfiguration::isParsing() const
{
return m_buildDirManager && m_buildDirManager->isParsing();
}
void CMakeBuildConfiguration::parse()
{
m_buildDirManager->parse();
}
void CMakeBuildConfiguration::resetData()
{
m_buildDirManager->resetData();
}
QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration() const
{
if (m_buildDirManager->isParsing())
return QList<ConfigModel::DataItem>();
if (m_completeConfigurationCache.isEmpty())
m_completeConfigurationCache = m_buildDirManager->configuration();
return Utils::transform(m_completeConfigurationCache, [](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.isAdvanced = i.isAdvanced;
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)
{
if (m_buildDirManager->isParsing())
return;
const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) {
CMakeConfigItem ni;
ni.key = i.key.toUtf8();
ni.value = i.value.toUtf8();
ni.documentation = i.description.toUtf8();
ni.isAdvanced = i.isAdvanced;
switch (i.type) {
case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN:
ni.type = CMakeConfigItem::BOOL;
break;
case CMakeProjectManager::ConfigModel::DataItem::FILE:
ni.type = CMakeConfigItem::FILEPATH;
break;
case CMakeProjectManager::ConfigModel::DataItem::DIRECTORY:
ni.type = CMakeConfigItem::PATH;
break;
case CMakeProjectManager::ConfigModel::DataItem::STRING:
ni.type = CMakeConfigItem::STRING;
break;
case CMakeProjectManager::ConfigModel::DataItem::UNKNOWN:
default:
ni.type = CMakeConfigItem::INTERNAL;
break;
}
return ni;
});
// There is a buildDirManager, so there must also be an active BC:
const CMakeConfig config = cmakeConfiguration() + newConfig;
setCMakeConfiguration(config);
m_buildDirManager->forceReparse();
}
void CMakeBuildConfiguration::emitBuildTypeChanged() void CMakeBuildConfiguration::emitBuildTypeChanged()
{ {
emit buildTypeChanged(); emit buildTypeChanged();

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "cmakeconfigitem.h" #include "cmakeconfigitem.h"
#include "configmodel.h"
#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/abi.h> #include <projectexplorer/abi.h>
@@ -38,7 +39,9 @@ class CMakeProject;
namespace Internal { namespace Internal {
class BuildDirManager;
class CMakeBuildConfigurationFactory; class CMakeBuildConfigurationFactory;
class CMakeBuildSettingsWidget;
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
{ {
@@ -47,6 +50,7 @@ class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
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;
@@ -60,24 +64,44 @@ public:
void emitBuildTypeChanged(); void emitBuildTypeChanged();
void setCMakeConfiguration(const CMakeConfig &config); void setCMakeConfiguration(const CMakeConfig &config);
bool hasCMakeConfiguration() const;
CMakeConfig cmakeConfiguration() const; CMakeConfig cmakeConfiguration() const;
void setError(const QString &message);
QString error() const; QString error() const;
BuildDirManager *buildDirManager() const;
bool isParsing() const;
void parse();
void resetData();
signals: signals:
void errorOccured(const QString &message); void errorOccured(const QString &message);
void parsingStarted();
void dataAvailable();
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;
private: private:
QList<ConfigModel::DataItem> completeCMakeConfiguration() const;
void setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items);
void setError(const QString &message);
QString m_initialArguments; QString m_initialArguments;
CMakeConfig m_configuration; CMakeConfig m_configuration;
QString m_error; QString m_error;
friend class CMakeProjectManager::CMakeProject; mutable QList<CMakeConfigItem> m_completeConfigurationCache;
BuildDirManager *m_buildDirManager = nullptr;
friend class CMakeBuildSettingsWidget;
friend class CMakeProject;
}; };
class CMakeBuildConfigurationFactory : public ProjectExplorer::IBuildConfigurationFactory class CMakeBuildConfigurationFactory : public ProjectExplorer::IBuildConfigurationFactory

View File

@@ -84,9 +84,9 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
buildDirChooser->setBaseFileName(project->projectDirectory()); buildDirChooser->setBaseFileName(project->projectDirectory());
buildDirChooser->setFileName(bc->buildDirectory()); buildDirChooser->setFileName(bc->buildDirectory());
connect(buildDirChooser, &Utils::PathChooser::rawPathChanged, this, connect(buildDirChooser, &Utils::PathChooser::rawPathChanged, this,
[this, project](const QString &path) { [this](const QString &path) {
m_configModel->flush(); // clear out config cache... m_configModel->flush(); // clear out config cache...
project->changeBuildDirectory(m_buildConfiguration, path); m_buildConfiguration->setBuildDirectory(Utils::FileName::fromString(path));
}); });
int row = 0; int row = 0;
@@ -123,7 +123,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
m_configView->setMinimumHeight(300); m_configView->setMinimumHeight(300);
m_configView->setRootIsDecorated(false); m_configView->setRootIsDecorated(false);
m_configView->setUniformRowHeights(true); m_configView->setUniformRowHeights(true);
new Utils::HeaderViewStretcher(m_configView->header(), 1); auto stretcher = new Utils::HeaderViewStretcher(m_configView->header(), 1);
m_configView->setSelectionMode(QAbstractItemView::SingleSelection); m_configView->setSelectionMode(QAbstractItemView::SingleSelection);
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems); m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
m_configView->setFrameShape(QFrame::NoFrame); m_configView->setFrameShape(QFrame::NoFrame);
@@ -166,13 +166,18 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
updateButtonState(); updateButtonState();
m_showProgressTimer.start(); m_showProgressTimer.start();
}); });
connect(project, &CMakeProject::buildDirectoryDataAvailable,
this, [this, project, buildDirChooser](ProjectExplorer::BuildConfiguration *bc) { if (m_buildConfiguration->isParsing())
m_showProgressTimer.start();
else
m_configModel->setConfiguration(m_buildConfiguration->completeCMakeConfiguration());
connect(m_buildConfiguration, &CMakeBuildConfiguration::dataAvailable,
this, [this, buildDirChooser, stretcher]() {
updateButtonState(); updateButtonState();
if (m_buildConfiguration == bc) { m_configModel->setConfiguration(m_buildConfiguration->completeCMakeConfiguration());
m_configModel->setConfiguration(project->currentCMakeConfiguration()); stretcher->stretch();
buildDirChooser->triggerChanged(); // refresh valid state... buildDirChooser->triggerChanged(); // refresh valid state...
}
m_showProgressTimer.stop(); m_showProgressTimer.stop();
m_progressIndicator->hide(); m_progressIndicator->hide();
}); });
@@ -186,8 +191,8 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
this, &CMakeBuildSettingsWidget::updateAdvancedCheckBox); this, &CMakeBuildSettingsWidget::updateAdvancedCheckBox);
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, project]() { connect(m_reconfigureButton, &QPushButton::clicked, this, [this]() {
project->setCurrentCMakeConfiguration(m_configModel->configurationChanges()); m_buildConfiguration->setCurrentCMakeConfiguration(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();
@@ -218,8 +223,7 @@ void CMakeBuildSettingsWidget::setError(const QString &message)
void CMakeBuildSettingsWidget::updateButtonState() void CMakeBuildSettingsWidget::updateButtonState()
{ {
auto project = static_cast<CMakeProject *>(m_buildConfiguration->target()->project()); const bool isParsing = m_buildConfiguration->isParsing();
const bool isParsing = project->isParsing();
const bool hasChanges = m_configModel->hasChanges(); const bool hasChanges = m_configModel->hasChanges();
m_resetButton->setEnabled(hasChanges && !isParsing); m_resetButton->setEnabled(hasChanges && !isParsing);
m_reconfigureButton->setEnabled((hasChanges || m_configModel->hasCMakeChanges()) && !isParsing); m_reconfigureButton->setEnabled((hasChanges || m_configModel->hasCMakeChanges()) && !isParsing);

View File

@@ -72,12 +72,12 @@ const char ADD_RUNCONFIGURATION_TEXT[] = "Current executable";
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl) : AbstractProcessStep(bsl, Core::Id(MS_ID)) CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl) : AbstractProcessStep(bsl, Core::Id(MS_ID))
{ {
ctor(); ctor(bsl);
} }
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Core::Id id) : AbstractProcessStep(bsl, id) CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Core::Id id) : AbstractProcessStep(bsl, id)
{ {
ctor(); ctor(bsl);
} }
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, CMakeBuildStep *bs) : CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, CMakeBuildStep *bs) :
@@ -86,10 +86,10 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, CMakeBuildStep *bs) :
m_toolArguments(bs->m_toolArguments), m_toolArguments(bs->m_toolArguments),
m_addRunConfigurationArgument(bs->m_addRunConfigurationArgument) m_addRunConfigurationArgument(bs->m_addRunConfigurationArgument)
{ {
ctor(); ctor(bsl);
} }
void CMakeBuildStep::ctor() void CMakeBuildStep::ctor(BuildStepList *bsl)
{ {
m_percentProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)%\\]")); m_percentProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)%\\]"));
m_ninjaProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)/\\s*(\\d*)")); m_ninjaProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)/\\s*(\\d*)"));
@@ -97,9 +97,15 @@ void CMakeBuildStep::ctor()
//: Default display name for the cmake make step. //: Default display name for the cmake make step.
setDefaultDisplayName(tr("Make")); setDefaultDisplayName(tr("Make"));
auto bc = qobject_cast<CMakeBuildConfiguration *>(bsl->parent());
if (!bc) {
auto t = qobject_cast<Target *>(bsl->parent()->parent());
QTC_ASSERT(t, return);
bc = qobject_cast<CMakeBuildConfiguration *>(t->activeBuildConfiguration());
}
connect(target(), &Target::kitChanged, this, &CMakeBuildStep::cmakeCommandChanged); connect(target(), &Target::kitChanged, this, &CMakeBuildStep::cmakeCommandChanged);
connect(static_cast<CMakeProject *>(project()), &CMakeProject::buildDirectoryDataAvailable, connect(bc, &CMakeBuildConfiguration::dataAvailable, this, &CMakeBuildStep::handleBuildTargetChanges);
this, &CMakeBuildStep::buildTargetsChanged);
} }
CMakeBuildConfiguration *CMakeBuildStep::cmakeBuildConfiguration() const CMakeBuildConfiguration *CMakeBuildStep::cmakeBuildConfiguration() const
@@ -117,12 +123,13 @@ CMakeRunConfiguration *CMakeBuildStep::targetsActiveRunConfiguration() const
return qobject_cast<CMakeRunConfiguration *>(target()->activeRunConfiguration()); return qobject_cast<CMakeRunConfiguration *>(target()->activeRunConfiguration());
} }
void CMakeBuildStep::buildTargetsChanged() void CMakeBuildStep::handleBuildTargetChanges()
{ {
const QStringList filteredTargets const QStringList filteredTargets
= Utils::filtered(static_cast<CMakeProject *>(project())->buildTargetTitles(), = Utils::filtered(static_cast<CMakeProject *>(project())->buildTargetTitles(),
[this](const QString &s) { return m_buildTargets.contains(s); }); [this](const QString &s) { return m_buildTargets.contains(s); });
setBuildTargets(filteredTargets); setBuildTargets(filteredTargets);
emit buildTargetsChanged();
} }
QVariantMap CMakeBuildStep::toMap() const QVariantMap CMakeBuildStep::toMap() const
@@ -401,7 +408,7 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
this, &CMakeBuildStepConfigWidget::updateDetails); this, &CMakeBuildStepConfigWidget::updateDetails);
connect(pro, &CMakeProject::buildDirectoryDataAvailable, this, &CMakeBuildStepConfigWidget::buildTargetsChanged); connect(m_buildStep, &CMakeBuildStep::buildTargetsChanged, this, &CMakeBuildStepConfigWidget::buildTargetsChanged);
connect(m_buildStep, &CMakeBuildStep::targetsToBuildChanged, this, &CMakeBuildStepConfigWidget::selectedBuildTargetsChanged); connect(m_buildStep, &CMakeBuildStep::targetsToBuildChanged, this, &CMakeBuildStepConfigWidget::selectedBuildTargetsChanged);
connect(pro, &CMakeProject::environmentChanged, this, &CMakeBuildStepConfigWidget::updateDetails); connect(pro, &CMakeProject::environmentChanged, this, &CMakeBuildStepConfigWidget::updateDetails);
} }

View File

@@ -83,6 +83,7 @@ public:
signals: signals:
void cmakeCommandChanged(); void cmakeCommandChanged();
void targetsToBuildChanged(); void targetsToBuildChanged();
void buildTargetsChanged();
protected: protected:
void processStarted() override; void processStarted() override;
@@ -97,9 +98,9 @@ protected:
void stdOutput(const QString &line) override; void stdOutput(const QString &line) override;
private: private:
void ctor(); void ctor(ProjectExplorer::BuildStepList *bsl);
void buildTargetsChanged(); void handleBuildTargetChanges();
CMakeRunConfiguration *targetsActiveRunConfiguration() const; CMakeRunConfiguration *targetsActiveRunConfiguration() const;
QRegExp m_percentProgress; QRegExp m_percentProgress;

View File

@@ -67,19 +67,18 @@
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QTemporaryDir> #include <QTemporaryDir>
using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace Utils; using namespace Utils;
namespace CMakeProjectManager {
using namespace Internal;
// 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
// DEFINES // DEFINES
// Open Questions
// Who sets up the environment for cl.exe ? INCLUDEPATH and so on
/*! /*!
\class CMakeProject \class CMakeProject
*/ */
@@ -93,19 +92,6 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName)
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX)); setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
rootProjectNode()->setDisplayName(fileName.parentDir().fileName()); rootProjectNode()->setDisplayName(fileName.parentDir().fileName());
connect(this, &CMakeProject::buildDirectoryDataAvailable, this, &CMakeProject::updateRunConfigurations);
connect(this, &Project::activeTargetChanged, this, &CMakeProject::activeTargetHasChanged);
connect(this, &CMakeProject::environmentChanged, this, [this]() {
BuildConfiguration *bc = nullptr;
if (activeTarget())
bc = activeTarget()->activeBuildConfiguration();
changeActiveBuildConfiguration(bc); // Does a clean reset of the builddirmanager
});
connect(this, &Project::addedTarget, this, [this](Target *t) {
connect(t, &Target::kitChanged, this, &CMakeProject::handleKitChanges);
});
} }
CMakeProject::~CMakeProject() CMakeProject::~CMakeProject()
@@ -115,71 +101,6 @@ CMakeProject::~CMakeProject()
qDeleteAll(m_extraCompilers); qDeleteAll(m_extraCompilers);
} }
void CMakeProject::changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
{
if (m_buildDirManager) {
m_buildDirManager->disconnect();
m_buildDirManager->deleteLater();
}
m_buildDirManager = nullptr;
Kit *k = nullptr;
CMakeConfig config;
Utils::FileName buildDir;
CMakeBuildConfiguration *cmakebc = qobject_cast<CMakeBuildConfiguration *>(bc);
if (!cmakebc) {
k = KitManager::defaultKit();
config = CMakeConfigurationKitInformation::configuration(k);
} else {
k = cmakebc->target()->kit();
config = cmakebc->cmakeConfiguration();
buildDir = cmakebc->buildDirectory();
}
if (k) {
m_buildDirManager = new Internal::BuildDirManager(projectDirectory(), k, config,
cmakebc->environment(), buildDir);
connect(m_buildDirManager, &BuildDirManager::parsingStarted,
this, &CMakeProject::parsingStarted);
connect(m_buildDirManager, &BuildDirManager::dataAvailable,
this, &CMakeProject::parseCMakeOutput);
connect(m_buildDirManager, &BuildDirManager::errorOccured,
cmakebc, &CMakeBuildConfiguration::setError);
}
}
void CMakeProject::activeTargetHasChanged(Target *target)
{
if (m_activeTarget) {
disconnect(m_activeTarget, &Target::activeBuildConfigurationChanged,
this, &CMakeProject::changeActiveBuildConfiguration);
}
m_activeTarget = target;
if (!m_activeTarget)
return;
connect(m_activeTarget, &Target::activeBuildConfigurationChanged,
this, &CMakeProject::changeActiveBuildConfiguration);
changeActiveBuildConfiguration(m_activeTarget->activeBuildConfiguration());
}
void CMakeProject::changeBuildDirectory(CMakeBuildConfiguration *bc, const QString &newBuildDirectory)
{
bc->setBuildDirectory(FileName::fromString(newBuildDirectory));
if (activeTarget() && activeTarget()->activeBuildConfiguration() == bc)
changeActiveBuildConfiguration(bc);
}
void CMakeProject::handleKitChanges()
{
const Target *t = qobject_cast<Target *>(sender());
if (t && t != activeTarget())
return;
changeActiveBuildConfiguration(t->activeBuildConfiguration()); // force proper refresh
}
QStringList CMakeProject::getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QStringList CMakeProject::getCXXFlagsFor(const CMakeBuildTarget &buildTarget,
QHash<QString, QStringList> &cache) QHash<QString, QStringList> &cache)
{ {
@@ -279,23 +200,25 @@ bool CMakeProject::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget,
void CMakeProject::parseCMakeOutput() void CMakeProject::parseCMakeOutput()
{ {
QTC_ASSERT(m_buildDirManager, return); auto cmakeBc = qobject_cast<CMakeBuildConfiguration *>(sender());
QTC_ASSERT(activeTarget() && activeTarget()->activeBuildConfiguration(), return); QTC_ASSERT(cmakeBc, return);
if (!activeTarget() || activeTarget()->activeBuildConfiguration() != cmakeBc)
return;
auto activeBC = static_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration()); BuildDirManager *bdm = cmakeBc->buildDirManager();
QTC_ASSERT(bdm, return);
rootProjectNode()->setDisplayName(m_buildDirManager->projectName()); rootProjectNode()->setDisplayName(bdm->projectName());
buildTree(static_cast<CMakeProjectNode *>(rootProjectNode()), m_buildDirManager->files()); buildTree(static_cast<CMakeProjectNode *>(rootProjectNode()), bdm->files());
m_buildDirManager->clearFiles(); // Some of the FileNodes in files() were deleted! bdm->clearFiles(); // Some of the FileNodes in files() were deleted!
updateApplicationAndDeploymentTargets(); updateApplicationAndDeploymentTargets();
createGeneratedCodeModelSupport(); createGeneratedCodeModelSupport();
ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(m_buildDirManager->kit()); ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(cmakeBc->target()->kit());
if (!tc) { if (!tc) {
emit buildDirectoryDataAvailable(activeBC);
emit fileListChanged(); emit fileListChanged();
return; return;
} }
@@ -305,7 +228,7 @@ void CMakeProject::parseCMakeOutput()
CppTools::ProjectPartBuilder ppBuilder(pinfo); CppTools::ProjectPartBuilder ppBuilder(pinfo);
CppTools::ProjectPart::QtVersion activeQtVersion = CppTools::ProjectPart::NoQt; CppTools::ProjectPart::QtVersion activeQtVersion = CppTools::ProjectPart::NoQt;
if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(m_buildDirManager->kit())) { if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(cmakeBc->target()->kit())) {
if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0)) if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
activeQtVersion = CppTools::ProjectPart::Qt4; activeQtVersion = CppTools::ProjectPart::Qt4;
else else
@@ -336,10 +259,11 @@ void CMakeProject::parseCMakeOutput()
m_codeModelFuture = modelmanager->updateProjectInfo(pinfo); m_codeModelFuture = modelmanager->updateProjectInfo(pinfo);
emit displayNameChanged(); emit displayNameChanged();
emit buildDirectoryDataAvailable(activeBC);
emit fileListChanged(); emit fileListChanged();
emit activeBC->emitBuildTypeChanged(); emit cmakeBc->emitBuildTypeChanged();
updateRunConfigurations();
} }
bool CMakeProject::needsConfiguration() const bool CMakeProject::needsConfiguration() const
@@ -364,105 +288,26 @@ bool CMakeProject::supportsKit(Kit *k, QString *errorMessage) const
void CMakeProject::runCMake() void CMakeProject::runCMake()
{ {
if (m_buildDirManager && !m_buildDirManager->isBusy()) CMakeBuildConfiguration *bc = nullptr;
m_buildDirManager->forceReparse(); if (activeTarget())
} bc = qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
bool CMakeProject::isParsing() const if (!bc)
{
return m_buildDirManager && m_buildDirManager->isBusy();
}
QList<ConfigModel::DataItem> CMakeProject::currentCMakeConfiguration() const
{
if (!m_buildDirManager || m_buildDirManager->isBusy())
return QList<ConfigModel::DataItem>();
const QList<CMakeConfigItem> cmakeItems = m_buildDirManager->configuration();
return Utils::transform(cmakeItems, [](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.isAdvanced = i.isAdvanced;
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 CMakeProject::setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items)
{
if (!m_buildDirManager || m_buildDirManager->isBusy())
return; return;
const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) { BuildDirManager *bdm = bc->buildDirManager();
CMakeConfigItem ni; if (bdm && !bdm->isParsing())
ni.key = i.key.toUtf8(); bdm->forceReparse();
ni.value = i.value.toUtf8();
ni.documentation = i.description.toUtf8();
ni.isAdvanced = i.isAdvanced;
switch (i.type) {
case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN:
ni.type = CMakeConfigItem::BOOL;
break;
case CMakeProjectManager::ConfigModel::DataItem::FILE:
ni.type = CMakeConfigItem::FILEPATH;
break;
case CMakeProjectManager::ConfigModel::DataItem::DIRECTORY:
ni.type = CMakeConfigItem::PATH;
break;
case CMakeProjectManager::ConfigModel::DataItem::STRING:
ni.type = CMakeConfigItem::STRING;
break;
case CMakeProjectManager::ConfigModel::DataItem::UNKNOWN:
default:
ni.type = CMakeConfigItem::INTERNAL;
break;
}
return ni;
});
// There is a buildDirManager, so there must also be an active BC:
QTC_ASSERT(activeTarget(), return);
QTC_ASSERT(activeTarget()->activeBuildConfiguration(), return);
auto bc = static_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
QTC_ASSERT(bc, return);
const CMakeConfig config = bc->cmakeConfiguration() + newConfig;
bc->setCMakeConfiguration(config);
m_buildDirManager->setInputConfiguration(config);
}
bool CMakeProject::isProjectFile(const FileName &fileName)
{
if (!m_buildDirManager)
return false;
return m_buildDirManager->isProjectFile(fileName);
} }
QList<CMakeBuildTarget> CMakeProject::buildTargets() const QList<CMakeBuildTarget> CMakeProject::buildTargets() const
{ {
if (!m_buildDirManager) BuildDirManager *bdm = nullptr;
if (activeTarget() && activeTarget()->activeBuildConfiguration())
bdm = static_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration())->buildDirManager();
if (!bdm)
return QList<CMakeBuildTarget>(); return QList<CMakeBuildTarget>();
return m_buildDirManager->buildTargets(); return bdm->buildTargets();
} }
QStringList CMakeProject::buildTargetTitles(bool runnable) const QStringList CMakeProject::buildTargetTitles(bool runnable) const
@@ -571,26 +416,22 @@ QString CMakeProject::displayName() const
QStringList CMakeProject::files(FilesMode fileMode) const QStringList CMakeProject::files(FilesMode fileMode) const
{ {
QStringList result; QList<FileNode *> nodes;
if (m_buildDirManager) { gatherFileNodes(rootProjectNode(), nodes);
QList<FileNode *> nodes; nodes = Utils::filtered(nodes, [fileMode](const FileNode *fn) {
gatherFileNodes(rootProjectNode(), nodes); const bool isGenerated = fn->isGenerated();
nodes = Utils::filtered(nodes, [fileMode](const FileNode *fn) { switch (fileMode)
const bool isGenerated = fn->isGenerated(); {
switch (fileMode) case ProjectExplorer::Project::SourceFiles:
{ return !isGenerated;
case ProjectExplorer::Project::SourceFiles: case ProjectExplorer::Project::GeneratedFiles:
return !isGenerated; return isGenerated;
case ProjectExplorer::Project::GeneratedFiles: case ProjectExplorer::Project::AllFiles:
return isGenerated; default:
case ProjectExplorer::Project::AllFiles: return true;
default: }
return true; });
} return Utils::transform(nodes, [fileMode](const FileNode* fn) { return fn->filePath().toString(); });
});
result = Utils::transform(nodes, [fileMode](const FileNode* fn) { return fn->filePath().toString(); });
}
return result;
} }
Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *errorMessage) Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *errorMessage)
@@ -599,13 +440,8 @@ Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *er
if (result != RestoreResult::Ok) if (result != RestoreResult::Ok)
return result; return result;
m_activeTarget = activeTarget(); handleActiveTargetChanged();
if (m_activeTarget) { handleActiveBuildConfigurationChanged();
connect(m_activeTarget, &Target::activeBuildConfigurationChanged,
this, &CMakeProject::changeActiveBuildConfiguration);
if (BuildConfiguration *bc = m_activeTarget->activeBuildConfiguration())
changeActiveBuildConfiguration(bc);
}
return RestoreResult::Ok; return RestoreResult::Ok;
} }
@@ -620,6 +456,46 @@ bool CMakeProject::setupTarget(Target *t)
return true; return true;
} }
void CMakeProject::handleActiveTargetChanged()
{
if (m_connectedTarget) {
disconnect(m_connectedTarget, &Target::activeBuildConfigurationChanged,
this, &CMakeProject::handleActiveBuildConfigurationChanged);
}
m_connectedTarget = activeTarget();
if (m_connectedTarget) {
connect(m_connectedTarget, &Target::activeBuildConfigurationChanged,
this, &CMakeProject::handleActiveBuildConfigurationChanged);
}
}
void CMakeProject::handleActiveBuildConfigurationChanged()
{
if (!activeTarget() || !activeTarget()->activeBuildConfiguration())
return;
auto activeBc = qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
foreach (Target *t, targets()) {
foreach (BuildConfiguration *bc, t->buildConfigurations()) {
auto i = qobject_cast<CMakeBuildConfiguration *>(bc);
QTC_ASSERT(i, continue);
if (i == activeBc)
i->parse();
else
i->resetData();
}
}
}
void CMakeProject::handleParsingStarted()
{
if (activeTarget() && activeTarget()->activeBuildConfiguration() == sender())
emit parsingStarted();
}
CMakeBuildTarget CMakeProject::buildTargetForTitle(const QString &title) CMakeBuildTarget CMakeProject::buildTargetForTitle(const QString &title)
{ {
foreach (const CMakeBuildTarget &ct, buildTargets()) foreach (const CMakeBuildTarget &ct, buildTargets())
@@ -807,3 +683,5 @@ void CMakeBuildTarget::clear()
compilerOptions.clear(); compilerOptions.clear();
defines.clear(); defines.clear();
} }
} // namespace CMakeProjectManager

View File

@@ -27,7 +27,6 @@
#include "cmake_global.h" #include "cmake_global.h"
#include "cmakeprojectnodes.h" #include "cmakeprojectnodes.h"
#include "configmodel.h"
#include <projectexplorer/extracompiler.h> #include <projectexplorer/extracompiler.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
@@ -104,39 +103,27 @@ public:
CMakeBuildTarget buildTargetForTitle(const QString &title); CMakeBuildTarget buildTargetForTitle(const QString &title);
bool isProjectFile(const Utils::FileName &fileName);
bool needsConfiguration() const override; bool needsConfiguration() const override;
bool requiresTargetPanel() const override; bool requiresTargetPanel() const override;
bool supportsKit(ProjectExplorer::Kit *k, QString *errorMessage = 0) const override; bool supportsKit(ProjectExplorer::Kit *k, QString *errorMessage = 0) const override;
void runCMake(); void runCMake();
bool isParsing() const;
QList<ConfigModel::DataItem> currentCMakeConfiguration() const;
void setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items);
signals: signals:
/// emitted when parsing starts: /// emitted when cmake is running:
void parsingStarted(); void parsingStarted();
/// emitted after parsing
void buildDirectoryDataAvailable(ProjectExplorer::BuildConfiguration *bc);
protected: protected:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override;
bool setupTarget(ProjectExplorer::Target *t) override; bool setupTarget(ProjectExplorer::Target *t) override;
// called by CMakeBuildSettingsWidget
void changeBuildDirectory(Internal::CMakeBuildConfiguration *bc, const QString &newBuildDirectory);
private: private:
void handleKitChanges(); void handleActiveTargetChanged();
void handleActiveBuildConfigurationChanged();
void handleParsingStarted();
void parseCMakeOutput(); void parseCMakeOutput();
void activeTargetHasChanged(ProjectExplorer::Target *target);
void changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*);
void updateRunConfigurations(); void updateRunConfigurations();
void buildTree(Internal::CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list); void buildTree(Internal::CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list);
@@ -150,13 +137,14 @@ private:
bool extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache); bool extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
bool extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache); bool extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
ProjectExplorer::Target *m_activeTarget = 0; ProjectExplorer::Target *m_connectedTarget = nullptr;
Internal::BuildDirManager *m_buildDirManager = 0;
// TODO probably need a CMake specific node structure // TODO probably need a CMake specific node structure
QList<CMakeBuildTarget> m_buildTargets; QList<CMakeBuildTarget> m_buildTargets;
QFuture<void> m_codeModelFuture; QFuture<void> m_codeModelFuture;
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers; QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
friend class Internal::CMakeBuildConfiguration;
}; };
} // namespace CMakeProjectManager } // namespace CMakeProjectManager