forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
CMakeConfig configuration;
|
||||
|
||||
QString generator;
|
||||
QString extraGenerator;
|
||||
QString platform;
|
||||
QString toolset;
|
||||
QStringList generatorArguments;
|
||||
QStringList initialCMakeArguments;
|
||||
QStringList extraCMakeArguments;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -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()});
|
||||
const Kit *k = target->kit();
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
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,53 +276,33 @@ CMakeConfig CMakeBuildConfiguration::configurationFromCMake() const
|
||||
return m_configurationFromCMake;
|
||||
}
|
||||
|
||||
QStringList CMakeBuildConfiguration::extraCMakeArguments() const
|
||||
{
|
||||
return m_extraCMakeArguments;
|
||||
}
|
||||
|
||||
QStringList CMakeBuildConfiguration::initialCMakeArguments() const
|
||||
{
|
||||
return aspect<InitialCMakeArgumentsAspect>()->value().split('\n', Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::setExtraCMakeArguments(const QStringList &args)
|
||||
{
|
||||
if (m_extraCMakeArguments == args)
|
||||
return;
|
||||
|
||||
qCDebug(cmakeBuildConfigurationLog)
|
||||
<< "Extra Args changed from" << m_extraCMakeArguments << "to" << args << "...";
|
||||
m_extraCMakeArguments = args;
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &config)
|
||||
{
|
||||
m_configurationFromCMake = config;
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::DataItem> &items)
|
||||
{
|
||||
const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) {
|
||||
CMakeConfigItem ni;
|
||||
ni.key = i.key.toUtf8();
|
||||
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;
|
||||
});
|
||||
|
||||
const CMakeConfig config = configurationForCMake() + newConfig;
|
||||
setConfigurationForCMake(config);
|
||||
|
||||
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()});
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
CMakeConfig changedConfig;
|
||||
|
||||
for (const CMakeConfigItem &item : configList) {
|
||||
if (!cxxFlags.contains(item.key))
|
||||
continue;
|
||||
|
||||
CMakeConfigItem it(item);
|
||||
|
||||
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;
|
||||
}
|
||||
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 ¤t, const QModelIndex &previous)
|
||||
|
||||
@@ -68,7 +68,6 @@ private:
|
||||
void updateFromKit();
|
||||
void handleQmlDebugCxxFlags();
|
||||
|
||||
void setConfigurationForCMake();
|
||||
void updateSelection(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
QAction *createForceAction(int type, const QModelIndex &idx);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
m_waitingForScan = (m_reparseParameters | REPARSE_SCAN) != 0;
|
||||
int reparseParameters = takeReparseParameters();
|
||||
|
||||
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 ¶meters,
|
||||
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 );
|
||||
if (m_parameters.extraCMakeArguments.isEmpty())
|
||||
return false;
|
||||
|
||||
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());
|
||||
|
||||
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);
|
||||
|
||||
if (m_parameters.workDirectory == m_parameters.buildDirectory)
|
||||
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 (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 ¶meters)
|
||||
@@ -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());
|
||||
|
||||
@@ -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 ¶meters,
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -113,11 +113,7 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, 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);
|
||||
|
||||
|
||||
@@ -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>());
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -42,6 +42,7 @@ class Node;
|
||||
// BuildSystem:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Check buildsystem.md for more information
|
||||
class PROJECTEXPLORER_EXPORT BuildSystem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Reference in New Issue
Block a user