aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTobias Hunger <tobias.hunger@qt.io>2020-04-02 14:49:05 +0200
committerTobias Hunger <tobias.hunger@qt.io>2020-06-09 16:34:00 +0000
commit01b0d4f8f561328628051f14776d056a4bc023b6 (patch)
treead9ec87399761abae79f5bb7ece600eae6fa065c /src
parentc02a0037d52ec72c52fb0f924af417a7f400633c (diff)
CMake: Remove magic configuration from CMake
Get rid of magic configuration handling in the CMakeProjectManager. * Use CMakeCache.txt as the sole source of truth, do not keep a shadow copy of configuration in the .user file * Have initial CMake arguments that are easy to edit in batch (Fixes: QTCREATORBUG-18179) used whenever no CMakeCache.txt file is in the build directory. These allow for any thing that can be passed to CMake on the command line. (Fixes: QTCREATORBUG-16296) * Ask when changes to CMake configuration were not applied (Fixes: QTCREATORBUG-18504) * Run cmake with arguments effecting its configuration only when the CMake settings are changed in the UI, run CMake without any special arguments in all other cases. * Get rid of the confusing dialog used to keep settings in sync between what is in CMakeCache.txt and Creator (Fixes: QTCREATORBUG-23218) Change-Id: I26d55be7df733f084f5691ecf7d7b4352f58b8e7 Reviewed-by: Cristian Adam <cristian.adam@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/cmakeprojectmanager/builddirparameters.cpp28
-rw-r--r--src/plugins/cmakeprojectmanager/builddirparameters.h16
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp250
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h26
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp113
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h1
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp321
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsystem.h25
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp48
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeconfigitem.h1
-rw-r--r--src/plugins/cmakeprojectmanager/cmakekitinformation.cpp6
-rw-r--r--src/plugins/cmakeprojectmanager/cmakekitinformation.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprocess.cpp6
-rw-r--r--src/plugins/cmakeprojectmanager/configmodel.cpp18
-rw-r--r--src/plugins/cmakeprojectmanager/configmodel.h2
-rw-r--r--src/plugins/cmakeprojectmanager/fileapireader.cpp70
-rw-r--r--src/plugins/cmakeprojectmanager/fileapireader.h2
-rw-r--r--src/plugins/projectexplorer/buildsystem.h1
18 files changed, 432 insertions, 504 deletions
diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.cpp b/src/plugins/cmakeprojectmanager/builddirparameters.cpp
index 8522029e679..82b4b91d22b 100644
--- a/src/plugins/cmakeprojectmanager/builddirparameters.cpp
+++ b/src/plugins/cmakeprojectmanager/builddirparameters.cpp
@@ -49,6 +49,17 @@ BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
{
QTC_ASSERT(bc, return );
+ const Utils::MacroExpander *expander = bc->macroExpander();
+
+ initialCMakeArguments = Utils::transform(bc->initialCMakeArguments(),
+ [expander](const QString &s) {
+ return expander->expand(s);
+ });
+ extraCMakeArguments = Utils::transform(bc->extraCMakeArguments(),
+ [expander](const QString &s) {
+ return expander->expand(s);
+ });
+
const Target *t = bc->target();
const Kit *k = t->kit();
const Project *p = t->project();
@@ -70,23 +81,6 @@ BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
environment.appendOrSetPath(settings->ninjaPath().toString());
cmakeToolId = CMakeKitAspect::cmakeToolId(k);
-
- auto tc = ToolChainKitAspect::cxxToolChain(k);
- if (tc)
- cxxToolChainId = tc->id();
- tc = ToolChainKitAspect::cToolChain(k);
- if (tc)
- cToolChainId = tc->id();
-
- expander = k->macroExpander();
-
- configuration = bc->configurationForCMake();
-
- generator = CMakeGeneratorKitAspect::generator(k);
- extraGenerator = CMakeGeneratorKitAspect::extraGenerator(k);
- platform = CMakeGeneratorKitAspect::platform(k);
- toolset = CMakeGeneratorKitAspect::toolset(k);
- generatorArguments = CMakeGeneratorKitAspect::generatorArguments(k);
}
bool BuildDirParameters::isValid() const
diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.h b/src/plugins/cmakeprojectmanager/builddirparameters.h
index 7318ef03d86..5074a62fba3 100644
--- a/src/plugins/cmakeprojectmanager/builddirparameters.h
+++ b/src/plugins/cmakeprojectmanager/builddirparameters.h
@@ -54,21 +54,13 @@ public:
Utils::FilePath sourceDirectory;
Utils::FilePath buildDirectory;
Utils::FilePath workDirectory; // either buildDirectory or a QTemporaryDirectory!
- Utils::Environment environment;
- Core::Id cmakeToolId;
-
- QByteArray cxxToolChainId;
- QByteArray cToolChainId;
- Utils::MacroExpander *expander = nullptr;
+ Utils::Environment environment;
- CMakeConfig configuration;
+ Core::Id cmakeToolId;
- QString generator;
- QString extraGenerator;
- QString platform;
- QString toolset;
- QStringList generatorArguments;
+ QStringList initialCMakeArguments;
+ QStringList extraCMakeArguments;
};
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index 0a28a902ff0..25ba5986e58 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -61,6 +61,41 @@ static Q_LOGGING_CATEGORY(cmakeBuildConfigurationLog, "qtc.cmake.bc", QtWarningM
const char CONFIGURATION_KEY[] = "CMake.Configuration";
+// -----------------------------------------------------------------------------
+// Helper:
+// -----------------------------------------------------------------------------
+
+static QStringList defaultInitialCMakeArguments(const Kit *k, const QString buildType)
+{
+ // Generator:
+ QStringList initialArgs = CMakeGeneratorKitAspect::generatorArguments(k);
+
+ // CMAKE_BUILD_TYPE:
+ if (!buildType.isEmpty())
+ initialArgs.append(QString::fromLatin1("-DCMAKE_BUILD_TYPE:String=%1").arg(buildType));
+
+ // Cross-compilation settings:
+ const QString sysRoot = SysRootKitAspect::sysRoot(k).toString();
+ if (!sysRoot.isEmpty()) {
+ initialArgs.append(QString::fromLatin1("-DCMAKE_SYSROOT:PATH=%1").arg(sysRoot));
+ if (ToolChain *tc = ToolChainKitAspect::cxxToolChain(k)) {
+ const QString targetTriple = tc->originalTargetTriple();
+ initialArgs.append(
+ QString::fromLatin1("-DCMAKE_C_COMPILER_TARGET:STRING=%1").arg(targetTriple));
+ initialArgs.append(
+ QString::fromLatin1("-DCMAKE_CXX_COMPILER_TARGET:STRING=%1").arg(targetTriple));
+ }
+ }
+
+ initialArgs += CMakeConfigurationKitAspect::toArgumentsList(k);
+
+ return initialArgs;
+}
+
+// -----------------------------------------------------------------------------
+// CMakeBuildConfiguration:
+// -----------------------------------------------------------------------------
+
CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Core::Id id)
: BuildConfiguration(target, id)
{
@@ -88,41 +123,31 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Core::Id id)
return Utils::nullopt;
});
+ addAspect<InitialCMakeArgumentsAspect>();
+
appendInitialBuildStep(Constants::CMAKE_BUILD_STEP_ID);
appendInitialCleanStep(Constants::CMAKE_BUILD_STEP_ID);
setInitializer([this, target](const BuildInfo &info) {
- CMakeConfig config;
- config.append({"CMAKE_BUILD_TYPE", info.typeName.toUtf8()});
-
- Kit *k = target->kit();
- const QString sysRoot = SysRootKitAspect::sysRoot(k).toString();
- if (!sysRoot.isEmpty()) {
- config.append(CMakeConfigItem("CMAKE_SYSROOT", sysRoot.toUtf8()));
- if (ToolChain *tc = ToolChainKitAspect::cxxToolChain(k)) {
- const QByteArray targetTriple = tc->originalTargetTriple().toUtf8();
- config.append(CMakeConfigItem("CMAKE_C_COMPILER_TARGET", targetTriple));
- config.append(CMakeConfigItem("CMAKE_CXX_COMPILER_TARGET ", targetTriple));
- }
- }
+ const Kit *k = target->kit();
+
+ QStringList initialArgs = defaultInitialCMakeArguments(k, info.typeName);
+ // Android magic:
if (DeviceTypeKitAspect::deviceTypeId(k) == Android::Constants::ANDROID_DEVICE_TYPE) {
buildSteps()->appendStep(Android::Constants::ANDROID_BUILD_APK_ID);
const auto &bs = buildSteps()->steps().constLast();
- m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_NATIVE_API_LEVEL",
- CMakeProjectManager::CMakeConfigItem::Type::STRING,
- "Android native API level",
- bs->data(Android::Constants::AndroidNdkPlatform).toString().toUtf8()});
+ initialArgs.append(
+ QString::fromLatin1("-DANDROID_NATIVE_API_LEVEL:STRING=%1")
+ .arg(bs->data(Android::Constants::AndroidNdkPlatform).toString()));
auto ndkLocation = bs->data(Android::Constants::NdkLocation).value<FilePath>();
- m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_NDK",
- CMakeProjectManager::CMakeConfigItem::Type::PATH,
- "Android NDK PATH",
- ndkLocation.toString().toUtf8()});
+ initialArgs.append(
+ QString::fromLatin1("-DANDROID_NDK:PATH=%1").arg(ndkLocation.toString()));
- m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_TOOLCHAIN_FILE",
- CMakeProjectManager::CMakeConfigItem::Type::PATH,
- "Android CMake toolchain file",
- ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").toString().toUtf8()});
+ initialArgs.append(
+ QString::fromLatin1("-DCMAKE_TOOLCHAIN_FILE:PATH=%1")
+ .arg(
+ ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").toString()));
auto androidAbis = bs->data(Android::Constants::AndroidABIs).toStringList();
QString preferredAbi;
@@ -133,29 +158,19 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Core::Id id)
} else {
preferredAbi = androidAbis.first();
}
- // FIXME: configmodel doesn't care about our androidAbis list...
- m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_ABI",
- CMakeProjectManager::CMakeConfigItem::Type::STRING,
- "Android ABI",
- preferredAbi.toLatin1(),
- androidAbis});
+ initialArgs.append(QString::fromLatin1("-DANDROID_ABI:STRING=%1").arg(preferredAbi));
QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k);
if (qt->qtVersion() >= QtSupport::QtVersionNumber{5, 14, 0}) {
auto sdkLocation = bs->data(Android::Constants::SdkLocation).value<FilePath>();
- m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_SDK",
- CMakeProjectManager::CMakeConfigItem::Type::PATH,
- "Android SDK PATH",
- sdkLocation.toString().toUtf8()});
-
+ initialArgs.append(
+ QString::fromLatin1("-DANDROID_SDK:PATH=%1").arg(sdkLocation.toString()));
}
- m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_STL",
- CMakeProjectManager::CMakeConfigItem::Type::STRING,
- "Android STL",
- "c++_shared"});
+ initialArgs.append(QString::fromLatin1("-DANDROID_STL:STRING=cxx_shared"));
- m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH", "%{Qt:QT_INSTALL_PREFIX}"});
+ initialArgs.append(
+ QString::fromLatin1("-DCMAKE_FIND_ROOT_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}"));
}
if (info.buildDirectory.isEmpty()) {
@@ -165,13 +180,11 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Core::Id id)
info.buildType));
}
- setConfigurationForCMake(config);
+ setInitialCMakeArguments(initialArgs);
});
const auto qmlDebuggingAspect = addAspect<QtSupport::QmlDebuggingAspect>();
qmlDebuggingAspect->setKit(target->kit());
- connect(qmlDebuggingAspect, &QtSupport::QmlDebuggingAspect::changed,
- this, &CMakeBuildConfiguration::configurationForCMakeChanged);
}
CMakeBuildConfiguration::~CMakeBuildConfiguration()
@@ -182,9 +195,6 @@ CMakeBuildConfiguration::~CMakeBuildConfiguration()
QVariantMap CMakeBuildConfiguration::toMap() const
{
QVariantMap map(ProjectExplorer::BuildConfiguration::toMap());
- const QStringList config
- = Utils::transform(m_configurationForCMake, [](const CMakeConfigItem &i) { return i.toString(); });
- map.insert(QLatin1String(CONFIGURATION_KEY), config);
return map;
}
@@ -198,7 +208,29 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
[](const QString &v) { return CMakeConfigItem::fromString(v); }),
[](const CMakeConfigItem &c) { return !c.isNull(); });
- setConfigurationForCMake(conf);
+ // TODO: Upgrade from Qt Creator < 4.13: Remove when no longer supported!
+ const QString buildTypeName = [this]() {
+ switch (buildType()) {
+ case Debug:
+ return QString("Debug");
+ case Profile:
+ return QString("RelWithDebInfo");
+ case Release:
+ return QString("Release");
+ case Unknown:
+ default:
+ return QString("");
+ }
+ }();
+ if (initialCMakeArguments().isEmpty()) {
+ QStringList initialArgs = defaultInitialCMakeArguments(target()->kit(),
+ buildTypeName)
+ + Utils::transform(conf, [this](const CMakeConfigItem &i) {
+ return i.toArgument(macroExpander());
+ });
+
+ setInitialCMakeArguments(initialArgs);
+ }
return true;
}
@@ -244,54 +276,34 @@ CMakeConfig CMakeBuildConfiguration::configurationFromCMake() const
return m_configurationFromCMake;
}
-void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &config)
+QStringList CMakeBuildConfiguration::extraCMakeArguments() const
{
- m_configurationFromCMake = config;
+ return m_extraCMakeArguments;
}
-void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::DataItem> &items)
+QStringList CMakeBuildConfiguration::initialCMakeArguments() const
{
- 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;
- ni.isUnset = i.isUnset;
- ni.inCMakeCache = i.inCMakeCache;
- ni.values = i.values;
- 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;
- });
+ return aspect<InitialCMakeArgumentsAspect>()->value().split('\n', Qt::SkipEmptyParts);
+}
- const CMakeConfig config = configurationForCMake() + newConfig;
- setConfigurationForCMake(config);
+void CMakeBuildConfiguration::setExtraCMakeArguments(const QStringList &args)
+{
+ if (m_extraCMakeArguments == args)
+ return;
- if (Utils::indexOf(newConfig, [](const CMakeConfigItem &item){
- return item.key.startsWith("ANDROID_BUILD_ABI_");
- }) != -1) {
- // We always need to clean when we change the ANDROID_BUILD_ABI_ variables
- BuildManager::buildLists({cleanSteps()});
- }
+ qCDebug(cmakeBuildConfigurationLog)
+ << "Extra Args changed from" << m_extraCMakeArguments << "to" << args << "...";
+ m_extraCMakeArguments = args;
}
+void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &config)
+{
+ m_configurationFromCMake = config;
+}
+
+// FIXME: Run clean steps when a setting starting with "ANDROID_BUILD_ABI_" is changed.
+// FIXME: Warn when kit settings are overridden by a project.
+
void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec)
{
if (!m_error.isEmpty()) {
@@ -320,37 +332,9 @@ static CMakeConfig removeDuplicates(const CMakeConfig &config)
return result;
}
-void CMakeBuildConfiguration::setConfigurationForCMake(const CMakeConfig &config)
+void CMakeBuildConfiguration::setInitialCMakeArguments(const QStringList &args)
{
- auto configs = removeDuplicates(config);
- if (m_configurationForCMake.isEmpty())
- m_configurationForCMake = removeDuplicates(m_initialConfiguration +
- CMakeConfigurationKitAspect::configuration(target()->kit()) + configs);
- else
- m_configurationForCMake = configs;
-
- const Kit *k = target()->kit();
- CMakeConfig kitConfig = CMakeConfigurationKitAspect::configuration(k);
- bool hasKitOverride = false;
- foreach (const CMakeConfigItem &i, m_configurationForCMake) {
- const QString b = CMakeConfigItem::expandedValueOf(k, i.key, kitConfig);
- if (!b.isNull() && (i.expandedValue(k) != b || i.isUnset)) {
- hasKitOverride = true;
- break;
- }
- }
-
- if (hasKitOverride)
- setWarning(tr("CMake configuration set by the kit was overridden in the project."));
- else
- setWarning(QString());
-
- emit configurationForCMakeChanged();
-}
-
-CMakeConfig CMakeBuildConfiguration::configurationForCMake() const
-{
- return removeDuplicates(CMakeConfigurationKitAspect::configuration(target()->kit()) + m_configurationForCMake);
+ aspect<InitialCMakeArgumentsAspect>()->setValue(args.join('\n'));
}
void CMakeBuildConfiguration::setError(const QString &message)
@@ -491,19 +475,7 @@ BuildInfo CMakeBuildConfigurationFactory::createBuildInfo(BuildType buildType)
ProjectExplorer::BuildConfiguration::BuildType CMakeBuildConfiguration::buildType() const
{
- QByteArray cmakeBuildTypeName;
- QFile cmakeCache(buildDirectory().toString() + QLatin1String("/CMakeCache.txt"));
- if (cmakeCache.open(QIODevice::ReadOnly)) {
- while (!cmakeCache.atEnd()) {
- QByteArray line = cmakeCache.readLine();
- if (line.startsWith("CMAKE_BUILD_TYPE")) {
- if (int pos = line.indexOf('='))
- cmakeBuildTypeName = line.mid(pos + 1).trimmed();
- break;
- }
- }
- cmakeCache.close();
- }
+ QByteArray cmakeBuildTypeName = CMakeConfigItem::valueOf("CMAKE_BUILD_TYPE", m_configurationFromCMake);
// Cover all common CMake build types
const CMakeBuildConfigurationFactory::BuildType cmakeBuildType
@@ -516,5 +488,21 @@ BuildSystem *CMakeBuildConfiguration::buildSystem() const
return m_buildSystem;
}
+void CMakeBuildConfiguration::runCMakeWithExtraArguments()
+{
+ m_buildSystem->runCMakeWithExtraArguments();
+}
+
+// ----------------------------------------------------------------------
+// - InitialCMakeParametersAspect:
+// ----------------------------------------------------------------------
+
+InitialCMakeArgumentsAspect::InitialCMakeArgumentsAspect()
+{
+ setSettingsKey("CMake.Initial.Parameters");
+ setLabelText(tr("Initial CMake Parameters:"));
+ setDisplayStyle(TextEditDisplay);
+}
+
} // namespace Internal
} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
index c3d0f06254f..24a3ca1d43c 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
@@ -28,6 +28,7 @@
#include "cmakeconfigitem.h"
#include "configmodel.h"
+#include <projectexplorer/buildaspects.h>
#include <projectexplorer/buildconfiguration.h>
namespace CMakeProjectManager {
@@ -47,9 +48,12 @@ class CMakeBuildConfiguration final : public ProjectExplorer::BuildConfiguration
~CMakeBuildConfiguration() final;
public:
- CMakeConfig configurationForCMake() const;
CMakeConfig configurationFromCMake() const;
+ QStringList extraCMakeArguments() const;
+
+ QStringList initialCMakeArguments() const;
+
QString error() const;
QString warning() const;
@@ -61,12 +65,12 @@ public:
void buildTarget(const QString &buildTarget);
ProjectExplorer::BuildSystem *buildSystem() const final;
+ void runCMakeWithExtraArguments();
+
signals:
void errorOccurred(const QString &message);
void warningOccurred(const QString &message);
- void configurationForCMakeChanged();
-
private:
QVariantMap toMap() const override;
BuildType buildType() const override;
@@ -79,13 +83,13 @@ private:
void clearError(ForceEnabledChanged fec = ForceEnabledChanged::False);
void setConfigurationFromCMake(const CMakeConfig &config);
- void setConfigurationForCMake(const QList<ConfigModel::DataItem> &items);
- void setConfigurationForCMake(const CMakeConfig &config);
+
+ void setExtraCMakeArguments(const QStringList &args);
+ void setInitialCMakeArguments(const QStringList &args);
void setError(const QString &message);
void setWarning(const QString &message);
- CMakeConfig m_configurationForCMake;
CMakeConfig m_initialConfiguration;
QString m_error;
QString m_warning;
@@ -93,6 +97,8 @@ private:
CMakeConfig m_configurationFromCMake;
CMakeBuildSystem *m_buildSystem = nullptr;
+ QStringList m_extraCMakeArguments;
+
friend class CMakeBuildSettingsWidget;
friend class CMakeBuildSystem;
friend class CMakeProject;
@@ -120,5 +126,13 @@ private:
friend class CMakeProjectImporter;
};
+class InitialCMakeArgumentsAspect final : public ProjectExplorer::BaseStringAspect
+{
+ Q_OBJECT
+
+public:
+ InitialCMakeArgumentsAspect();
+};
+
} // namespace Internal
} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
index c1b4d038c8d..a564bb12529 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
@@ -27,6 +27,7 @@
#include "cmakebuildconfiguration.h"
#include "cmakebuildsystem.h"
+#include "cmakeconfigitem.h"
#include "cmakekitinformation.h"
#include "configmodel.h"
#include "configmodelitemdelegate.h"
@@ -37,6 +38,7 @@
#include <projectexplorer/target.h>
#include <qtsupport/qtbuildaspects.h>
+#include <utils/algorithm.h>
#include <utils/categorysortfiltermodel.h>
#include <utils/detailswidget.h>
#include <utils/headerviewstretcher.h>
@@ -101,10 +103,13 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(buildDirAspect, &ProjectConfigurationAspect::changed, this, [this]() {
m_configModel->flush(); // clear out config cache...;
});
- auto buildDirWidget = new QWidget;
- LayoutBuilder buildDirWidgetBuilder(buildDirWidget);
- buildDirAspect->addToLayout(buildDirWidgetBuilder);
- mainLayout->addWidget(buildDirWidget, row, 0, 1, 2);
+ auto initialCMakeAspect = bc->aspect<InitialCMakeArgumentsAspect>();
+ auto aspectWidget = new QWidget;
+ LayoutBuilder aspectWidgetBuilder(aspectWidget);
+ buildDirAspect->addToLayout(aspectWidgetBuilder);
+ aspectWidgetBuilder.startNewRow();
+ initialCMakeAspect->addToLayout(aspectWidgetBuilder);
+ mainLayout->addWidget(aspectWidget, row, 0, 1, 2);
++row;
auto qmlDebugAspect = bc->aspect<QtSupport::QmlDebuggingAspect>();
@@ -270,9 +275,10 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
m_configTextFilterModel, &QSortFilterProxyModel::setFilterFixedString);
connect(m_resetButton, &QPushButton::clicked, m_configModel, &ConfigModel::resetAllChanges);
- connect(m_reconfigureButton, &QPushButton::clicked, this, [this]() {
- m_buildConfiguration->setConfigurationForCMake(m_configModel->configurationForCMake());
- });
+ connect(m_reconfigureButton,
+ &QPushButton::clicked,
+ m_buildConfiguration,
+ &CMakeBuildConfiguration::runCMakeWithExtraArguments);
connect(m_unsetButton, &QPushButton::clicked, this, [this]() {
m_configModel->toggleUnsetFlag(mapToSource(m_configView, m_configView->currentIndex()));
});
@@ -312,10 +318,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(m_buildConfiguration, &CMakeBuildConfiguration::enabledChanged,
this, [this]() {
setError(m_buildConfiguration->disabledReason());
- setConfigurationForCMake();
});
- connect(m_buildConfiguration, &CMakeBuildConfiguration::configurationForCMakeChanged,
- this, [this]() { setConfigurationForCMake(); });
updateSelection(QModelIndex(), QModelIndex());
}
@@ -338,6 +341,42 @@ void CMakeBuildSettingsWidget::updateButtonState()
const bool hasChanges = m_configModel->hasChanges();
m_resetButton->setEnabled(hasChanges && !isParsing);
m_reconfigureButton->setEnabled((hasChanges || m_configModel->hasCMakeChanges()) && !isParsing);
+
+ // Update extra data in buildconfiguration
+ const QList<ConfigModel::DataItem> changes = m_configModel->configurationForCMake();
+
+ const CMakeConfig configChanges = Utils::transform(changes, [](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;
+ ni.isUnset = i.isUnset;
+ ni.inCMakeCache = i.inCMakeCache;
+ ni.values = i.values;
+ 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;
+ });
+
+ m_buildConfiguration->setExtraCMakeArguments(
+ Utils::transform(configChanges, [](const CMakeConfigItem &i) { return i.toArgument(); }));
}
void CMakeBuildSettingsWidget::updateAdvancedCheckBox()
@@ -371,49 +410,39 @@ void CMakeBuildSettingsWidget::handleQmlDebugCxxFlags()
const auto aspect = m_buildConfiguration->aspect<QtSupport::QmlDebuggingAspect>();
const bool enable = aspect->setting() == TriState::Enabled;
- CMakeConfig changedConfig = m_buildConfiguration->configurationForCMake();
const CMakeConfig configList = m_buildConfiguration->configurationFromCMake();
const QByteArrayList cxxFlags{"CMAKE_CXX_FLAGS", "CMAKE_CXX_FLAGS_DEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO"};
const QByteArray qmlDebug("-DQT_QML_DEBUG");
- for (CMakeConfigItem item : configList) {
- CMakeConfigItem it(item);
+ CMakeConfig changedConfig;
+
+ for (const CMakeConfigItem &item : configList) {
+ if (!cxxFlags.contains(item.key))
+ continue;
- if (cxxFlags.contains(it.key)) {
- if (enable) {
- if (!it.value.contains(qmlDebug)) {
- it.value = it.value.append(' ').append(qmlDebug);
- changed = true;
- }
- } else {
- int index = it.value.indexOf(qmlDebug);
- if (index != -1) {
- it.value.remove(index, qmlDebug.length());
- changed = true;
- }
+ CMakeConfigItem it(item);
+ if (enable) {
+ if (!it.value.contains(qmlDebug)) {
+ it.value = it.value.append(' ').append(qmlDebug);
+ changed = true;
+ }
+ } else {
+ int index = it.value.indexOf(qmlDebug);
+ if (index != -1) {
+ it.value.remove(index, qmlDebug.length());
+ changed = true;
}
- it.value = it.value.trimmed();
- changedConfig.append(it);
}
+ it.value = it.value.trimmed();
+ changedConfig.append(it);
}
- if (!changed)
- return;
-
- m_buildConfiguration->setConfigurationForCMake(changedConfig);
-}
-
-void CMakeBuildSettingsWidget::setConfigurationForCMake()
-{
- QHash<QString, QString> config;
- const CMakeConfig configList = m_buildConfiguration->configurationForCMake();
- for (const CMakeConfigItem &i : configList) {
- config.insert(QString::fromUtf8(i.key),
- CMakeConfigItem::expandedValueOf(m_buildConfiguration->target()->kit(),
- i.key, configList));
+ if (changed) {
+ m_buildConfiguration->setExtraCMakeArguments(
+ Utils::transform(changedConfig,
+ [](const CMakeConfigItem &i) { return i.toArgument(); }));
}
- m_configModel->setConfigurationForCMake(config);
}
void CMakeBuildSettingsWidget::updateSelection(const QModelIndex &current, const QModelIndex &previous)
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h
index 1014d2f6747..49f945230b9 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h
@@ -68,7 +68,6 @@ private:
void updateFromKit();
void handleQmlDebugCxxFlags();
- void setConfigurationForCMake();
void updateSelection(const QModelIndex &current, const QModelIndex &previous);
QAction *createForceAction(int type, const QModelIndex &idx);
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
index 48ef90f682a..4501ee7e3af 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
@@ -224,6 +224,7 @@ void CMakeBuildSystem::triggerParsing()
// is selected while this here is already running.
// Stop old parse run and keep that ParseGuard!
+ qCDebug(cmakeBuildSystemLog) << "Stopping current parsing run!";
stopParsingAndClearState();
} else {
// Use new ParseGuard
@@ -233,10 +234,15 @@ void CMakeBuildSystem::triggerParsing()
qCDebug(cmakeBuildSystemLog) << "ParseGuard acquired.";
- if (m_allFiles.isEmpty())
+ if (m_allFiles.isEmpty()) {
+ qCDebug(cmakeBuildSystemLog)
+ << "No treescanner information available, forcing treescanner run.";
updateReparseParameters(REPARSE_SCAN);
+ }
+
+ int reparseParameters = takeReparseParameters();
- m_waitingForScan = (m_reparseParameters | REPARSE_SCAN) != 0;
+ m_waitingForScan = (reparseParameters & REPARSE_SCAN) != 0;
m_waitingForParse = true;
m_combinedScanAndParseResult = true;
@@ -254,30 +260,31 @@ void CMakeBuildSystem::triggerParsing()
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
- int reparseParameters = takeReparseParameters();
-
qCDebug(cmakeBuildSystemLog) << "Parse called with flags:"
<< reparseParametersString(reparseParameters);
const QString cache = m_parameters.workDirectory.pathAppended("CMakeCache.txt").toString();
if (!QFileInfo::exists(cache)) {
- reparseParameters |= REPARSE_FORCE_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN;
+ reparseParameters |= REPARSE_FORCE_INITIAL_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN;
qCDebug(cmakeBuildSystemLog)
<< "No" << cache
<< "file found, new flags:" << reparseParametersString(reparseParameters);
- } else if (reparseParameters & REPARSE_CHECK_CONFIGURATION) {
- if (checkConfiguration()) {
- reparseParameters |= REPARSE_FORCE_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN;
- qCDebug(cmakeBuildSystemLog) << "Config check triggered flags change:"
- << reparseParametersString(reparseParameters);
- }
}
- writeConfigurationIntoBuildDirectory(m_parameters.expander);
+ if ((0 == (reparseParameters & REPARSE_FORCE_EXTRA_CONFIGURATION))
+ && !m_parameters.extraCMakeArguments.isEmpty()) {
+ if (mustApplyExtraArguments())
+ reparseParameters |= REPARSE_FORCE_CMAKE_RUN | REPARSE_FORCE_EXTRA_CONFIGURATION;
+ }
+
+ // Do not add extra args when doing initial configuration
+ if (0 != (reparseParameters & REPARSE_FORCE_INITIAL_CONFIGURATION))
+ reparseParameters = reparseParameters ^ REPARSE_FORCE_EXTRA_CONFIGURATION;
qCDebug(cmakeBuildSystemLog) << "Asking reader to parse";
m_reader.parse(reparseParameters & REPARSE_FORCE_CMAKE_RUN,
- reparseParameters & REPARSE_FORCE_CONFIGURATION);
+ reparseParameters & REPARSE_FORCE_INITIAL_CONFIGURATION,
+ reparseParameters & REPARSE_FORCE_EXTRA_CONFIGURATION);
}
bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
@@ -350,10 +357,8 @@ QString CMakeBuildSystem::reparseParametersString(int reparseFlags)
result += " URGENT";
if (reparseFlags & REPARSE_FORCE_CMAKE_RUN)
result += " FORCE_CMAKE_RUN";
- if (reparseFlags & REPARSE_FORCE_CONFIGURATION)
+ if (reparseFlags & REPARSE_FORCE_INITIAL_CONFIGURATION)
result += " FORCE_CONFIG";
- if (reparseFlags & REPARSE_CHECK_CONFIGURATION)
- result += " CHECK_CONFIG";
if (reparseFlags & REPARSE_SCAN)
result += " SCAN";
}
@@ -363,7 +368,8 @@ QString CMakeBuildSystem::reparseParametersString(int reparseFlags)
void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters &parameters,
const int reparseParameters)
{
- qCDebug(cmakeBuildSystemLog) << "setting parameters and requesting reparse";
+ qCDebug(cmakeBuildSystemLog) << "setting parameters and requesting reparse"
+ << reparseParametersString(reparseParameters);
if (!parameters.cmakeTool()) {
TaskHub::addTask(
BuildSystemTask(Task::Error,
@@ -387,42 +393,42 @@ void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters &pa
}
}
-void CMakeBuildSystem::writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander)
+bool CMakeBuildSystem::mustApplyExtraArguments() const
{
- QTC_ASSERT(expander, return );
-
- const FilePath buildDir = workDirectory(m_parameters);
- QTC_ASSERT(buildDir.exists(), return );
-
- const FilePath settingsFile = buildDir.pathAppended("qtcsettings.cmake");
-
- QByteArray contents;
- contents.append("# This file is managed by Qt Creator, do not edit!\n\n");
- contents.append(
- transform(m_parameters.configuration,
- [expander](const CMakeConfigItem &item) { return item.toCMakeSetLine(expander); })
- .join('\n')
- .toUtf8());
+ if (m_parameters.extraCMakeArguments.isEmpty())
+ return false;
- QFile file(settingsFile.toString());
- QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return );
- file.write(contents);
+ auto answer = QMessageBox::question(Core::ICore::mainWindow(),
+ tr("Apply configuration changes?"),
+ tr("Run CMake with \"%1\"?")
+ .arg(m_parameters.extraCMakeArguments.join(" ")),
+ QMessageBox::Apply | QMessageBox::Discard,
+ QMessageBox::Apply);
+ return answer == QMessageBox::Apply;
}
void CMakeBuildSystem::runCMake()
{
BuildDirParameters parameters(cmakeBuildConfiguration());
qCDebug(cmakeBuildSystemLog) << "Requesting parse due \"Run CMake\" command";
- setParametersAndRequestParse(parameters,
- REPARSE_CHECK_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN
- | REPARSE_URGENT);
+ setParametersAndRequestParse(parameters, REPARSE_FORCE_CMAKE_RUN | REPARSE_URGENT);
}
void CMakeBuildSystem::runCMakeAndScanProjectTree()
{
BuildDirParameters parameters(cmakeBuildConfiguration());
qCDebug(cmakeBuildSystemLog) << "Requesting parse due to \"Rescan Project\" command";
- setParametersAndRequestParse(parameters, REPARSE_CHECK_CONFIGURATION | REPARSE_SCAN);
+ setParametersAndRequestParse(parameters,
+ REPARSE_FORCE_CMAKE_RUN | REPARSE_SCAN | REPARSE_URGENT);
+}
+
+void CMakeBuildSystem::runCMakeWithExtraArguments()
+{
+ BuildDirParameters parameters(cmakeBuildConfiguration());
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to \"Rescan Project\" command";
+ setParametersAndRequestParse(parameters,
+ REPARSE_FORCE_CMAKE_RUN | REPARSE_FORCE_EXTRA_CONFIGURATION
+ | REPARSE_URGENT);
}
void CMakeBuildSystem::buildCMakeTarget(const QString &buildTarget)
@@ -445,20 +451,39 @@ void CMakeBuildSystem::handleTreeScanningFinished()
bool CMakeBuildSystem::persistCMakeState()
{
- QTC_ASSERT(m_parameters.isValid(), return false);
+ BuildDirParameters parameters(cmakeBuildConfiguration());
+ QTC_ASSERT(parameters.isValid(), return false);
+
+ parameters.workDirectory = workDirectory(parameters);
+
+ int reparseFlags = REPARSE_DEFAULT;
+ qCDebug(cmakeBuildSystemLog) << "Checking whether build system needs to be persisted:"
+ << "workdir:" << parameters.workDirectory
+ << "buildDir:" << parameters.buildDirectory
+ << "Has extraargs:" << !parameters.extraCMakeArguments.isEmpty()
+ << "must apply extra Args:"
+ << mustApplyExtraArguments();
+
+ if (parameters.workDirectory == parameters.buildDirectory
+ && !parameters.extraCMakeArguments.isEmpty() && mustApplyExtraArguments()) {
+ reparseFlags = REPARSE_FORCE_EXTRA_CONFIGURATION;
+ qCDebug(cmakeBuildSystemLog) << " -> must run CMake with extra arguments.";
+ }
+ if (parameters.workDirectory != parameters.buildDirectory
+ && buildConfiguration()->createBuildDirectory()) {
+ reparseFlags = REPARSE_FORCE_INITIAL_CONFIGURATION;
+ qCDebug(cmakeBuildSystemLog) << " -> must run CMake with initial arguments.";
+ }
- if (m_parameters.workDirectory == m_parameters.buildDirectory)
+ if (reparseFlags == REPARSE_DEFAULT)
return false;
- if (!buildConfiguration()->createBuildDirectory())
- return false;
+ if (reparseFlags == REPARSE_FORCE_INITIAL_CONFIGURATION)
+ parameters.workDirectory.clear();
- BuildDirParameters newParameters = m_parameters;
- newParameters.workDirectory.clear();
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to persisting CMake State";
- setParametersAndRequestParse(newParameters,
- REPARSE_URGENT | REPARSE_FORCE_CMAKE_RUN
- | REPARSE_FORCE_CONFIGURATION | REPARSE_CHECK_CONFIGURATION);
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse to persist CMake State";
+ setParametersAndRequestParse(parameters,
+ REPARSE_URGENT | REPARSE_FORCE_CMAKE_RUN | reparseFlags);
return true;
}
@@ -685,22 +710,20 @@ void CMakeBuildSystem::wireUpConnections(const Project *p)
connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) {
if (k != 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
+ // FIXME: This is no longer correct: QtC now needs to update the initial parameters
+ // FIXME: and then ask to reconfigure.
qCDebug(cmakeBuildSystemLog) << "Requesting parse due to kit being updated";
setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ CMakeBuildSystem::REPARSE_FORCE_CMAKE_RUN);
});
// Became active/inactive:
connect(project(), &Project::activeTargetChanged, this, [this](Target *t) {
if (t == target()) {
- // Build configuration has switched:
- // * Check configuration if reader changes due to it not existing yet:-)
- // * run cmake without configuration arguments if the reader stays
+ // Build configuration has changed along with the target:
qCDebug(cmakeBuildSystemLog) << "Requesting parse due to active target changed";
setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ CMakeBuildSystem::REPARSE_DEFAULT);
} else {
stopParsingAndClearState();
}
@@ -708,12 +731,10 @@ void CMakeBuildSystem::wireUpConnections(const Project *p)
connect(target(), &Target::activeBuildConfigurationChanged, this, [this](BuildConfiguration *bc) {
if (cmakeBuildConfiguration()->isActive()) {
if (cmakeBuildConfiguration() == bc) {
- // Build configuration has switched:
- // * Check configuration if reader changes due to it not existing yet:-)
- // * run cmake without configuration arguments if the reader stays
+ // Build configuration has changed:
qCDebug(cmakeBuildSystemLog) << "Requesting parse due to active BC changed";
setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ CMakeBuildSystem::REPARSE_DEFAULT);
} else {
stopParsingAndClearState();
}
@@ -723,40 +744,22 @@ void CMakeBuildSystem::wireUpConnections(const Project *p)
// BuildConfiguration changed:
connect(cmakeBuildConfiguration(), &CMakeBuildConfiguration::environmentChanged, this, [this]() {
if (cmakeBuildConfiguration()->isActive()) {
- // The environment on our BC has changed:
- // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
- // * run cmake without configuration arguments if the reader stays
+ // The environment on our BC has changed, force CMake run to catch up with possible changes
qCDebug(cmakeBuildSystemLog) << "Requesting parse due to environment change";
setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ CMakeBuildSystem::REPARSE_FORCE_CMAKE_RUN);
}
});
connect(cmakeBuildConfiguration(), &CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() {
if (cmakeBuildConfiguration()->isActive()) {
// The build directory of our BC has changed:
- // * Error out if the reader updates, cannot 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.
+ // Run with initial arguments!
qCDebug(cmakeBuildSystemLog) << "Requesting parse due to build directory change";
setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ CMakeBuildSystem::REPARSE_FORCE_INITIAL_CONFIGURATION
+ | CMakeBuildSystem::REPARSE_FORCE_CMAKE_RUN);
}
});
- connect(cmakeBuildConfiguration(),
- &CMakeBuildConfiguration::configurationForCMakeChanged,
- this,
- [this]() {
- if (cmakeBuildConfiguration()->isActive()) {
- // The CMake configuration has changed on our BC:
- // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
- // * run cmake with configuration arguments if the reader stays
- qCDebug(cmakeBuildSystemLog)
- << "Requesting parse due to cmake configuration change";
- setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- CMakeBuildSystem::REPARSE_FORCE_CONFIGURATION);
- }
- });
connect(project(), &Project::projectFileIsDirty, this, [this]() {
if (cmakeBuildConfiguration()->isActive() && !isParsing()) {
@@ -770,9 +773,11 @@ void CMakeBuildSystem::wireUpConnections(const Project *p)
});
// Force initial parsing run:
- if (cmakeBuildConfiguration()->isActive())
+ if (cmakeBuildConfiguration()->isActive()) {
+ qCDebug(cmakeBuildSystemLog) << "Initial run:";
setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ CMakeBuildSystem::REPARSE_DEFAULT);
+ }
}
FilePath CMakeBuildSystem::workDirectory(const BuildDirParameters &parameters)
@@ -824,8 +829,7 @@ void CMakeBuildSystem::becameDirty()
if (!tool->isAutoRun())
return;
- setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
- REPARSE_CHECK_CONFIGURATION | REPARSE_SCAN);
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()), REPARSE_SCAN);
}
void CMakeBuildSystem::updateReparseParameters(const int parameters)
@@ -840,149 +844,6 @@ int CMakeBuildSystem::takeReparseParameters()
return result;
}
-bool CMakeBuildSystem::hasConfigChanged()
-{
- checkConfiguration();
-
- const QByteArray GENERATOR_KEY = "CMAKE_GENERATOR";
- const QByteArray EXTRA_GENERATOR_KEY = "CMAKE_EXTRA_GENERATOR";
- const QByteArray CMAKE_COMMAND_KEY = "CMAKE_COMMAND";
- const QByteArray CMAKE_C_COMPILER_KEY = "CMAKE_C_COMPILER";
- const QByteArray CMAKE_CXX_COMPILER_KEY = "CMAKE_CXX_COMPILER";
-
- const QByteArrayList criticalKeys = {GENERATOR_KEY,
- CMAKE_COMMAND_KEY,
- CMAKE_C_COMPILER_KEY,
- CMAKE_CXX_COMPILER_KEY};
-
- QString errorMessage;
- const CMakeConfig currentConfig = cmakeBuildConfiguration()->configurationFromCMake();
- if (!errorMessage.isEmpty())
- return false;
-
- 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())
- 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)) {
- clearCMakeCache();
- return false; // no need to trigger a new reader, clearCache will do that
- }
- 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.
- return mustReparse || kcit != targetConfig.constEnd();
-}
-
-bool CMakeBuildSystem::checkConfiguration()
-{
- if (m_parameters.workDirectory
- != m_parameters.buildDirectory) // always throw away changes in the tmpdir!
- return false;
-
- const CMakeConfig cache = cmakeBuildConfiguration()->configurationFromCMake();
- if (cache.isEmpty())
- return false; // No cache file yet.
-
- CMakeConfig newConfig;
- QHash<QString, QPair<QString, QString>> changedKeys;
- foreach (const CMakeConfigItem &projectItem, m_parameters.configuration) {
- const QString projectKey = QString::fromUtf8(projectItem.key);
- const QString projectValue = projectItem.expandedValue(m_parameters.expander);
- const CMakeConfigItem &cmakeItem = Utils::findOrDefault(cache,
- [&projectItem](
- const CMakeConfigItem &i) {
- return i.key == projectItem.key;
- });
- const QString iCacheValue = QString::fromUtf8(cmakeItem.value);
- if (cmakeItem.isNull()) {
- changedKeys.insert(projectKey, qMakePair(tr("<removed>"), projectValue));
- } else if (iCacheValue != projectValue) {
- changedKeys.insert(projectKey, qMakePair(iCacheValue, projectValue));
- newConfig.append(cmakeItem);
- } else {
- newConfig.append(projectItem);
- }
- }
-
- if (!changedKeys.isEmpty()) {
- QStringList keyList = changedKeys.keys();
- Utils::sort(keyList);
- QString table = QString::fromLatin1("<table><tr><th>%1</th><th>%2</th><th>%3</th></tr>")
- .arg(tr("Key"))
- .arg(tr("%1 Project").arg(Core::Constants::IDE_DISPLAY_NAME))
- .arg(tr("Changed value"));
- foreach (const QString &k, keyList) {
- const QPair<QString, QString> data = changedKeys.value(k);
- table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td><td>%3</td></tr>")
- .arg(k)
- .arg(data.second.toHtmlEscaped())
- .arg(data.first.toHtmlEscaped());
- }
- table += QLatin1String("\n</table>");
-
- QPointer<QMessageBox> box = new QMessageBox(Core::ICore::dialogParent());
- box->setText(tr("The project has been changed outside of %1.")
- .arg(Core::Constants::IDE_DISPLAY_NAME));
- box->setInformativeText(table);
- auto *defaultButton = box->addButton(tr("Discard External Changes"),
- QMessageBox::RejectRole);
- auto *applyButton = box->addButton(tr("Adapt %1 Project to Changes")
- .arg(Core::Constants::IDE_DISPLAY_NAME),
- QMessageBox::ApplyRole);
- box->setDefaultButton(defaultButton);
-
- box->exec();
- if (box->clickedButton() == applyButton) {
- m_parameters.configuration = newConfig;
- QSignalBlocker blocker(buildConfiguration());
- cmakeBuildConfiguration()->setConfigurationForCMake(newConfig);
- return false;
- } else if (box->clickedButton() == defaultButton)
- return true;
- }
- return false;
-}
-
CMakeBuildConfiguration *CMakeBuildSystem::cmakeBuildConfiguration() const
{
return static_cast<CMakeBuildConfiguration *>(BuildSystem::buildConfiguration());
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
index 5ada71513c6..86d77d7a7d7 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
@@ -63,7 +63,7 @@ public:
bool supportsAction(ProjectExplorer::Node *context,
ProjectExplorer::ProjectAction action,
- const ProjectExplorer::Node *node) const override;
+ const ProjectExplorer::Node *node) const final;
bool addFiles(ProjectExplorer::Node *context,
const QStringList &filePaths, QStringList *) final;
@@ -73,6 +73,7 @@ public:
// Actions:
void runCMake();
void runCMakeAndScanProjectTree();
+ void runCMakeWithExtraArguments();
bool persistCMakeState();
void clearCMakeCache();
@@ -95,19 +96,20 @@ public:
private:
// Actually ask for parsing:
enum ReparseParameters {
- REPARSE_DEFAULT = 0, // Nothing special:-)
- REPARSE_FORCE_CMAKE_RUN = (1 << 0), // Force cmake to run
- REPARSE_FORCE_CONFIGURATION = (1 << 1), // Force configuration arguments to cmake
- REPARSE_CHECK_CONFIGURATION
- = (1 << 2), // Check for on-disk config and QtC config diff // FIXME: Remove this!
- REPARSE_SCAN = (1 << 3), // Run filesystem scan
- REPARSE_URGENT = (1 << 4), // Do not delay the parser run by 1s
+ REPARSE_DEFAULT = 0, // Nothing special:-)
+ REPARSE_FORCE_CMAKE_RUN
+ = (1 << 0), // Force cmake to run, apply extraCMakeArguments if non-empty
+ REPARSE_FORCE_INITIAL_CONFIGURATION
+ = (1 << 1), // Force initial configuration arguments to cmake
+ REPARSE_FORCE_EXTRA_CONFIGURATION = (1 << 2), // Force extra configuration arguments to cmake
+ REPARSE_SCAN = (1 << 3), // Run filesystem scan
+ REPARSE_URGENT = (1 << 4), // Do not delay the parser run by 1s
};
QString reparseParametersString(int reparseFlags);
void setParametersAndRequestParse(const BuildDirParameters &parameters,
const int reparseParameters);
- void writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander);
+ bool mustApplyExtraArguments() const;
// State handling:
// Parser states:
@@ -155,12 +157,9 @@ private:
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
QList<CMakeBuildTarget> m_buildTargets;
- bool checkConfiguration();
- bool hasConfigChanged();
-
// Parsing state:
BuildDirParameters m_parameters;
- int m_reparseParameters;
+ int m_reparseParameters = REPARSE_DEFAULT;
mutable std::unordered_map<Utils::FilePath, std::unique_ptr<Utils::TemporaryDirectory>>
m_buildDirToTempDir;
FileApiReader m_reader;
diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
index a57d780d453..f979c283f35 100644
--- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
@@ -284,6 +284,54 @@ static QByteArrayList splitCMakeCacheLine(const QByteArray &line) {
<< line.mid(equalPos + 1);
}
+static CMakeConfigItem setItemFromString(const QString &input)
+{
+ return CMakeConfigItem::fromString(input);
+}
+
+static CMakeConfigItem unsetItemFromString(const QString &input)
+{
+ CMakeConfigItem item(input.toUtf8(), QByteArray());
+ item.isUnset = true;
+ return item;
+}
+
+QList<CMakeConfigItem> CMakeConfigItem::itemsFromArguments(const QStringList &list)
+{
+ CMakeConfig result;
+ bool inSet = false;
+ bool inUnset = false;
+ for (const QString &i : list) {
+ if (inSet) {
+ inSet = false;
+ result.append(setItemFromString(i));
+ continue;
+ }
+ if (inUnset) {
+ inUnset = false;
+ result.append(unsetItemFromString(i));
+ continue;
+ }
+ if (i == "-U") {
+ inUnset = true;
+ continue;
+ }
+ if (i == "-D") {
+ inSet = true;
+ continue;
+ }
+ if (i.startsWith("-U")) {
+ result.append(unsetItemFromString(i.mid(2)));
+ continue;
+ }
+ if (i.startsWith("-D")) {
+ result.append(setItemFromString(i.mid(2)));
+ }
+ // ignore everything else as that does not define a configuration option
+ }
+ return result;
+}
+
QList<CMakeConfigItem> CMakeConfigItem::itemsFromFile(const Utils::FilePath &cacheFile, QString *errorMessage)
{
CMakeConfig result;
diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
index c99f1e64f7e..10c7651f6f7 100644
--- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
+++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
@@ -64,6 +64,7 @@ public:
static std::function<bool(const CMakeConfigItem &a, const CMakeConfigItem &b)> sortOperator();
static CMakeConfigItem fromString(const QString &s);
+ static QList<CMakeConfigItem> itemsFromArguments(const QStringList &list);
static QList<CMakeConfigItem> itemsFromFile(const Utils::FilePath &input, QString *errorMessage);
QString toString(const Utils::MacroExpander *expander = nullptr) const;
QString toArgument(const Utils::MacroExpander *expander = nullptr) const;
diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
index 89ab5a9aab0..86c9f8114b2 100644
--- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
@@ -974,6 +974,12 @@ void CMakeConfigurationKitAspect::fromStringList(Kit *k, const QStringList &in)
setConfiguration(k, result);
}
+QStringList CMakeConfigurationKitAspect::toArgumentsList(const Kit *k)
+{
+ return Utils::transform(CMakeConfigurationKitAspect::configuration(k),
+ [](const CMakeConfigItem &i) { return i.toArgument(nullptr); });
+}
+
CMakeConfig CMakeConfigurationKitAspect::defaultConfiguration(const Kit *k)
{
Q_UNUSED(k)
diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.h b/src/plugins/cmakeprojectmanager/cmakekitinformation.h
index f2579f3282c..fd6af308cff 100644
--- a/src/plugins/cmakeprojectmanager/cmakekitinformation.h
+++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.h
@@ -101,6 +101,8 @@ public:
static QStringList toStringList(const ProjectExplorer::Kit *k);
static void fromStringList(ProjectExplorer::Kit *k, const QStringList &in);
+ static QStringList toArgumentsList(const ProjectExplorer::Kit *k);
+
static CMakeConfig defaultConfiguration(const ProjectExplorer::Kit *k);
// KitAspect interface
diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
index e500ac8c2ec..ba6b582896a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
@@ -113,11 +113,7 @@ void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &
connect(process.get(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &CMakeProcess::handleProcessFinished);
- QStringList args;
- args += parameters.generatorArguments;
- args += arguments;
- args += srcDir;
- Utils::CommandLine commandLine(cmake->cmakeExecutable(), args);
+ Utils::CommandLine commandLine(cmake->cmakeExecutable(), QStringList({"-S", srcDir, QString("-B"), workDirectory.toString()}) + arguments);
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp
index b6134b14fa0..c0f075fda6b 100644
--- a/src/plugins/cmakeprojectmanager/configmodel.cpp
+++ b/src/plugins/cmakeprojectmanager/configmodel.cpp
@@ -96,24 +96,6 @@ void ConfigModel::setConfigurationFromKit(const QHash<QString, QString> &kitConf
setConfiguration(m_configuration);
}
-void ConfigModel::setConfigurationForCMake(const QHash<QString, QString> &config)
-{
- for (InternalDataItem &i : m_configuration) {
- if (!config.contains(i.key))
- continue;
-
- const QString v = config.value(i.key);
- if (i.value == v) {
- i.newValue.clear();
- i.isUserChanged = false;
- } else {
- i.newValue = v;
- i.isUserChanged = true;
- }
- }
- setConfiguration(m_configuration);
-}
-
void ConfigModel::flush()
{
setConfiguration(QList<InternalDataItem>());
diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h
index 5844c388f96..7c5cfa205b1 100644
--- a/src/plugins/cmakeprojectmanager/configmodel.h
+++ b/src/plugins/cmakeprojectmanager/configmodel.h
@@ -72,7 +72,7 @@ public:
void setConfiguration(const CMakeConfig &config);
void setConfiguration(const QList<DataItem> &config);
void setConfigurationFromKit(const QHash<QString, QString> &kitConfig);
- void setConfigurationForCMake(const QHash<QString, QString> &config);
+
void flush();
void resetAllChanges();
diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp
index 5b252f62978..1e25125a80a 100644
--- a/src/plugins/cmakeprojectmanager/fileapireader.cpp
+++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp
@@ -99,47 +99,63 @@ void FileApiReader::resetData()
m_knownHeaders.clear();
}
-void FileApiReader::parse(bool forceCMakeRun, bool forceConfiguration)
+void FileApiReader::parse(bool forceCMakeRun,
+ bool forceInitialConfiguration,
+ bool forceExtraConfiguration)
{
qCDebug(cmakeFileApiMode) << "Parse called with arguments: ForceCMakeRun:" << forceCMakeRun
- << " - forceConfiguration:" << forceConfiguration;
+ << " - forceConfiguration:" << forceInitialConfiguration
+ << " - forceExtraConfiguration:" << forceExtraConfiguration;
startState();
- if (forceConfiguration) {
- // Initial create:
- qCDebug(cmakeFileApiMode) << "FileApiReader: Starting CMake with forced configuration.";
- const FilePath path = m_parameters.workDirectory.pathAppended("qtcsettings.cmake");
- startCMakeState(QStringList({QString("-C"), path.toUserOutput()}));
- // Keep m_isParsing enabled!
- return;
- }
+ const QStringList args = (forceInitialConfiguration ? m_parameters.initialCMakeArguments
+ : QStringList())
+ + (forceExtraConfiguration ? m_parameters.extraCMakeArguments
+ : QStringList());
+ qCDebug(cmakeFileApiMode) << "Parameters request these CMake arguments:" << args;
const QFileInfo replyFi = FileApiParser::scanForCMakeReplyFile(m_parameters.workDirectory);
// Only need to update when one of the following conditions is met:
- // * The user forces the update,
+ // * The user forces the cmake run,
+ // * The user provided arguments,
// * There is no reply file,
// * One of the cmakefiles is newer than the replyFile and the user asked
// for creator to run CMake as needed,
// * A query file is newer than the reply file
- const bool mustUpdate = forceCMakeRun || !replyFi.exists()
- || (m_parameters.cmakeTool() && m_parameters.cmakeTool()->isAutoRun()
- && anyOf(m_cmakeFiles,
- [&replyFi](const FilePath &f) {
- return f.toFileInfo().lastModified()
- > replyFi.lastModified();
- }))
- || anyOf(FileApiParser::cmakeQueryFilePaths(m_parameters.workDirectory), [&replyFi](const QString &qf) {
- return QFileInfo(qf).lastModified() > replyFi.lastModified();
- });
+ const bool hasArguments = !args.isEmpty();
+ const bool replyFileMissing = !replyFi.exists();
+ const bool cmakeFilesChanged = m_parameters.cmakeTool() && m_parameters.cmakeTool()->isAutoRun()
+ && anyOf(m_cmakeFiles, [&replyFi](const FilePath &f) {
+ return f.toFileInfo().lastModified()
+ > replyFi.lastModified();
+ });
+ const bool queryFileChanged = anyOf(FileApiParser::cmakeQueryFilePaths(
+ m_parameters.workDirectory),
+ [&replyFi](const QString &qf) {
+ return QFileInfo(qf).lastModified()
+ > replyFi.lastModified();
+ });
+
+ const bool mustUpdate = forceCMakeRun || hasArguments || replyFileMissing || cmakeFilesChanged
+ || queryFileChanged;
+ qCDebug(cmakeFileApiMode) << QString("Do I need to run CMake? %1 "
+ "(force: %2 | args: %3 | missing reply: %4 | "
+ "cmakeFilesChanged: %5 | "
+ "queryFileChanged: %6)")
+ .arg(mustUpdate)
+ .arg(forceCMakeRun)
+ .arg(hasArguments)
+ .arg(replyFileMissing)
+ .arg(cmakeFilesChanged)
+ .arg(queryFileChanged);
if (mustUpdate) {
- qCDebug(cmakeFileApiMode) << "FileApiReader: Starting CMake with no arguments.";
- startCMakeState(QStringList());
- // Keep m_isParsing enabled!
- return;
+ qCDebug(cmakeFileApiMode) << QString("FileApiReader: Starting CMake with \"%1\".")
+ .arg(args.join("\", \""));
+ startCMakeState(args);
+ } else {
+ endState(replyFi);
}
-
- endState(replyFi);
}
void FileApiReader::stop()
diff --git a/src/plugins/cmakeprojectmanager/fileapireader.h b/src/plugins/cmakeprojectmanager/fileapireader.h
index 2319010aa46..0b578511ecb 100644
--- a/src/plugins/cmakeprojectmanager/fileapireader.h
+++ b/src/plugins/cmakeprojectmanager/fileapireader.h
@@ -58,7 +58,7 @@ public:
void setParameters(const BuildDirParameters &p);
void resetData();
- void parse(bool forceCMakeRun, bool forceConfiguration);
+ void parse(bool forceCMakeRun, bool forceInitialConfiguration, bool forceExtraConfiguration);
void stop();
bool isParsing() const;
diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h
index af69ca29e48..5d38e8300c2 100644
--- a/src/plugins/projectexplorer/buildsystem.h
+++ b/src/plugins/projectexplorer/buildsystem.h
@@ -42,6 +42,7 @@ class Node;
// BuildSystem:
// --------------------------------------------------------------------
+// Check buildsystem.md for more information
class PROJECTEXPLORER_EXPORT BuildSystem : public QObject
{
Q_OBJECT