forked from qt-creator/qt-creator
CMakePM: Add support for configure CMake presets
This patchset will add support for version 1 of the CMakePresets feature that has been implemented in CMake 3.19 https://cmake.org/cmake/help/v3.19/manual/cmake-presets.7.html The tests/manual/cmakepresets contains a manual test example for this feature. Task-number: QTCREATORBUG-24555 Change-Id: I93aba1ab4f090613d0b21d970b5b651d12c922af Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
281
src/plugins/cmakeprojectmanager/presetsparser.cpp
Normal file
281
src/plugins/cmakeprojectmanager/presetsparser.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "presetsparser.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
bool parseVersion(const QJsonValue &jsonValue, int &version)
|
||||
{
|
||||
if (jsonValue.isNull())
|
||||
return false;
|
||||
|
||||
const int invalidVersion = -1;
|
||||
version = jsonValue.toInt(invalidVersion);
|
||||
return version != invalidVersion;
|
||||
}
|
||||
|
||||
bool parseCMakeMinimumRequired(const QJsonValue &jsonValue, QVersionNumber &versionNumber)
|
||||
{
|
||||
if (jsonValue.isNull() || !jsonValue.isObject())
|
||||
return false;
|
||||
|
||||
QJsonObject object = jsonValue.toObject();
|
||||
versionNumber = QVersionNumber(object.value("major").toInt(),
|
||||
object.value("minor").toInt(),
|
||||
object.value("patch").toInt());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseConfigurePresets(const QJsonValue &jsonValue,
|
||||
std::vector<PresetsDetails::ConfigurePreset> &configurePresets)
|
||||
{
|
||||
// The whole section is optional
|
||||
if (jsonValue.isNull())
|
||||
return true;
|
||||
|
||||
if (!jsonValue.isArray())
|
||||
return false;
|
||||
|
||||
const QJsonArray configurePresetsArray = jsonValue.toArray();
|
||||
for (const QJsonValue &presetJson : configurePresetsArray) {
|
||||
if (!presetJson.isObject())
|
||||
continue;
|
||||
|
||||
QJsonObject object = presetJson.toObject();
|
||||
PresetsDetails::ConfigurePreset preset;
|
||||
|
||||
preset.name = object.value("name").toString();
|
||||
preset.hidden = object.value("hidden").toBool();
|
||||
|
||||
QJsonValue inherits = object.value("inherits");
|
||||
if (!inherits.isNull()) {
|
||||
preset.inherits = QStringList();
|
||||
if (inherits.isArray()) {
|
||||
const QJsonArray inheritsArray = inherits.toArray();
|
||||
for (const QJsonValue &inheritsValue : inheritsArray)
|
||||
preset.inherits.value() << inheritsValue.toString();
|
||||
} else {
|
||||
QString inheritsValue = inherits.toString();
|
||||
if (!inheritsValue.isEmpty())
|
||||
preset.inherits.value() << inheritsValue;
|
||||
}
|
||||
}
|
||||
if (object.contains("displayName"))
|
||||
preset.displayName = object.value("displayName").toString();
|
||||
if (object.contains("description"))
|
||||
preset.description = object.value("description").toString();
|
||||
if (object.contains("generator"))
|
||||
preset.generator = object.value("generator").toString();
|
||||
if (object.contains("binaryDir"))
|
||||
preset.binaryDir = object.value("binaryDir").toString();
|
||||
if (object.contains("cmakeExecutable"))
|
||||
preset.cmakeExecutable = object.value("cmakeExecutable").toString();
|
||||
|
||||
const QJsonObject cacheVariablesObj = object.value("cacheVariables").toObject();
|
||||
for (const QString &cacheKey : cacheVariablesObj.keys()) {
|
||||
if (!preset.cacheVariables)
|
||||
preset.cacheVariables = CMakeConfig();
|
||||
|
||||
QJsonValue cacheValue = cacheVariablesObj.value(cacheKey);
|
||||
if (cacheValue.isObject()) {
|
||||
QJsonObject cacheVariableObj = cacheValue.toObject();
|
||||
CMakeConfigItem item;
|
||||
item.key = cacheKey.toUtf8();
|
||||
item.type = CMakeConfigItem::typeStringToType(
|
||||
cacheVariableObj.value("type").toString().toUtf8());
|
||||
item.value = cacheVariableObj.value("type").toString().toUtf8();
|
||||
preset.cacheVariables.value() << item;
|
||||
|
||||
} else {
|
||||
preset.cacheVariables.value()
|
||||
<< CMakeConfigItem(cacheKey.toUtf8(), cacheValue.toString().toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
const QJsonObject environmentObj = object.value("environment").toObject();
|
||||
for (const QString &envKey : environmentObj.keys()) {
|
||||
if (!preset.environment)
|
||||
preset.environment = QHash<QString, QString>();
|
||||
|
||||
QJsonValue envValue = environmentObj.value(envKey);
|
||||
preset.environment.value().insert(envKey, envValue.toString());
|
||||
}
|
||||
|
||||
const QJsonObject warningsObj = object.value("warnings").toObject();
|
||||
if (!warningsObj.isEmpty()) {
|
||||
preset.warnings = PresetsDetails::Warnings();
|
||||
|
||||
if (warningsObj.contains("dev"))
|
||||
preset.warnings->dev = warningsObj.value("dev").toBool();
|
||||
if (warningsObj.contains("deprecated"))
|
||||
preset.warnings->deprecated = warningsObj.value("deprecated").toBool();
|
||||
if (warningsObj.contains("uninitialized"))
|
||||
preset.warnings->uninitialized = warningsObj.value("uninitialized").toBool();
|
||||
if (warningsObj.contains("unusedCli"))
|
||||
preset.warnings->unusedCli = warningsObj.value("unusedCli").toBool();
|
||||
if (warningsObj.contains("systemVars"))
|
||||
preset.warnings->systemVars = warningsObj.value("systemVars").toBool();
|
||||
}
|
||||
|
||||
const QJsonObject errorsObj = object.value("errors").toObject();
|
||||
if (!errorsObj.isEmpty()) {
|
||||
preset.errors = PresetsDetails::Errors();
|
||||
|
||||
if (errorsObj.contains("dev"))
|
||||
preset.errors->dev = errorsObj.value("dev").toBool();
|
||||
if (errorsObj.contains("deprecated"))
|
||||
preset.errors->deprecated = errorsObj.value("deprecated").toBool();
|
||||
}
|
||||
|
||||
const QJsonObject debugObj = object.value("debug").toObject();
|
||||
if (!debugObj.isEmpty()) {
|
||||
preset.debug = PresetsDetails::Debug();
|
||||
|
||||
if (debugObj.contains("output"))
|
||||
preset.debug->output = debugObj.value("output").toBool();
|
||||
if (debugObj.contains("tryCompile"))
|
||||
preset.debug->tryCompile = debugObj.value("tryCompile").toBool();
|
||||
if (debugObj.contains("find"))
|
||||
preset.debug->find = debugObj.value("find").toBool();
|
||||
}
|
||||
|
||||
const QJsonObject architectureObj = object.value("architecture").toObject();
|
||||
if (!architectureObj.isEmpty()) {
|
||||
preset.architecture = PresetsDetails::ValueStrategyPair();
|
||||
|
||||
if (architectureObj.contains("value"))
|
||||
preset.architecture->value = architectureObj.value("value").toString();
|
||||
if (architectureObj.contains("strategy")) {
|
||||
const QString strategy = architectureObj.value("strategy").toString();
|
||||
if (strategy == "set")
|
||||
preset.architecture->strategy = PresetsDetails::ValueStrategyPair::Strategy::set;
|
||||
if (strategy == "external")
|
||||
preset.architecture->strategy
|
||||
= PresetsDetails::ValueStrategyPair::Strategy::external;
|
||||
}
|
||||
}
|
||||
|
||||
const QJsonObject toolsetObj = object.value("toolset").toObject();
|
||||
if (!toolsetObj.isEmpty()) {
|
||||
preset.toolset = PresetsDetails::ValueStrategyPair();
|
||||
|
||||
if (toolsetObj.contains("value"))
|
||||
preset.toolset->value = toolsetObj.value("value").toString();
|
||||
if (toolsetObj.contains("strategy")) {
|
||||
const QString strategy = toolsetObj.value("strategy").toString();
|
||||
if (strategy == "set")
|
||||
preset.toolset->strategy = PresetsDetails::ValueStrategyPair::Strategy::set;
|
||||
if (strategy == "external")
|
||||
preset.toolset->strategy = PresetsDetails::ValueStrategyPair::Strategy::external;
|
||||
}
|
||||
}
|
||||
|
||||
configurePresets.emplace_back(preset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const PresetsData &PresetsParser::presetsData() const
|
||||
{
|
||||
return m_presetsData;
|
||||
}
|
||||
|
||||
bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage, int &errorLine)
|
||||
{
|
||||
const std::optional<QByteArray> jsonContents = jsonFile.fileContents();
|
||||
if (!jsonContents) {
|
||||
errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal",
|
||||
"Failed to read %1 file")
|
||||
.arg(jsonFile.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonParseError error;
|
||||
const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonContents.value(), &error);
|
||||
if (jsonDoc.isNull()) {
|
||||
errorLine = 1;
|
||||
for (int i = 0; i < error.offset; ++i)
|
||||
if (jsonContents.value().at(i) == '\n')
|
||||
++errorLine;
|
||||
errorMessage = error.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!jsonDoc.isObject()) {
|
||||
errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal",
|
||||
"Invalid %1 file")
|
||||
.arg(jsonFile.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject root = jsonDoc.object();
|
||||
|
||||
if (!parseVersion(root.value("version"), m_presetsData.version)) {
|
||||
errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal",
|
||||
"Invalid \"version\" in %1 file")
|
||||
.arg(jsonFile.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// optional
|
||||
parseCMakeMinimumRequired(root.value("cmakeMinimumRequired"),
|
||||
m_presetsData.cmakeMinimimRequired);
|
||||
|
||||
// optional
|
||||
if (!parseConfigurePresets(root.value("configurePresets"), m_presetsData.configurePresets)) {
|
||||
errorMessage = QCoreApplication::translate(
|
||||
"CMakeProjectManager::Internal",
|
||||
"Invalid \"configurePresets\" section in %1 file").arg(jsonFile.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PresetsDetails::ConfigurePreset::inheritFrom(const ConfigurePreset &other)
|
||||
{
|
||||
if (!vendor && other.vendor)
|
||||
vendor = other.vendor;
|
||||
|
||||
if (!generator && other.generator)
|
||||
generator = other.generator;
|
||||
|
||||
if (!architecture && other.architecture)
|
||||
architecture = other.architecture;
|
||||
|
||||
if (!toolset && other.toolset)
|
||||
toolset = other.toolset;
|
||||
|
||||
if (!binaryDir && other.binaryDir)
|
||||
binaryDir = other.binaryDir;
|
||||
|
||||
if (!cmakeExecutable && other.cmakeExecutable)
|
||||
cmakeExecutable = other.cmakeExecutable;
|
||||
|
||||
if (!cacheVariables && other.cacheVariables)
|
||||
cacheVariables = other.cacheVariables;
|
||||
|
||||
if (!environment && other.environment)
|
||||
environment = other.environment;
|
||||
|
||||
if (!warnings && other.warnings)
|
||||
warnings = other.warnings;
|
||||
|
||||
if (!errors && other.errors)
|
||||
errors = other.errors;
|
||||
|
||||
if (!debug && other.debug)
|
||||
debug = other.debug;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CMakeProjectManager
|
||||
Reference in New Issue
Block a user