2016-01-20 12:19:16 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** 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 "builddirmanager.h"
|
2017-03-13 14:22:16 +01:00
|
|
|
|
2016-02-24 18:00:24 +01:00
|
|
|
#include "cmakebuildconfiguration.h"
|
2016-01-20 12:19:16 +01:00
|
|
|
#include "cmakekitinformation.h"
|
2016-10-06 11:31:15 +02:00
|
|
|
#include "cmakeprojectnodes.h"
|
2016-01-20 12:19:16 +01:00
|
|
|
#include "cmaketool.h"
|
|
|
|
|
|
2016-05-13 16:19:31 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2016-01-20 12:19:16 +01:00
|
|
|
#include <projectexplorer/kit.h>
|
2016-10-10 10:22:06 +02:00
|
|
|
#include <projectexplorer/kitinformation.h>
|
2016-02-24 18:00:24 +01:00
|
|
|
#include <projectexplorer/project.h>
|
2016-01-20 12:19:16 +01:00
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
2016-02-24 18:00:24 +01:00
|
|
|
#include <projectexplorer/target.h>
|
2016-01-20 12:19:16 +01:00
|
|
|
#include <projectexplorer/taskhub.h>
|
2016-10-10 10:22:06 +02:00
|
|
|
#include <projectexplorer/toolchain.h>
|
2016-01-20 12:19:16 +01:00
|
|
|
|
|
|
|
|
#include <utils/algorithm.h>
|
2016-02-15 15:50:26 +01:00
|
|
|
#include <utils/fileutils.h>
|
2016-01-20 12:19:16 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
2016-05-13 16:19:31 +02:00
|
|
|
#include <QMessageBox>
|
2016-01-20 12:19:16 +01:00
|
|
|
#include <QSet>
|
|
|
|
|
|
2016-10-06 11:31:15 +02:00
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
|
2016-01-20 12:19:16 +01:00
|
|
|
namespace CMakeProjectManager {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
// BuildDirManager:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
2016-05-13 16:19:31 +02:00
|
|
|
BuildDirManager::BuildDirManager(CMakeBuildConfiguration *bc) :
|
2016-06-27 14:49:35 +02:00
|
|
|
m_buildConfiguration(bc)
|
2016-01-20 12:19:16 +01:00
|
|
|
{
|
2016-02-24 18:00:24 +01:00
|
|
|
QTC_ASSERT(bc, return);
|
2016-01-20 12:19:16 +01:00
|
|
|
|
2016-02-15 10:48:46 +01:00
|
|
|
m_reparseTimer.setSingleShot(true);
|
2016-10-06 15:55:55 +02:00
|
|
|
|
2016-02-25 14:18:05 +01:00
|
|
|
connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::parse);
|
2016-02-24 18:00:24 +01:00
|
|
|
}
|
|
|
|
|
|
2016-10-17 14:38:38 +02:00
|
|
|
BuildDirManager::~BuildDirManager() = default;
|
|
|
|
|
|
2016-02-25 14:18:05 +01:00
|
|
|
const Utils::FileName BuildDirManager::workDirectory() const
|
|
|
|
|
{
|
2016-10-17 13:55:54 +02:00
|
|
|
const Utils::FileName bdir = m_buildConfiguration->buildDirectory();
|
2016-02-25 14:18:05 +01:00
|
|
|
if (bdir.exists())
|
|
|
|
|
return bdir;
|
2016-10-17 14:38:38 +02:00
|
|
|
if (!m_tempDir) {
|
2017-01-19 16:44:22 +01:00
|
|
|
m_tempDir.reset(new Utils::TemporaryDirectory("qtc-cmake-XXXXXXXX"));
|
2016-10-17 14:38:38 +02:00
|
|
|
if (!m_tempDir->isValid())
|
2017-03-24 19:35:13 +01:00
|
|
|
emitErrorOccured(tr("Failed to create temporary directory \"%1\".").arg(m_tempDir->path()));
|
2016-10-17 14:38:38 +02:00
|
|
|
}
|
2016-10-17 13:55:54 +02:00
|
|
|
return Utils::FileName::fromString(m_tempDir->path());
|
2016-02-25 14:18:05 +01:00
|
|
|
}
|
|
|
|
|
|
2016-10-28 17:20:07 +02:00
|
|
|
void BuildDirManager::emitDataAvailable()
|
|
|
|
|
{
|
2016-12-04 03:36:12 +10:00
|
|
|
if (!isParsing())
|
2016-10-28 17:20:07 +02:00
|
|
|
emit dataAvailable();
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 19:35:13 +01:00
|
|
|
void BuildDirManager::emitErrorOccured(const QString &message) const
|
|
|
|
|
{
|
|
|
|
|
m_isHandlingError = true;
|
|
|
|
|
emit errorOccured(message);
|
|
|
|
|
m_isHandlingError = false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-17 14:38:38 +02:00
|
|
|
void BuildDirManager::updateReaderType(std::function<void()> todo)
|
2016-02-24 18:00:24 +01:00
|
|
|
{
|
2016-10-17 13:55:54 +02:00
|
|
|
BuildDirReader::Parameters p(m_buildConfiguration);
|
|
|
|
|
p.buildDirectory = workDirectory();
|
2016-01-20 12:19:16 +01:00
|
|
|
|
2016-10-17 13:55:54 +02:00
|
|
|
if (!m_reader || !m_reader->isCompatible(p)) {
|
|
|
|
|
m_reader.reset(BuildDirReader::createReader(p));
|
|
|
|
|
connect(m_reader.get(), &BuildDirReader::configurationStarted,
|
|
|
|
|
this, &BuildDirManager::configurationStarted);
|
|
|
|
|
connect(m_reader.get(), &BuildDirReader::dataAvailable,
|
2016-10-28 17:20:07 +02:00
|
|
|
this, &BuildDirManager::emitDataAvailable);
|
2016-10-17 13:55:54 +02:00
|
|
|
connect(m_reader.get(), &BuildDirReader::errorOccured,
|
2017-03-24 19:35:13 +01:00
|
|
|
this, &BuildDirManager::emitErrorOccured);
|
2016-10-17 13:55:54 +02:00
|
|
|
connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty);
|
|
|
|
|
}
|
|
|
|
|
m_reader->setParameters(p);
|
2016-10-17 14:38:38 +02:00
|
|
|
|
|
|
|
|
if (m_reader->isReady())
|
|
|
|
|
todo();
|
|
|
|
|
else
|
|
|
|
|
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)
|
|
|
|
|
{
|
2016-12-02 17:24:14 +01:00
|
|
|
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
|
|
|
|
|
2016-11-30 14:13:59 +01:00
|
|
|
m_buildTargets.clear();
|
2016-12-01 15:25:32 +01:00
|
|
|
m_cmakeCache.clear();
|
2016-10-17 14:38:38 +02:00
|
|
|
checkConfiguration();
|
|
|
|
|
m_reader->stop();
|
|
|
|
|
m_reader->parse(force);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BuildDirManager::maybeForceReparseOnceReaderReady()
|
|
|
|
|
{
|
|
|
|
|
checkConfiguration();
|
|
|
|
|
|
|
|
|
|
const QByteArray GENERATOR_KEY = "CMAKE_GENERATOR";
|
|
|
|
|
const QByteArray EXTRA_GENERATOR_KEY = "CMAKE_EXTRA_GENERATOR";
|
|
|
|
|
const QByteArray CMAKE_COMMAND_KEY = "CMAKE_COMMAND";
|
2016-12-01 12:15:40 +01:00
|
|
|
const QByteArray CMAKE_C_COMPILER_KEY = "CMAKE_C_COMPILER";
|
|
|
|
|
const QByteArray CMAKE_CXX_COMPILER_KEY = "CMAKE_CXX_COMPILER";
|
2016-10-17 14:38:38 +02:00
|
|
|
|
|
|
|
|
const QByteArrayList criticalKeys
|
2017-02-22 15:09:35 +01:00
|
|
|
= {GENERATOR_KEY, CMAKE_COMMAND_KEY, CMAKE_C_COMPILER_KEY, CMAKE_CXX_COMPILER_KEY};
|
2016-10-17 14:38:38 +02:00
|
|
|
|
|
|
|
|
const CMakeConfig currentConfig = parsedConfiguration();
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
targetConfig.append(CMakeConfigItem(GENERATOR_KEY, CMakeConfigItem::INTERNAL,
|
|
|
|
|
QByteArray(), mainKitGenerator.toUtf8()));
|
|
|
|
|
if (!extraKitGenerator.isEmpty())
|
|
|
|
|
targetConfig.append(CMakeConfigItem(EXTRA_GENERATOR_KEY, CMakeConfigItem::INTERNAL,
|
|
|
|
|
QByteArray(), extraKitGenerator.toUtf8()));
|
|
|
|
|
targetConfig.append(CMakeConfigItem(CMAKE_COMMAND_KEY, CMakeConfigItem::INTERNAL,
|
|
|
|
|
QByteArray(), tool->cmakeExecutable().toUserOutput().toUtf8()));
|
|
|
|
|
Utils::sort(targetConfig, CMakeConfigItem::sortOperator());
|
|
|
|
|
|
|
|
|
|
bool mustReparse = false;
|
|
|
|
|
auto ccit = currentConfig.constBegin();
|
|
|
|
|
auto kcit = targetConfig.constBegin();
|
|
|
|
|
|
|
|
|
|
while (ccit != currentConfig.constEnd() && kcit != targetConfig.constEnd()) {
|
|
|
|
|
if (ccit->key == kcit->key) {
|
|
|
|
|
if (ccit->value != kcit->value) {
|
|
|
|
|
if (criticalKeys.contains(kcit->key)) {
|
|
|
|
|
clearCache();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
mustReparse = true;
|
|
|
|
|
}
|
|
|
|
|
++ccit;
|
|
|
|
|
++kcit;
|
|
|
|
|
} else {
|
|
|
|
|
if (ccit->key < kcit->key) {
|
|
|
|
|
++ccit;
|
|
|
|
|
} else {
|
|
|
|
|
++kcit;
|
|
|
|
|
mustReparse = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have keys that do not exist yet, then reparse.
|
|
|
|
|
//
|
|
|
|
|
// The critical keys *must* be set in cmake configuration, so those were already
|
|
|
|
|
// handled above.
|
|
|
|
|
if (mustReparse || kcit != targetConfig.constEnd())
|
|
|
|
|
parseOnceReaderReady(true);
|
2016-02-24 18:00:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BuildDirManager::isParsing() const
|
2016-01-20 12:19:16 +01:00
|
|
|
{
|
2016-10-17 13:55:54 +02:00
|
|
|
return m_reader && m_reader->isParsing();
|
2016-01-20 12:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-10-17 13:55:54 +02:00
|
|
|
void BuildDirManager::becameDirty()
|
2016-06-27 14:49:35 +02:00
|
|
|
{
|
|
|
|
|
if (isParsing())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-17 13:55:54 +02:00
|
|
|
Target *t = m_buildConfiguration->target()->project()->activeTarget();
|
|
|
|
|
BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr;
|
|
|
|
|
|
|
|
|
|
if (bc != m_buildConfiguration)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-06-27 14:49:35 +02:00
|
|
|
const CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
|
|
|
|
|
if (!tool->isAutoRun())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-06 15:55:55 +02:00
|
|
|
m_reparseTimer.start(1000);
|
2016-06-27 14:49:35 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-20 12:19:16 +01:00
|
|
|
void BuildDirManager::forceReparse()
|
|
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
QTC_ASSERT(!m_isHandlingError, return);
|
|
|
|
|
|
2016-03-16 16:33:54 +01:00
|
|
|
if (m_buildConfiguration->target()->activeBuildConfiguration() != m_buildConfiguration)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-17 13:55:54 +02:00
|
|
|
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
|
2016-01-20 12:19:16 +01:00
|
|
|
QTC_ASSERT(tool, return);
|
|
|
|
|
|
2016-10-28 19:16:34 +02:00
|
|
|
m_reader.reset(); // Force reparse by forcing in a new reader
|
2016-10-17 14:38:38 +02:00
|
|
|
updateReaderType([this]() { parseOnceReaderReady(true); });
|
2016-01-20 12:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 18:00:24 +01:00
|
|
|
void BuildDirManager::resetData()
|
2016-01-27 10:22:07 +01:00
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
QTC_ASSERT(!m_isHandlingError, return);
|
|
|
|
|
|
2016-10-17 13:55:54 +02:00
|
|
|
if (m_reader)
|
|
|
|
|
m_reader->resetData();
|
2016-10-10 11:08:50 +02:00
|
|
|
|
2016-05-13 13:34:18 +02:00
|
|
|
m_cmakeCache.clear();
|
2016-11-07 18:20:47 +01:00
|
|
|
m_reader.reset();
|
2016-11-30 14:13:59 +01:00
|
|
|
|
|
|
|
|
m_buildTargets.clear();
|
2016-01-27 10:22:07 +01:00
|
|
|
}
|
|
|
|
|
|
2016-10-06 15:55:55 +02:00
|
|
|
bool BuildDirManager::updateCMakeStateBeforeBuild()
|
|
|
|
|
{
|
|
|
|
|
return m_reparseTimer.isActive();
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 14:18:05 +01:00
|
|
|
bool BuildDirManager::persistCMakeState()
|
|
|
|
|
{
|
|
|
|
|
if (!m_tempDir)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-10-17 13:55:54 +02:00
|
|
|
const QString buildDir = m_buildConfiguration->buildDirectory().toString();
|
|
|
|
|
QDir dir(buildDir);
|
|
|
|
|
dir.mkpath(buildDir);
|
2016-02-25 14:18:05 +01:00
|
|
|
|
2016-10-17 13:55:54 +02:00
|
|
|
m_tempDir.reset(nullptr);
|
2016-02-25 14:18:05 +01:00
|
|
|
|
2016-05-23 11:38:06 +02:00
|
|
|
QTimer::singleShot(0, this, &BuildDirManager::parse); // make sure signals only happen afterwards!
|
2016-02-25 14:18:05 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-14 15:35:02 +01:00
|
|
|
void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles)
|
2016-10-06 11:31:15 +02:00
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
QTC_ASSERT(!m_isHandlingError, return);
|
2016-10-17 13:55:54 +02:00
|
|
|
QTC_ASSERT(m_reader, return);
|
2016-11-04 09:31:46 +01:00
|
|
|
|
|
|
|
|
const Utils::FileName projectFile = m_buildConfiguration->target()->project()->projectFilePath();
|
|
|
|
|
|
2016-12-15 12:53:37 +01:00
|
|
|
m_reader->generateProjectTree(root, allFiles);
|
2016-11-04 09:31:46 +01:00
|
|
|
|
2016-11-07 21:20:55 +01:00
|
|
|
// Make sure the top level CMakeLists.txt is always visible:
|
2017-01-26 17:02:16 +01:00
|
|
|
if (root->isEmpty())
|
2017-02-08 14:50:43 +01:00
|
|
|
root->addNode(new FileNode(projectFile, FileType::Project, false));
|
2016-10-06 11:31:15 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
void BuildDirManager::updateCodeModel(CppTools::RawProjectParts &rpps)
|
2016-10-10 10:22:06 +02:00
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
QTC_ASSERT(!m_isHandlingError, return);
|
2017-02-06 16:59:53 +01:00
|
|
|
QTC_ASSERT(m_reader, return);
|
|
|
|
|
return m_reader->updateCodeModel(rpps);
|
2016-10-10 10:22:06 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-20 12:19:16 +01:00
|
|
|
void BuildDirManager::parse()
|
|
|
|
|
{
|
2016-10-17 14:38:38 +02:00
|
|
|
updateReaderType([this]() { parseOnceReaderReady(false); });
|
2016-01-20 12:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 12:01:30 +01:00
|
|
|
void BuildDirManager::clearCache()
|
|
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
QTC_ASSERT(!m_isHandlingError, return);
|
|
|
|
|
|
2016-05-12 12:24:56 +02:00
|
|
|
auto cmakeCache = Utils::FileName(workDirectory()).appendPath(QLatin1String("CMakeCache.txt"));
|
|
|
|
|
auto cmakeFiles = Utils::FileName(workDirectory()).appendPath(QLatin1String("CMakeFiles"));
|
2016-03-10 12:01:30 +01:00
|
|
|
|
|
|
|
|
const bool mustCleanUp = cmakeCache.exists() || cmakeFiles.exists();
|
|
|
|
|
if (!mustCleanUp)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Utils::FileUtils::removeRecursively(cmakeCache);
|
|
|
|
|
Utils::FileUtils::removeRecursively(cmakeFiles);
|
|
|
|
|
|
|
|
|
|
forceReparse();
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-20 12:19:16 +01:00
|
|
|
QList<CMakeBuildTarget> BuildDirManager::buildTargets() const
|
|
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
QTC_ASSERT(!m_isHandlingError, return {});
|
|
|
|
|
|
2016-11-04 11:10:42 +01:00
|
|
|
if (!m_reader)
|
|
|
|
|
return QList<CMakeBuildTarget>();
|
2016-11-30 14:13:59 +01:00
|
|
|
if (m_buildTargets.isEmpty())
|
|
|
|
|
m_buildTargets = m_reader->buildTargets();
|
|
|
|
|
return m_buildTargets;
|
2016-01-20 12:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 17:31:30 +01:00
|
|
|
CMakeConfig BuildDirManager::parsedConfiguration() const
|
2016-01-26 17:26:46 +01:00
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
QTC_ASSERT(!m_isHandlingError, return {});
|
|
|
|
|
|
2016-11-04 11:10:42 +01:00
|
|
|
if (!m_reader)
|
|
|
|
|
return m_cmakeCache;
|
2016-10-17 13:55:54 +02:00
|
|
|
if (m_cmakeCache.isEmpty())
|
2016-12-01 15:25:32 +01:00
|
|
|
m_cmakeCache = m_reader->takeParsedConfiguration();
|
2017-01-18 16:53:01 +01:00
|
|
|
|
|
|
|
|
for (auto &ci : m_cmakeCache)
|
|
|
|
|
ci.inCMakeCache = true;
|
|
|
|
|
|
2016-05-13 13:34:18 +02:00
|
|
|
return m_cmakeCache;
|
2016-01-26 17:26:46 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 17:23:30 +01:00
|
|
|
CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile, QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (!cacheFile.exists()) {
|
|
|
|
|
if (errorMessage)
|
|
|
|
|
*errorMessage = tr("CMakeCache.txt file not found.");
|
|
|
|
|
return { };
|
|
|
|
|
}
|
|
|
|
|
CMakeConfig result = CMakeConfigItem::itemsFromFile(cacheFile, errorMessage);
|
|
|
|
|
if (!errorMessage->isEmpty())
|
|
|
|
|
return { };
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:19:31 +02:00
|
|
|
void BuildDirManager::checkConfiguration()
|
|
|
|
|
{
|
|
|
|
|
if (m_tempDir) // always throw away changes in the tmpdir!
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-06 11:31:15 +02:00
|
|
|
Kit *k = m_buildConfiguration->target()->kit();
|
2016-12-01 15:25:32 +01:00
|
|
|
const CMakeConfig cache = parsedConfiguration();
|
2016-05-13 16:19:31 +02:00
|
|
|
if (cache.isEmpty())
|
|
|
|
|
return; // No cache file yet.
|
|
|
|
|
|
|
|
|
|
CMakeConfig newConfig;
|
|
|
|
|
QSet<QString> changedKeys;
|
|
|
|
|
QSet<QString> removedKeys;
|
2016-10-17 13:55:54 +02:00
|
|
|
foreach (const CMakeConfigItem &iBc, m_buildConfiguration->cmakeConfiguration()) {
|
2016-05-13 16:19:31 +02:00
|
|
|
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)) {
|
|
|
|
|
changedKeys << QString::fromUtf8(iBc.key);
|
|
|
|
|
newConfig.append(iCache);
|
|
|
|
|
} else {
|
|
|
|
|
newConfig.append(iBc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!changedKeys.isEmpty() || !removedKeys.isEmpty()) {
|
|
|
|
|
QSet<QString> total = removedKeys + changedKeys;
|
|
|
|
|
QStringList keyList = total.toList();
|
|
|
|
|
Utils::sort(keyList);
|
|
|
|
|
QString table = QLatin1String("<table>");
|
|
|
|
|
foreach (const QString &k, keyList) {
|
|
|
|
|
QString change;
|
|
|
|
|
if (removedKeys.contains(k))
|
|
|
|
|
change = tr("<removed>");
|
|
|
|
|
else
|
|
|
|
|
change = QString::fromUtf8(CMakeConfigItem::valueOf(k.toUtf8(), cache)).trimmed();
|
|
|
|
|
if (change.isEmpty())
|
|
|
|
|
change = tr("<empty>");
|
|
|
|
|
table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td></tr>").arg(k).arg(change.toHtmlEscaped());
|
|
|
|
|
}
|
|
|
|
|
table += QLatin1String("\n</table>");
|
|
|
|
|
|
|
|
|
|
QPointer<QMessageBox> box = new QMessageBox(Core::ICore::mainWindow());
|
|
|
|
|
box->setText(tr("CMake configuration has changed on disk."));
|
|
|
|
|
box->setInformativeText(tr("The CMakeCache.txt file has changed: %1").arg(table));
|
2016-10-17 13:47:41 +02:00
|
|
|
auto *defaultButton = box->addButton(tr("Overwrite Changes in CMake"), QMessageBox::RejectRole);
|
|
|
|
|
box->addButton(tr("Apply Changes to Project"), QMessageBox::AcceptRole);
|
|
|
|
|
box->setDefaultButton(defaultButton);
|
2016-05-13 16:19:31 +02:00
|
|
|
|
|
|
|
|
int ret = box->exec();
|
2016-12-01 14:15:52 +01:00
|
|
|
if (ret == QMessageBox::Apply)
|
2016-05-13 16:19:31 +02:00
|
|
|
m_buildConfiguration->setCMakeConfiguration(newConfig);
|
2016-01-26 17:26:46 +01:00
|
|
|
}
|
2016-10-06 11:31:15 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 17:34:47 +01:00
|
|
|
void BuildDirManager::maybeForceReparse()
|
|
|
|
|
{
|
2017-03-24 19:35:13 +01:00
|
|
|
if (m_isHandlingError)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-31 16:48:43 +01:00
|
|
|
if (!m_reader || !m_reader->hasData()) {
|
|
|
|
|
forceReparse();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-17 14:38:38 +02:00
|
|
|
updateReaderType([this]() { maybeForceReparseOnceReaderReady(); });
|
2016-03-10 17:34:47 +01:00
|
|
|
}
|
|
|
|
|
|
2016-01-20 12:19:16 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace CMakeProjectManager
|