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:
@@ -35,5 +35,7 @@ add_qtc_plugin(CMakeProjectManager
|
|||||||
fileapidataextractor.cpp fileapidataextractor.h
|
fileapidataextractor.cpp fileapidataextractor.h
|
||||||
fileapiparser.cpp fileapiparser.h
|
fileapiparser.cpp fileapiparser.h
|
||||||
fileapireader.cpp fileapireader.h
|
fileapireader.cpp fileapireader.h
|
||||||
|
presetsparser.cpp presetsparser.h
|
||||||
|
presetsmacros.cpp presetsmacros.h
|
||||||
projecttreehelper.cpp projecttreehelper.h
|
projecttreehelper.cpp projecttreehelper.h
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,12 +8,15 @@
|
|||||||
#include "cmakebuildsystem.h"
|
#include "cmakebuildsystem.h"
|
||||||
#include "cmakeconfigitem.h"
|
#include "cmakeconfigitem.h"
|
||||||
#include "cmakekitinformation.h"
|
#include "cmakekitinformation.h"
|
||||||
|
#include "cmakeproject.h"
|
||||||
#include "cmakeprojectconstants.h"
|
#include "cmakeprojectconstants.h"
|
||||||
#include "cmakeprojectplugin.h"
|
#include "cmakeprojectplugin.h"
|
||||||
#include "cmakespecificsettings.h"
|
#include "cmakespecificsettings.h"
|
||||||
#include "configmodel.h"
|
#include "configmodel.h"
|
||||||
#include "configmodelitemdelegate.h"
|
#include "configmodelitemdelegate.h"
|
||||||
#include "fileapiparser.h"
|
#include "fileapiparser.h"
|
||||||
|
#include "presetsmacros.h"
|
||||||
|
#include "presetsparser.h"
|
||||||
|
|
||||||
#include <android/androidconstants.h>
|
#include <android/androidconstants.h>
|
||||||
#include <docker/dockerconstants.h>
|
#include <docker/dockerconstants.h>
|
||||||
@@ -1163,6 +1166,164 @@ static CommandLine defaultInitialCMakeCommand(const Kit *k, const QString buildT
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArguments,
|
||||||
|
const CMakeProject *project,
|
||||||
|
const Kit *k,
|
||||||
|
const Utils::Environment &env)
|
||||||
|
|
||||||
|
{
|
||||||
|
const CMakeConfigItem presetItem = CMakeConfigurationKitAspect::cmakePresetConfigItem(k);
|
||||||
|
if (presetItem.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Remove the -DQTC_CMAKE_PRESET argument, which is only used as a kit marker
|
||||||
|
const QString presetArgument = presetItem.toArgument();
|
||||||
|
const QString presetName = presetItem.expandedValue(k);
|
||||||
|
initialArguments.removeIf(
|
||||||
|
[presetArgument](const QString &item) { return item == presetArgument; });
|
||||||
|
|
||||||
|
PresetsDetails::ConfigurePreset configurePreset
|
||||||
|
= Utils::findOrDefault(project->presetsData().configurePresets,
|
||||||
|
[presetName](const PresetsDetails::ConfigurePreset &preset) {
|
||||||
|
return preset.name == presetName;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the command line arguments
|
||||||
|
if (configurePreset.warnings) {
|
||||||
|
if (configurePreset.warnings.value().dev) {
|
||||||
|
bool value = configurePreset.warnings.value().dev.value();
|
||||||
|
initialArguments.append(value ? QString("-Wdev") : QString("-Wno-dev"));
|
||||||
|
}
|
||||||
|
if (configurePreset.warnings.value().deprecated) {
|
||||||
|
bool value = configurePreset.warnings.value().deprecated.value();
|
||||||
|
initialArguments.append(value ? QString("-Wdeprecated") : QString("-Wno-deprecated"));
|
||||||
|
}
|
||||||
|
if (configurePreset.warnings.value().uninitialized
|
||||||
|
&& configurePreset.warnings.value().uninitialized.value())
|
||||||
|
initialArguments.append("--warn-uninitialized");
|
||||||
|
if (configurePreset.warnings.value().unusedCli
|
||||||
|
&& !configurePreset.warnings.value().unusedCli.value())
|
||||||
|
initialArguments.append(" --no-warn-unused-cli");
|
||||||
|
if (configurePreset.warnings.value().systemVars
|
||||||
|
&& configurePreset.warnings.value().systemVars.value())
|
||||||
|
initialArguments.append("--check-system-vars");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurePreset.errors) {
|
||||||
|
if (configurePreset.errors.value().dev) {
|
||||||
|
bool value = configurePreset.errors.value().dev.value();
|
||||||
|
initialArguments.append(value ? QString("-Werror=dev") : QString("-Wno-error=dev"));
|
||||||
|
}
|
||||||
|
if (configurePreset.errors.value().deprecated) {
|
||||||
|
bool value = configurePreset.errors.value().deprecated.value();
|
||||||
|
initialArguments.append(value ? QString("-Werror=deprecated")
|
||||||
|
: QString("-Wno-error=deprecated"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurePreset.debug) {
|
||||||
|
if (configurePreset.debug.value().find && configurePreset.debug.value().find.value())
|
||||||
|
initialArguments.append("--debug-find");
|
||||||
|
if (configurePreset.debug.value().tryCompile
|
||||||
|
&& configurePreset.debug.value().tryCompile.value())
|
||||||
|
initialArguments.append("--debug-trycompile");
|
||||||
|
if (configurePreset.debug.value().output && configurePreset.debug.value().output.value())
|
||||||
|
initialArguments.append("--debug-output");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the presets cache variables
|
||||||
|
CMakeConfig cache;
|
||||||
|
if (configurePreset.cacheVariables)
|
||||||
|
cache = configurePreset.cacheVariables.value();
|
||||||
|
|
||||||
|
for (const CMakeConfigItem &presetItemRaw : cache) {
|
||||||
|
|
||||||
|
// Expand the CMakePresets Macros
|
||||||
|
CMakeConfigItem presetItem(presetItemRaw);
|
||||||
|
|
||||||
|
QString presetItemValue = QString::fromUtf8(presetItem.value);
|
||||||
|
CMakePresets::Macros::expand(configurePreset, env, project->projectDirectory(), presetItemValue);
|
||||||
|
presetItem.value = presetItemValue.toUtf8();
|
||||||
|
|
||||||
|
const QString presetItemArg = presetItem.toArgument();
|
||||||
|
const QString presetItemArgNoType = presetItemArg.left(presetItemArg.indexOf(":"));
|
||||||
|
|
||||||
|
auto it = std::find_if(initialArguments.begin(),
|
||||||
|
initialArguments.end(),
|
||||||
|
[presetItemArgNoType](const QString &arg) {
|
||||||
|
return arg.startsWith(presetItemArgNoType);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != initialArguments.end()) {
|
||||||
|
QString &arg = *it;
|
||||||
|
CMakeConfigItem argItem = CMakeConfigItem::fromString(arg.mid(2)); // skip -D
|
||||||
|
|
||||||
|
// For multi value path variables append the non Qt path
|
||||||
|
if (argItem.key == "CMAKE_PREFIX_PATH" || argItem.key == "CMAKE_FIND_ROOT_PATH") {
|
||||||
|
QStringList presetValueList = presetItem.expandedValue(k).split(";");
|
||||||
|
|
||||||
|
// Remove the expanded Qt path from the presets values
|
||||||
|
QString argItemExpandedValue = argItem.expandedValue(k);
|
||||||
|
presetValueList.removeIf([argItemExpandedValue](const QString &presetPath) {
|
||||||
|
QStringList argItemPaths = argItemExpandedValue.split(";");
|
||||||
|
for (const QString &argPath : argItemPaths) {
|
||||||
|
const FilePath argFilePath = FilePath::fromString(argPath);
|
||||||
|
const FilePath presetFilePath = FilePath::fromString(presetPath);
|
||||||
|
|
||||||
|
if (argFilePath == presetFilePath)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the presets values to the final argument
|
||||||
|
for (const QString &presetPath : presetValueList) {
|
||||||
|
argItem.value.append(";");
|
||||||
|
argItem.value.append(presetPath.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = argItem.toArgument();
|
||||||
|
} else if (argItem.key == "CMAKE_C_COMPILER" || argItem.key == "CMAKE_CXX_COMPILER"
|
||||||
|
|| argItem.key == "QT_QMAKE_EXECUTABLE" || argItem.key == "QT_HOST_PATH"
|
||||||
|
|| argItem.key == "CMAKE_PROJECT_INCLUDE_BEFORE"
|
||||||
|
|| argItem.key == "CMAKE_TOOLCHAIN_FILE") {
|
||||||
|
const FilePath argFilePath = FilePath::fromString(argItem.expandedValue(k));
|
||||||
|
const FilePath presetFilePath = FilePath::fromUtf8(presetItem.value);
|
||||||
|
|
||||||
|
if (argFilePath != presetFilePath)
|
||||||
|
arg = presetItem.toArgument();
|
||||||
|
} else if (argItem.expandedValue(k) != QString::fromUtf8(presetItem.value)) {
|
||||||
|
arg = presetItem.toArgument();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
initialArguments.append(presetItem.toArgument());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Utils::EnvironmentItems getEnvironmentItemsFromCMakePreset(const CMakeProject *project,
|
||||||
|
const Kit *k)
|
||||||
|
|
||||||
|
{
|
||||||
|
Utils::EnvironmentItems envItems;
|
||||||
|
|
||||||
|
const CMakeConfigItem presetItem = CMakeConfigurationKitAspect::cmakePresetConfigItem(k);
|
||||||
|
if (presetItem.isNull())
|
||||||
|
return envItems;
|
||||||
|
|
||||||
|
const QString presetName = presetItem.expandedValue(k);
|
||||||
|
|
||||||
|
PresetsDetails::ConfigurePreset configurePreset
|
||||||
|
= Utils::findOrDefault(project->presetsData().configurePresets,
|
||||||
|
[presetName](const PresetsDetails::ConfigurePreset &preset) {
|
||||||
|
return preset.name == presetName;
|
||||||
|
});
|
||||||
|
|
||||||
|
CMakePresets::Macros::expand(configurePreset, envItems, project->projectDirectory());
|
||||||
|
|
||||||
|
return envItems;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// CMakeBuildConfigurationPrivate:
|
// CMakeBuildConfigurationPrivate:
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -1365,7 +1526,15 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id)
|
|||||||
if (qt && qt->isQmlDebuggingSupported())
|
if (qt && qt->isQmlDebuggingSupported())
|
||||||
cmd.addArg("-DCMAKE_CXX_FLAGS_INIT:STRING=%{" + QLatin1String(QT_QML_DEBUG_FLAG) + "}");
|
cmd.addArg("-DCMAKE_CXX_FLAGS_INIT:STRING=%{" + QLatin1String(QT_QML_DEBUG_FLAG) + "}");
|
||||||
|
|
||||||
m_buildSystem->setInitialCMakeArguments(cmd.splitArguments());
|
CMakeProject *cmakeProject = static_cast<CMakeProject *>(target->project());
|
||||||
|
setUserConfigureEnvironmentChanges(getEnvironmentItemsFromCMakePreset(cmakeProject, k));
|
||||||
|
|
||||||
|
QStringList initialCMakeArguments = cmd.splitArguments();
|
||||||
|
addCMakeConfigurePresetToInitialArguments(initialCMakeArguments,
|
||||||
|
cmakeProject,
|
||||||
|
k,
|
||||||
|
configureEnvironment());
|
||||||
|
m_buildSystem->setInitialCMakeArguments(initialCMakeArguments);
|
||||||
m_buildSystem->setCMakeBuildType(buildType);
|
m_buildSystem->setCMakeBuildType(buildType);
|
||||||
updateAndEmitConfigureEnvironmentChanged();
|
updateAndEmitConfigureEnvironmentChanged();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (C) 2016 Canonical Ltd.
|
// Copyright (C) 2016 Canonical Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "cmakeconfigitem.h"
|
||||||
#include "cmakekitinformation.h"
|
#include "cmakekitinformation.h"
|
||||||
|
|
||||||
#include "cmakeprojectconstants.h"
|
#include "cmakeprojectconstants.h"
|
||||||
@@ -875,6 +876,7 @@ const char CMAKE_C_TOOLCHAIN_KEY[] = "CMAKE_C_COMPILER";
|
|||||||
const char CMAKE_CXX_TOOLCHAIN_KEY[] = "CMAKE_CXX_COMPILER";
|
const char CMAKE_CXX_TOOLCHAIN_KEY[] = "CMAKE_CXX_COMPILER";
|
||||||
const char CMAKE_QMAKE_KEY[] = "QT_QMAKE_EXECUTABLE";
|
const char CMAKE_QMAKE_KEY[] = "QT_QMAKE_EXECUTABLE";
|
||||||
const char CMAKE_PREFIX_PATH_KEY[] = "CMAKE_PREFIX_PATH";
|
const char CMAKE_PREFIX_PATH_KEY[] = "CMAKE_PREFIX_PATH";
|
||||||
|
const char QTC_CMAKE_PRESET_KEY[] = "QTC_CMAKE_PRESET";
|
||||||
|
|
||||||
class CMakeConfigurationKitAspectWidget final : public KitAspectWidget
|
class CMakeConfigurationKitAspectWidget final : public KitAspectWidget
|
||||||
{
|
{
|
||||||
@@ -1120,6 +1122,23 @@ CMakeConfig CMakeConfigurationKitAspect::defaultConfiguration(const Kit *k)
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMakeConfigurationKitAspect::setCMakePreset(Kit *k, const QString &presetName)
|
||||||
|
{
|
||||||
|
CMakeConfig config = configuration(k);
|
||||||
|
config.prepend(
|
||||||
|
CMakeConfigItem(QTC_CMAKE_PRESET_KEY, CMakeConfigItem::INTERNAL, presetName.toUtf8()));
|
||||||
|
|
||||||
|
setConfiguration(k, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeConfigItem CMakeConfigurationKitAspect::cmakePresetConfigItem(const ProjectExplorer::Kit *k)
|
||||||
|
{
|
||||||
|
const CMakeConfig config = configuration(k);
|
||||||
|
return Utils::findOrDefault(config, [](const CMakeConfigItem &item) {
|
||||||
|
return item.key == QTC_CMAKE_PRESET_KEY;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QVariant CMakeConfigurationKitAspect::defaultValue(const Kit *k) const
|
QVariant CMakeConfigurationKitAspect::defaultValue(const Kit *k) const
|
||||||
{
|
{
|
||||||
// FIXME: Convert preload scripts
|
// FIXME: Convert preload scripts
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ public:
|
|||||||
|
|
||||||
static CMakeConfig defaultConfiguration(const ProjectExplorer::Kit *k);
|
static CMakeConfig defaultConfiguration(const ProjectExplorer::Kit *k);
|
||||||
|
|
||||||
|
static void setCMakePreset(ProjectExplorer::Kit *k, const QString &presetName);
|
||||||
|
static CMakeConfigItem cmakePresetConfigItem(const ProjectExplorer::Kit *k);
|
||||||
|
|
||||||
// KitAspect interface
|
// KitAspect interface
|
||||||
ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const final;
|
ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const final;
|
||||||
void setup(ProjectExplorer::Kit *k) final;
|
void setup(ProjectExplorer::Kit *k) final;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
#include <projectexplorer/projectnodes.h>
|
#include <projectexplorer/projectnodes.h>
|
||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
|
#include <projectexplorer/taskhub.h>
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
@@ -34,6 +35,8 @@ CMakeProject::CMakeProject(const FilePath &fileName)
|
|||||||
setDisplayName(projectDirectory().fileName());
|
setDisplayName(projectDirectory().fileName());
|
||||||
setCanBuildProducts();
|
setCanBuildProducts();
|
||||||
setHasMakeInstallEquivalent(true);
|
setHasMakeInstallEquivalent(true);
|
||||||
|
|
||||||
|
readPresets();
|
||||||
}
|
}
|
||||||
|
|
||||||
CMakeProject::~CMakeProject()
|
CMakeProject::~CMakeProject()
|
||||||
@@ -59,7 +62,7 @@ Tasks CMakeProject::projectIssues(const Kit *k) const
|
|||||||
ProjectImporter *CMakeProject::projectImporter() const
|
ProjectImporter *CMakeProject::projectImporter() const
|
||||||
{
|
{
|
||||||
if (!m_projectImporter)
|
if (!m_projectImporter)
|
||||||
m_projectImporter = new CMakeProjectImporter(projectFilePath());
|
m_projectImporter = new CMakeProjectImporter(projectFilePath(), m_presetsData);
|
||||||
return m_projectImporter;
|
return m_projectImporter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +76,100 @@ void CMakeProject::clearIssues()
|
|||||||
m_issues.clear();
|
m_issues.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PresetsData CMakeProject::presetsData() const
|
||||||
|
{
|
||||||
|
return m_presetsData;
|
||||||
|
}
|
||||||
|
|
||||||
|
Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakePresetsData,
|
||||||
|
Internal::PresetsData &cmakeUserPresetsData)
|
||||||
|
{
|
||||||
|
Internal::PresetsData result;
|
||||||
|
result.version = cmakePresetsData.version;
|
||||||
|
result.cmakeMinimimRequired = cmakePresetsData.cmakeMinimimRequired;
|
||||||
|
|
||||||
|
QHash<QString, PresetsDetails::ConfigurePreset> configurePresets;
|
||||||
|
|
||||||
|
// Populate the hash map with the CMakePresets
|
||||||
|
for (const PresetsDetails::ConfigurePreset &p: cmakePresetsData.configurePresets)
|
||||||
|
configurePresets.insert(p.name, p);
|
||||||
|
|
||||||
|
auto resolveInherits =
|
||||||
|
[configurePresets](std::vector<PresetsDetails::ConfigurePreset> &configurePresetsList) {
|
||||||
|
for (PresetsDetails::ConfigurePreset &cp : configurePresetsList) {
|
||||||
|
if (!cp.inherits)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const QString &inheritFromName : cp.inherits.value())
|
||||||
|
if (configurePresets.contains(inheritFromName))
|
||||||
|
cp.inheritFrom(configurePresets[inheritFromName]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// First resolve the CMakePresets
|
||||||
|
resolveInherits(cmakePresetsData.configurePresets);
|
||||||
|
|
||||||
|
// Add the CMakeUserPresets to the resolve hash map
|
||||||
|
for (const PresetsDetails::ConfigurePreset &cp : cmakeUserPresetsData.configurePresets) {
|
||||||
|
if (configurePresets.contains(cp.name)) {
|
||||||
|
TaskHub::addTask(BuildSystemTask(
|
||||||
|
Task::TaskType::Error,
|
||||||
|
tr("CMakeUserPresets.json cannot re-define the configure preset: %1").arg(cp.name),
|
||||||
|
"CMakeUserPresets.json"));
|
||||||
|
TaskHub::requestPopup();
|
||||||
|
} else {
|
||||||
|
configurePresets.insert(cp.name, cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then resolve the CMakeUserPresets
|
||||||
|
resolveInherits(cmakeUserPresetsData.configurePresets);
|
||||||
|
|
||||||
|
// Get both CMakePresets and CMakeUserPresets into the result
|
||||||
|
result.configurePresets = cmakePresetsData.configurePresets;
|
||||||
|
|
||||||
|
// std::vector doesn't have append
|
||||||
|
std::copy(cmakeUserPresetsData.configurePresets.begin(),
|
||||||
|
cmakeUserPresetsData.configurePresets.end(),
|
||||||
|
std::back_inserter(result.configurePresets));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMakeProject::readPresets()
|
||||||
|
{
|
||||||
|
auto parsePreset = [](const Utils::FilePath &presetFile) -> Internal::PresetsData {
|
||||||
|
Internal::PresetsData data;
|
||||||
|
Internal::PresetsParser parser;
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
int errorLine = -1;
|
||||||
|
|
||||||
|
if (presetFile.exists()) {
|
||||||
|
if (parser.parse(presetFile, errorMessage, errorLine)) {
|
||||||
|
data = parser.presetsData();
|
||||||
|
} else {
|
||||||
|
TaskHub::addTask(BuildSystemTask(Task::TaskType::Error,
|
||||||
|
tr("Failed to load %1: %2")
|
||||||
|
.arg(presetFile.fileName())
|
||||||
|
.arg(errorMessage),
|
||||||
|
presetFile,
|
||||||
|
errorLine));
|
||||||
|
TaskHub::requestPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Utils::FilePath cmakePresetsJson = projectDirectory().pathAppended("CMakePresets.json");
|
||||||
|
const Utils::FilePath cmakeUserPresetsJson = projectDirectory().pathAppended("CMakeUserPresets.json");
|
||||||
|
|
||||||
|
Internal::PresetsData cmakePresetsData = parsePreset(cmakePresetsJson);
|
||||||
|
Internal::PresetsData cmakeUserPresetsData = parsePreset(cmakeUserPresetsJson);
|
||||||
|
|
||||||
|
m_presetsData = combinePresets(cmakePresetsData, cmakeUserPresetsData);
|
||||||
|
}
|
||||||
|
|
||||||
bool CMakeProject::setupTarget(Target *t)
|
bool CMakeProject::setupTarget(Target *t)
|
||||||
{
|
{
|
||||||
t->updateDefaultBuildConfigurations();
|
t->updateDefaultBuildConfigurations();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cmake_global.h"
|
#include "cmake_global.h"
|
||||||
|
#include "presetsparser.h"
|
||||||
|
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
|
|
||||||
@@ -27,15 +28,21 @@ public:
|
|||||||
void addIssue(IssueType type, const QString &text);
|
void addIssue(IssueType type, const QString &text);
|
||||||
void clearIssues();
|
void clearIssues();
|
||||||
|
|
||||||
|
Internal::PresetsData presetsData() const;
|
||||||
|
void readPresets();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool setupTarget(ProjectExplorer::Target *t) final;
|
bool setupTarget(ProjectExplorer::Target *t) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
|
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
|
||||||
|
Internal::PresetsData combinePresets(Internal::PresetsData &cmakePresetsData,
|
||||||
|
Internal::PresetsData &cmakeUserPresetsData);
|
||||||
|
|
||||||
mutable Internal::CMakeProjectImporter *m_projectImporter = nullptr;
|
mutable Internal::CMakeProjectImporter *m_projectImporter = nullptr;
|
||||||
|
|
||||||
ProjectExplorer::Tasks m_issues;
|
ProjectExplorer::Tasks m_issues;
|
||||||
|
Internal::PresetsData m_presetsData;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "cmakekitinformation.h"
|
#include "cmakekitinformation.h"
|
||||||
#include "cmakeprojectconstants.h"
|
#include "cmakeprojectconstants.h"
|
||||||
#include "cmaketoolmanager.h"
|
#include "cmaketoolmanager.h"
|
||||||
|
#include "presetsmacros.h"
|
||||||
|
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
@@ -43,6 +45,9 @@ struct DirectoryData
|
|||||||
FilePath cmakeHomeDirectory;
|
FilePath cmakeHomeDirectory;
|
||||||
bool hasQmlDebugging = false;
|
bool hasQmlDebugging = false;
|
||||||
|
|
||||||
|
QString cmakePresetDisplayname;
|
||||||
|
QString cmakePreset;
|
||||||
|
|
||||||
// Kit Stuff
|
// Kit Stuff
|
||||||
FilePath cmakeBinary;
|
FilePath cmakeBinary;
|
||||||
QString generator;
|
QString generator;
|
||||||
@@ -88,7 +93,10 @@ static QString uniqueCMakeToolDisplayName(CMakeTool &tool)
|
|||||||
|
|
||||||
// CMakeProjectImporter
|
// CMakeProjectImporter
|
||||||
|
|
||||||
CMakeProjectImporter::CMakeProjectImporter(const FilePath &path) : QtProjectImporter(path)
|
CMakeProjectImporter::CMakeProjectImporter(const FilePath &path, const PresetsData &presetsData)
|
||||||
|
: QtProjectImporter(path)
|
||||||
|
, m_presetsData(presetsData)
|
||||||
|
, m_presetsTempDir("qtc-cmake-presets-XXXXXXXX")
|
||||||
{
|
{
|
||||||
useTemporaryKitAspect(CMakeKitAspect::id(),
|
useTemporaryKitAspect(CMakeKitAspect::id(),
|
||||||
[this](Kit *k, const QVariantList &vl) { cleanupTemporaryCMake(k, vl); },
|
[this](Kit *k, const QVariantList &vl) { cleanupTemporaryCMake(k, vl); },
|
||||||
@@ -111,11 +119,102 @@ QStringList CMakeProjectImporter::importCandidates()
|
|||||||
BuildConfiguration::Unknown);
|
BuildConfiguration::Unknown);
|
||||||
candidates << scanDirectory(shadowBuildDirectory.absolutePath(), QString());
|
candidates << scanDirectory(shadowBuildDirectory.absolutePath(), QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &configPreset : m_presetsData.configurePresets) {
|
||||||
|
if (configPreset.hidden.value())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString presetDirName = m_presetsTempDir.filePath(configPreset.name).toString();
|
||||||
|
const QDir presetDir;
|
||||||
|
presetDir.mkpath(presetDirName);
|
||||||
|
candidates << presetDirName;
|
||||||
|
}
|
||||||
|
|
||||||
const QStringList finalists = Utils::filteredUnique(candidates);
|
const QStringList finalists = Utils::filteredUnique(candidates);
|
||||||
qCInfo(cmInputLog) << "import candidates:" << finalists;
|
qCInfo(cmInputLog) << "import candidates:" << finalists;
|
||||||
return finalists;
|
return finalists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CMakeConfig configurationFromPresetProbe(
|
||||||
|
const FilePath &importPath, const PresetsDetails::ConfigurePreset &configurePreset)
|
||||||
|
{
|
||||||
|
QFile cmakeListTxt(importPath.pathAppended("CMakeLists.txt").toString());
|
||||||
|
if (!cmakeListTxt.open(QIODevice::WriteOnly)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
cmakeListTxt.write(QByteArray("cmake_minimum_required(VERSION 3.15)\n"
|
||||||
|
"\n"
|
||||||
|
"project(preset-probe)\n"
|
||||||
|
"\n"));
|
||||||
|
cmakeListTxt.close();
|
||||||
|
|
||||||
|
QtcProcess cmake;
|
||||||
|
cmake.setTimeoutS(30);
|
||||||
|
cmake.setDisableUnixTerminal();
|
||||||
|
|
||||||
|
Environment env = Environment::systemEnvironment();
|
||||||
|
CMakePresets::Macros::expand(configurePreset, env, importPath);
|
||||||
|
|
||||||
|
env.setupEnglishOutput();
|
||||||
|
cmake.setEnvironment(env);
|
||||||
|
cmake.setTimeOutMessageBoxEnabled(false);
|
||||||
|
|
||||||
|
const FilePath cmakeExecutable = FilePath::fromString(configurePreset.cmakeExecutable.value());
|
||||||
|
|
||||||
|
QStringList args;
|
||||||
|
args.emplace_back("-S");
|
||||||
|
args.emplace_back(importPath.path());
|
||||||
|
args.emplace_back("-B");
|
||||||
|
args.emplace_back(importPath.pathAppended("build/").path());
|
||||||
|
|
||||||
|
if (configurePreset.generator) {
|
||||||
|
args.emplace_back("-G");
|
||||||
|
args.emplace_back(configurePreset.generator.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurePreset.cacheVariables) {
|
||||||
|
const CMakeConfig cache = configurePreset.cacheVariables
|
||||||
|
? configurePreset.cacheVariables.value()
|
||||||
|
: CMakeConfig();
|
||||||
|
const FilePath cmakeMakeProgram = cache.filePathValueOf(QByteArray("CMAKE_MAKE_PROGRAM"));
|
||||||
|
const FilePath toolchainFile = cache.filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"));
|
||||||
|
const QString prefixPath = cache.stringValueOf(QByteArray("CMAKE_PREFIX_PATH"));
|
||||||
|
const QString findRootPath = cache.stringValueOf(QByteArray("CMAKE_FIND_ROOT_PATH"));
|
||||||
|
const QString qtHostPath = cache.stringValueOf(QByteArray("QT_HOST_PATH"));
|
||||||
|
|
||||||
|
if (!cmakeMakeProgram.isEmpty()) {
|
||||||
|
args.emplace_back(
|
||||||
|
QStringLiteral("-DCMAKE_MAKE_PROGRAM=%1").arg(cmakeMakeProgram.toString()));
|
||||||
|
}
|
||||||
|
if (!toolchainFile.isEmpty()) {
|
||||||
|
args.emplace_back(
|
||||||
|
QStringLiteral("-DCMAKE_TOOLCHAIN_FILE=%1").arg(toolchainFile.toString()));
|
||||||
|
}
|
||||||
|
if (!prefixPath.isEmpty()) {
|
||||||
|
args.emplace_back(QStringLiteral("-DCMAKE_PREFIX_PATH=%1").arg(prefixPath));
|
||||||
|
}
|
||||||
|
if (!findRootPath.isEmpty()) {
|
||||||
|
args.emplace_back(QStringLiteral("-DCMAKE_FIND_ROOT_PATH=%1").arg(findRootPath));
|
||||||
|
}
|
||||||
|
if (!qtHostPath.isEmpty()) {
|
||||||
|
args.emplace_back(QStringLiteral("-DQT_HOST_PATH=%1").arg(qtHostPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(cmInputLog) << "CMake probing for compilers: " << cmakeExecutable.toUserOutput()
|
||||||
|
<< args;
|
||||||
|
cmake.setCommand({cmakeExecutable, args});
|
||||||
|
cmake.runBlocking();
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
const CMakeConfig config = CMakeConfig::fromFile(importPath.pathAppended(
|
||||||
|
"build/CMakeCache.txt"),
|
||||||
|
&errorMessage);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
||||||
{
|
{
|
||||||
// Qt4 way to define things (more convenient for us, so try this first;-)
|
// Qt4 way to define things (more convenient for us, so try this first;-)
|
||||||
@@ -134,10 +233,15 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
|||||||
qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput();
|
qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput();
|
||||||
const FilePath canQtCMakeDir = FilePath::fromString(qtCMakeDir.toFileInfo().canonicalFilePath());
|
const FilePath canQtCMakeDir = FilePath::fromString(qtCMakeDir.toFileInfo().canonicalFilePath());
|
||||||
qCInfo(cmInputLog) << "QtXCore_DIR (canonical)=" << canQtCMakeDir.toUserOutput();
|
qCInfo(cmInputLog) << "QtXCore_DIR (canonical)=" << canQtCMakeDir.toUserOutput();
|
||||||
if (qtCMakeDir.isEmpty())
|
QString prefixPath;
|
||||||
|
if (!qtCMakeDir.isEmpty()) {
|
||||||
|
prefixPath = canQtCMakeDir.parentDir().parentDir().parentDir().toString(); // Up 3 levels...
|
||||||
|
} else {
|
||||||
|
prefixPath = config.stringValueOf("CMAKE_PREFIX_PATH");
|
||||||
|
}
|
||||||
|
qCDebug(cmInputLog) << "PrefixPath:" << prefixPath;
|
||||||
|
if (prefixPath.isEmpty())
|
||||||
return FilePath();
|
return FilePath();
|
||||||
const FilePath baseQtDir = canQtCMakeDir.parentDir().parentDir().parentDir(); // Up 3 levels...
|
|
||||||
qCDebug(cmInputLog) << "BaseQtDir:" << baseQtDir.toUserOutput();
|
|
||||||
|
|
||||||
// Run a CMake project that would do qmake probing
|
// Run a CMake project that would do qmake probing
|
||||||
TemporaryDirectory qtcQMakeProbeDir("qtc-cmake-qmake-probe-XXXXXXXX");
|
TemporaryDirectory qtcQMakeProbeDir("qtc-cmake-qmake-probe-XXXXXXXX");
|
||||||
@@ -204,9 +308,9 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
|||||||
args.push_back(QStringLiteral("-DCMAKE_MAKE_PROGRAM=%1").arg(cmakeMakeProgram.toString()));
|
args.push_back(QStringLiteral("-DCMAKE_MAKE_PROGRAM=%1").arg(cmakeMakeProgram.toString()));
|
||||||
}
|
}
|
||||||
if (toolchainFile.isEmpty()) {
|
if (toolchainFile.isEmpty()) {
|
||||||
args.push_back(QStringLiteral("-DCMAKE_PREFIX_PATH=%1").arg(baseQtDir.toString()));
|
args.push_back(QStringLiteral("-DCMAKE_PREFIX_PATH=%1").arg(prefixPath));
|
||||||
} else {
|
} else {
|
||||||
args.push_back(QStringLiteral("-DCMAKE_FIND_ROOT_PATH=%1").arg(baseQtDir.toString()));
|
args.push_back(QStringLiteral("-DCMAKE_FIND_ROOT_PATH=%1").arg(prefixPath));
|
||||||
args.push_back(QStringLiteral("-DCMAKE_TOOLCHAIN_FILE=%1").arg(toolchainFile.toString()));
|
args.push_back(QStringLiteral("-DCMAKE_TOOLCHAIN_FILE=%1").arg(toolchainFile.toString()));
|
||||||
}
|
}
|
||||||
if (!hostPath.isEmpty()) {
|
if (!hostPath.isEmpty()) {
|
||||||
@@ -279,19 +383,102 @@ static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfi
|
|||||||
QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
||||||
QString *warningMessage) const
|
QString *warningMessage) const
|
||||||
{
|
{
|
||||||
|
QList<void *> result;
|
||||||
qCInfo(cmInputLog) << "Examining directory:" << importPath.toUserOutput();
|
qCInfo(cmInputLog) << "Examining directory:" << importPath.toUserOutput();
|
||||||
|
|
||||||
|
if (importPath.isChildOf(m_presetsTempDir.path())) {
|
||||||
|
auto data = std::make_unique<DirectoryData>();
|
||||||
|
|
||||||
|
const QString presetName = importPath.fileName();
|
||||||
|
|
||||||
|
PresetsDetails::ConfigurePreset configurePreset
|
||||||
|
= Utils::findOrDefault(m_presetsData.configurePresets,
|
||||||
|
[presetName](const PresetsDetails::ConfigurePreset &preset) {
|
||||||
|
return preset.name == presetName;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (configurePreset.displayName)
|
||||||
|
data->cmakePresetDisplayname = configurePreset.displayName.value();
|
||||||
|
else
|
||||||
|
data->cmakePresetDisplayname = configurePreset.name;
|
||||||
|
data->cmakePreset = configurePreset.name;
|
||||||
|
|
||||||
|
if (!configurePreset.cmakeExecutable) {
|
||||||
|
const CMakeTool *cmakeTool = CMakeToolManager::defaultCMakeTool();
|
||||||
|
if (cmakeTool)
|
||||||
|
configurePreset.cmakeExecutable = cmakeTool->cmakeExecutable().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
data->cmakeBinary = Utils::FilePath::fromString(configurePreset.cmakeExecutable.value());
|
||||||
|
if (configurePreset.generator)
|
||||||
|
data->generator = configurePreset.generator.value();
|
||||||
|
|
||||||
|
if (configurePreset.architecture && configurePreset.architecture.value().value)
|
||||||
|
data->platform = configurePreset.architecture.value().value.value();
|
||||||
|
|
||||||
|
if (configurePreset.toolset && configurePreset.toolset.value().value)
|
||||||
|
data->toolset = configurePreset.toolset.value().value.value();
|
||||||
|
|
||||||
|
QString binaryDir = importPath.toString();
|
||||||
|
if (configurePreset.binaryDir) {
|
||||||
|
binaryDir = configurePreset.binaryDir.value();
|
||||||
|
CMakePresets::Macros::expand(configurePreset,
|
||||||
|
Environment::systemEnvironment(),
|
||||||
|
projectDirectory(),
|
||||||
|
binaryDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->buildDirectory = Utils::FilePath::fromString(binaryDir);
|
||||||
|
|
||||||
|
const CMakeConfig cache = configurePreset.cacheVariables
|
||||||
|
? configurePreset.cacheVariables.value()
|
||||||
|
: CMakeConfig();
|
||||||
|
data->cmakeBuildType = cache.valueOf("CMAKE_BUILD_TYPE");
|
||||||
|
if (data->cmakeBuildType.isEmpty())
|
||||||
|
data->cmakeBuildType = "Debug";
|
||||||
|
|
||||||
|
data->sysroot = cache.filePathValueOf("CMAKE_SYSROOT");
|
||||||
|
|
||||||
|
CMakeConfig config;
|
||||||
|
if (cache.valueOf("CMAKE_C_COMPILER").isEmpty()
|
||||||
|
&& cache.valueOf("CMAKE_CXX_COMPILER").isEmpty()) {
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
config = configurationFromPresetProbe(importPath, configurePreset);
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
} else {
|
||||||
|
config = cache;
|
||||||
|
config << CMakeConfigItem("CMAKE_COMMAND",
|
||||||
|
CMakeConfigItem::PATH,
|
||||||
|
configurePreset.cmakeExecutable.value().toUtf8());
|
||||||
|
if (configurePreset.generator)
|
||||||
|
config << CMakeConfigItem("CMAKE_GENERATOR",
|
||||||
|
CMakeConfigItem::STRING,
|
||||||
|
configurePreset.generator.value().toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
const FilePath qmake = qmakeFromCMakeCache(config);
|
||||||
|
if (!qmake.isEmpty())
|
||||||
|
data->qt = findOrCreateQtVersion(qmake);
|
||||||
|
|
||||||
|
// ToolChains:
|
||||||
|
data->toolChains = extractToolChainsFromCache(config);
|
||||||
|
|
||||||
|
result.push_back(static_cast<void *>(data.release()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
const FilePath cacheFile = importPath.pathAppended("CMakeCache.txt");
|
const FilePath cacheFile = importPath.pathAppended("CMakeCache.txt");
|
||||||
|
|
||||||
if (!cacheFile.exists()) {
|
if (!cacheFile.exists()) {
|
||||||
qCDebug(cmInputLog) << cacheFile.toUserOutput() << "does not exist, returning.";
|
qCDebug(cmInputLog) << cacheFile.toUserOutput() << "does not exist, returning.";
|
||||||
return { };
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
const CMakeConfig config = CMakeConfig::fromFile(cacheFile, &errorMessage);
|
const CMakeConfig config = CMakeConfig::fromFile(cacheFile, &errorMessage);
|
||||||
if (config.isEmpty() || !errorMessage.isEmpty()) {
|
if (config.isEmpty() || !errorMessage.isEmpty()) {
|
||||||
qCDebug(cmInputLog) << "Failed to read configuration from" << cacheFile << errorMessage;
|
qCDebug(cmInputLog) << "Failed to read configuration from" << cacheFile << errorMessage;
|
||||||
return { };
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArrayList buildConfigurationTypes = {config.valueOf("CMAKE_BUILD_TYPE")};
|
QByteArrayList buildConfigurationTypes = {config.valueOf("CMAKE_BUILD_TYPE")};
|
||||||
@@ -301,7 +488,6 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
|||||||
buildConfigurationTypes = buildConfigurationTypesString.split(';');
|
buildConfigurationTypes = buildConfigurationTypesString.split(';');
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<void *> result;
|
|
||||||
for (auto const &buildType: qAsConst(buildConfigurationTypes)) {
|
for (auto const &buildType: qAsConst(buildConfigurationTypes)) {
|
||||||
auto data = std::make_unique<DirectoryData>();
|
auto data = std::make_unique<DirectoryData>();
|
||||||
|
|
||||||
@@ -374,6 +560,12 @@ bool CMakeProjectImporter::matchKit(void *directoryData, const Kit *k) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data->cmakePreset.isEmpty()) {
|
||||||
|
auto presetConfigItem = CMakeConfigurationKitAspect::cmakePresetConfigItem(k);
|
||||||
|
if (data->cmakePreset != presetConfigItem.expandedValue(k))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(cmInputLog) << k->displayName()
|
qCDebug(cmInputLog) << k->displayName()
|
||||||
<< "matches directoryData for" << data->buildDirectory.toUserOutput();
|
<< "matches directoryData for" << data->buildDirectory.toUserOutput();
|
||||||
return true;
|
return true;
|
||||||
@@ -395,6 +587,13 @@ Kit *CMakeProjectImporter::createKit(void *directoryData) const
|
|||||||
CMakeGeneratorKitAspect::setPlatform(k, data->platform);
|
CMakeGeneratorKitAspect::setPlatform(k, data->platform);
|
||||||
CMakeGeneratorKitAspect::setToolset(k, data->toolset);
|
CMakeGeneratorKitAspect::setToolset(k, data->toolset);
|
||||||
|
|
||||||
|
if (!data->cmakePresetDisplayname.isEmpty()) {
|
||||||
|
k->setUnexpandedDisplayName(
|
||||||
|
QString("%1 (CMake preset)").arg(data->cmakePresetDisplayname));
|
||||||
|
|
||||||
|
CMakeConfigurationKitAspect::setCMakePreset(k, data->cmakePreset);
|
||||||
|
}
|
||||||
|
|
||||||
SysRootKitAspect::setSysRoot(k, data->sysroot);
|
SysRootKitAspect::setSysRoot(k, data->sysroot);
|
||||||
|
|
||||||
for (const ToolChainDescription &cmtcd : data->toolChains) {
|
for (const ToolChainDescription &cmtcd : data->toolChains) {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "presetsparser.h"
|
||||||
|
#include "utils/temporarydirectory.h"
|
||||||
|
|
||||||
#include <qtsupport/qtprojectimporter.h>
|
#include <qtsupport/qtprojectimporter.h>
|
||||||
|
|
||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
@@ -16,7 +19,7 @@ class CMakeProjectImporter : public QtSupport::QtProjectImporter
|
|||||||
Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeProjectImporter)
|
Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeProjectImporter)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMakeProjectImporter(const Utils::FilePath &path);
|
CMakeProjectImporter(const Utils::FilePath &path, const Internal::PresetsData &presetsData);
|
||||||
|
|
||||||
QStringList importCandidates() final;
|
QStringList importCandidates() final;
|
||||||
|
|
||||||
@@ -37,6 +40,9 @@ private:
|
|||||||
|
|
||||||
void cleanupTemporaryCMake(ProjectExplorer::Kit *k, const QVariantList &vl);
|
void cleanupTemporaryCMake(ProjectExplorer::Kit *k, const QVariantList &vl);
|
||||||
void persistTemporaryCMake(ProjectExplorer::Kit *k, const QVariantList &vl);
|
void persistTemporaryCMake(ProjectExplorer::Kit *k, const QVariantList &vl);
|
||||||
|
|
||||||
|
Internal::PresetsData m_presetsData;
|
||||||
|
Utils::TemporaryDirectory m_presetsTempDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ QtcPlugin {
|
|||||||
"fileapiparser.h",
|
"fileapiparser.h",
|
||||||
"fileapireader.cpp",
|
"fileapireader.cpp",
|
||||||
"fileapireader.h",
|
"fileapireader.h",
|
||||||
|
"presetsparser.cpp",
|
||||||
|
"presetsparser.h",
|
||||||
|
"presetsmacros.cpp",
|
||||||
|
"presetsmacros.h",
|
||||||
"projecttreehelper.cpp",
|
"projecttreehelper.cpp",
|
||||||
"projecttreehelper.h"
|
"projecttreehelper.h"
|
||||||
]
|
]
|
||||||
|
|||||||
131
src/plugins/cmakeprojectmanager/presetsmacros.cpp
Normal file
131
src/plugins/cmakeprojectmanager/presetsmacros.cpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
// 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 "presetsmacros.h"
|
||||||
|
#include "presetsparser.h"
|
||||||
|
|
||||||
|
#include <utils/environment.h>
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
namespace CMakeProjectManager::Internal::CMakePresets::Macros {
|
||||||
|
|
||||||
|
static void expandAllButEnv(const PresetsDetails::ConfigurePreset &configurePreset,
|
||||||
|
const Utils::FilePath &sourceDirectory,
|
||||||
|
QString &value)
|
||||||
|
{
|
||||||
|
value.replace("${dollar}", "$");
|
||||||
|
|
||||||
|
value.replace("${sourceDir}", sourceDirectory.toString());
|
||||||
|
value.replace("${sourceParentDir}", sourceDirectory.parentDir().toString());
|
||||||
|
value.replace("${sourceDirName}", sourceDirectory.fileName());
|
||||||
|
|
||||||
|
value.replace("${presetName}", configurePreset.name);
|
||||||
|
if (configurePreset.generator)
|
||||||
|
value.replace("${generator}", configurePreset.generator.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand(const PresetsDetails::ConfigurePreset &configurePreset,
|
||||||
|
Utils::Environment &env,
|
||||||
|
const Utils::FilePath &sourceDirectory)
|
||||||
|
{
|
||||||
|
const QHash<QString, QString> presetEnv = configurePreset.environment
|
||||||
|
? configurePreset.environment.value()
|
||||||
|
: QHash<QString, QString>();
|
||||||
|
for (auto it = presetEnv.constKeyValueBegin(); it != presetEnv.constKeyValueEnd(); ++it) {
|
||||||
|
const QString key = it->first;
|
||||||
|
QString value = it->second;
|
||||||
|
|
||||||
|
expandAllButEnv(configurePreset, sourceDirectory, value);
|
||||||
|
|
||||||
|
QRegularExpression envRegex(R"((\$env\{(\w+)\}))");
|
||||||
|
for (const QRegularExpressionMatch &match : envRegex.globalMatch(value)) {
|
||||||
|
if (match.captured(2) != key)
|
||||||
|
value.replace(match.captured(1), presetEnv.value(match.captured(2)));
|
||||||
|
else
|
||||||
|
value.replace(match.captured(1), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sep;
|
||||||
|
bool append = true;
|
||||||
|
if (key.compare("PATH", Qt::CaseInsensitive) == 0) {
|
||||||
|
sep = Utils::OsSpecificAspects::pathListSeparator(env.osType());
|
||||||
|
const int index = value.indexOf("$penv{PATH}", 0, Qt::CaseInsensitive);
|
||||||
|
if (index != 0)
|
||||||
|
append = false;
|
||||||
|
value.replace("$penv{PATH}", "", Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegularExpression penvRegex(R"((\$penv\{(\w+)\}))");
|
||||||
|
for (const QRegularExpressionMatch &match : penvRegex.globalMatch(value))
|
||||||
|
value.replace(match.captured(1), env.value(match.captured(2)));
|
||||||
|
|
||||||
|
if (append)
|
||||||
|
env.appendOrSet(key, value, sep);
|
||||||
|
else
|
||||||
|
env.prependOrSet(key, value, sep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand(const PresetsDetails::ConfigurePreset &configurePreset,
|
||||||
|
Utils::EnvironmentItems &envItems,
|
||||||
|
const Utils::FilePath &sourceDirectory)
|
||||||
|
{
|
||||||
|
const QHash<QString, QString> presetEnv = configurePreset.environment
|
||||||
|
? configurePreset.environment.value()
|
||||||
|
: QHash<QString, QString>();
|
||||||
|
|
||||||
|
for (auto it = presetEnv.constKeyValueBegin(); it != presetEnv.constKeyValueEnd(); ++it) {
|
||||||
|
const QString key = it->first;
|
||||||
|
QString value = it->second;
|
||||||
|
|
||||||
|
expandAllButEnv(configurePreset, sourceDirectory, value);
|
||||||
|
|
||||||
|
QRegularExpression envRegex(R"((\$env\{(\w+)\}))");
|
||||||
|
for (const QRegularExpressionMatch &match : envRegex.globalMatch(value)) {
|
||||||
|
if (match.captured(2) != key)
|
||||||
|
value.replace(match.captured(1), presetEnv.value(match.captured(2)));
|
||||||
|
else
|
||||||
|
value.replace(match.captured(1), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operation = Utils::EnvironmentItem::Operation::SetEnabled;
|
||||||
|
if (key.compare("PATH", Qt::CaseInsensitive) == 0) {
|
||||||
|
operation = Utils::EnvironmentItem::Operation::Append;
|
||||||
|
const int index = value.indexOf("$penv{PATH}", 0, Qt::CaseInsensitive);
|
||||||
|
if (index != 0)
|
||||||
|
operation = Utils::EnvironmentItem::Operation::Prepend;
|
||||||
|
value.replace("$penv{PATH}", "", Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegularExpression penvRegex(R"((\$penv\{(\w+)\}))");
|
||||||
|
for (const QRegularExpressionMatch &match : penvRegex.globalMatch(value))
|
||||||
|
value.replace(match.captured(1), QString("${%1}").arg(match.captured(2)));
|
||||||
|
|
||||||
|
envItems.emplace_back(Utils::EnvironmentItem(key, value, operation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand(const PresetsDetails::ConfigurePreset &configurePreset,
|
||||||
|
const Utils::Environment &env,
|
||||||
|
const Utils::FilePath &sourceDirectory,
|
||||||
|
QString &value)
|
||||||
|
{
|
||||||
|
expandAllButEnv(configurePreset, sourceDirectory, value);
|
||||||
|
|
||||||
|
const QHash<QString, QString> presetEnv = configurePreset.environment
|
||||||
|
? configurePreset.environment.value()
|
||||||
|
: QHash<QString, QString>();
|
||||||
|
|
||||||
|
QRegularExpression envRegex(R"((\$env\{(\w+)\}))");
|
||||||
|
for (const QRegularExpressionMatch &match : envRegex.globalMatch(value))
|
||||||
|
value.replace(match.captured(1), presetEnv.value(match.captured(2)));
|
||||||
|
|
||||||
|
QRegularExpression penvRegex(R"((\$penv\{(\w+)\}))");
|
||||||
|
for (const QRegularExpressionMatch &match : penvRegex.globalMatch(value))
|
||||||
|
value.replace(match.captured(1), env.value(match.captured(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CMakeProjectManager::Internal::CMakePresets::Macros
|
||||||
46
src/plugins/cmakeprojectmanager/presetsmacros.h
Normal file
46
src/plugins/cmakeprojectmanager/presetsmacros.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/environmentfwd.h>
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
class Environment;
|
||||||
|
class FilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CMakeProjectManager::Internal {
|
||||||
|
|
||||||
|
namespace PresetsDetails {
|
||||||
|
class ConfigurePreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CMakePresets::Macros {
|
||||||
|
/**
|
||||||
|
* Expands the CMakePresets Macros using Utils::Environment as target and source for parent environment values.
|
||||||
|
* $penv{PATH} is taken from Utils::Environment
|
||||||
|
*/
|
||||||
|
void expand(const PresetsDetails::ConfigurePreset &configurePreset,
|
||||||
|
Utils::Environment &env,
|
||||||
|
const Utils::FilePath &sourceDirectory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands the CMakePresets Macros using Utils::Environment as target
|
||||||
|
* $penv{PATH} is replaced with Qt Creator macros ${PATH}
|
||||||
|
*/
|
||||||
|
void expand(const PresetsDetails::ConfigurePreset &configurePreset,
|
||||||
|
Utils::EnvironmentItems &envItems,
|
||||||
|
const Utils::FilePath &sourceDirectory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands the CMakePresets macros inside the @value QString parameter.
|
||||||
|
*/
|
||||||
|
void expand(const PresetsDetails::ConfigurePreset &configurePreset,
|
||||||
|
const Utils::Environment &env,
|
||||||
|
const Utils::FilePath &sourceDirectory,
|
||||||
|
QString &value);
|
||||||
|
|
||||||
|
} // namespace CMakePresets::Macros
|
||||||
|
|
||||||
|
} // namespace CMakeProjectManager::Internal
|
||||||
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
|
||||||
91
src/plugins/cmakeprojectmanager/presetsparser.h
Normal file
91
src/plugins/cmakeprojectmanager/presetsparser.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
|
||||||
|
#include "cmakeconfigitem.h"
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
#include <QVersionNumber>
|
||||||
|
|
||||||
|
namespace CMakeProjectManager {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
namespace PresetsDetails {
|
||||||
|
|
||||||
|
class ValueStrategyPair {
|
||||||
|
public:
|
||||||
|
std::optional<QString> value;
|
||||||
|
enum class Strategy : bool { set, external };
|
||||||
|
std::optional<Strategy> strategy;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Warnings {
|
||||||
|
public:
|
||||||
|
std::optional<bool> dev;
|
||||||
|
std::optional<bool> deprecated;
|
||||||
|
std::optional<bool> uninitialized = false;
|
||||||
|
std::optional<bool> unusedCli = true;
|
||||||
|
std::optional<bool> systemVars = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Errors {
|
||||||
|
public:
|
||||||
|
std::optional<bool> dev;
|
||||||
|
std::optional<bool> deprecated;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Debug {
|
||||||
|
public:
|
||||||
|
std::optional<bool> output = false;
|
||||||
|
std::optional<bool> tryCompile = false;
|
||||||
|
std::optional<bool> find = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfigurePreset {
|
||||||
|
public:
|
||||||
|
void inheritFrom(const ConfigurePreset &other);
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
std::optional<bool> hidden = false;
|
||||||
|
std::optional<QStringList> inherits;
|
||||||
|
std::optional<QHash<QString, QString>> vendor;
|
||||||
|
std::optional<QString> displayName;
|
||||||
|
std::optional<QString> description;
|
||||||
|
std::optional<QString> generator;
|
||||||
|
std::optional<ValueStrategyPair> architecture;
|
||||||
|
std::optional<ValueStrategyPair> toolset;
|
||||||
|
std::optional<QString> binaryDir;
|
||||||
|
std::optional<QString> cmakeExecutable;
|
||||||
|
std::optional<CMakeConfig> cacheVariables;
|
||||||
|
std::optional<QHash<QString, QString>> environment;
|
||||||
|
std::optional<Warnings> warnings;
|
||||||
|
std::optional<Errors> errors;
|
||||||
|
std::optional<Debug> debug;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PresetsDetails
|
||||||
|
|
||||||
|
class PresetsData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int version = 0;
|
||||||
|
QVersionNumber cmakeMinimimRequired;
|
||||||
|
QHash<QString, QString> vendor;
|
||||||
|
std::vector<PresetsDetails::ConfigurePreset> configurePresets;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PresetsParser
|
||||||
|
{
|
||||||
|
PresetsData m_presetsData;
|
||||||
|
public:
|
||||||
|
bool parse(Utils::FilePath const &jsonFile, QString &errorMessage, int &errorLine);
|
||||||
|
|
||||||
|
const PresetsData &presetsData() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace CMakeProjectManager
|
||||||
66
tests/manual/cmakepresets/CMakeLists.txt
Normal file
66
tests/manual/cmakepresets/CMakeLists.txt
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
project(cmakepresets VERSION 0.1 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
|
||||||
|
# Check https://doc.qt.io/qt/deployment-android.html for more information.
|
||||||
|
# They need to be set before the find_package( ...) calls below.
|
||||||
|
|
||||||
|
#if(ANDROID)
|
||||||
|
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
|
||||||
|
# if (ANDROID_ABI STREQUAL "armeabi-v7a")
|
||||||
|
# set(ANDROID_EXTRA_LIBS
|
||||||
|
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
|
||||||
|
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
|
||||||
|
# endif()
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
|
||||||
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
|
||||||
|
|
||||||
|
set(PROJECT_SOURCES
|
||||||
|
main.cpp
|
||||||
|
mainwindow.cpp
|
||||||
|
mainwindow.h
|
||||||
|
mainwindow.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||||
|
qt_add_executable(cmakepresets
|
||||||
|
MANUAL_FINALIZATION
|
||||||
|
${PROJECT_SOURCES}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
if(ANDROID)
|
||||||
|
add_library(cmakepresets SHARED
|
||||||
|
${PROJECT_SOURCES}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
add_executable(cmakepresets WIN32
|
||||||
|
${PROJECT_SOURCES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(cmakepresets PROPERTIES FOLDER qtc_runnable)
|
||||||
|
|
||||||
|
target_link_libraries(cmakepresets PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
||||||
|
|
||||||
|
set_target_properties(cmakepresets PROPERTIES
|
||||||
|
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
|
||||||
|
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||||
|
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(QT_VERSION_MAJOR EQUAL 6)
|
||||||
|
qt_finalize_executable(cmakepresets)
|
||||||
|
endif()
|
||||||
44
tests/manual/cmakepresets/CMakePresets.json
Normal file
44
tests/manual/cmakepresets/CMakePresets.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 19,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "mingw",
|
||||||
|
"displayName": "MinGW 11.2.0",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build-${presetName}-release",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release",
|
||||||
|
"CMAKE_PREFIX_PATH": "c:/Qt/6.3.1/mingw_64"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"PATH": "c:/mingw64/bin;$penv{PATH}"
|
||||||
|
},
|
||||||
|
"debug" : {
|
||||||
|
"find" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mingw-make",
|
||||||
|
"displayName": "MinGW 11.2.0 Makefiles",
|
||||||
|
"generator": "MinGW Makefiles",
|
||||||
|
"inherits" : "mingw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "visualc",
|
||||||
|
"displayName": "Visual C++ 2019 x64",
|
||||||
|
"generator": "Visual Studio 16 2019",
|
||||||
|
"binaryDir": "${sourceDir}/build-${presetName}",
|
||||||
|
"architecture" : {
|
||||||
|
"value": "x64"
|
||||||
|
},
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_PREFIX_PATH": "c:/Qt/6.3.1/msvc2019_64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
14
tests/manual/cmakepresets/main.cpp
Normal file
14
tests/manual/cmakepresets/main.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// 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 "mainwindow.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
18
tests/manual/cmakepresets/mainwindow.cpp
Normal file
18
tests/manual/cmakepresets/mainwindow.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// 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 "mainwindow.h"
|
||||||
|
#include "./ui_mainwindow.h"
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
|
: QMainWindow(parent)
|
||||||
|
, ui(new Ui::MainWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
24
tests/manual/cmakepresets/mainwindow.h
Normal file
24
tests/manual/cmakepresets/mainwindow.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui { class MainWindow; }
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MainWindow(QWidget *parent = nullptr);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
};
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
22
tests/manual/cmakepresets/mainwindow.ui
Normal file
22
tests/manual/cmakepresets/mainwindow.ui
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget"/>
|
||||||
|
<widget class="QMenuBar" name="menubar"/>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user