2022-05-30 19:04:54 +02:00
|
|
|
// 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>
|
|
|
|
|
|
|
|
|
|
namespace CMakeProjectManager::Internal::CMakePresets::Macros {
|
|
|
|
|
|
2022-09-26 18:59:04 +02:00
|
|
|
QString getHostSystemName()
|
|
|
|
|
{
|
|
|
|
|
Utils::OsType osType = Utils::HostOsInfo::hostOs();
|
|
|
|
|
|
|
|
|
|
switch (osType) {
|
|
|
|
|
case Utils::OsTypeWindows:
|
|
|
|
|
return "Windows";
|
|
|
|
|
case Utils::OsTypeLinux:
|
|
|
|
|
return "Linux";
|
|
|
|
|
case Utils::OsTypeMac:
|
|
|
|
|
return "Darwin";
|
|
|
|
|
case Utils::OsTypeOtherUnix:
|
|
|
|
|
return "Unix";
|
|
|
|
|
case Utils::OsTypeOther:
|
|
|
|
|
return "Other";
|
|
|
|
|
}
|
|
|
|
|
return "Other";
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
void expandAllButEnv(const PresetsDetails::ConfigurePreset &preset,
|
|
|
|
|
const Utils::FilePath &sourceDirectory,
|
|
|
|
|
QString &value)
|
2022-05-30 19:04:54 +02:00
|
|
|
{
|
|
|
|
|
value.replace("${dollar}", "$");
|
|
|
|
|
|
|
|
|
|
value.replace("${sourceDir}", sourceDirectory.toString());
|
|
|
|
|
value.replace("${sourceParentDir}", sourceDirectory.parentDir().toString());
|
|
|
|
|
value.replace("${sourceDirName}", sourceDirectory.fileName());
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
value.replace("${presetName}", preset.name);
|
|
|
|
|
if (preset.generator)
|
|
|
|
|
value.replace("${generator}", preset.generator.value());
|
2022-09-26 18:59:04 +02:00
|
|
|
|
|
|
|
|
value.replace("${hostSystemName}", getHostSystemName());
|
2022-05-30 19:04:54 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
void expandAllButEnv(const PresetsDetails::BuildPreset &preset,
|
|
|
|
|
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}", preset.name);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-30 15:01:58 +02:00
|
|
|
QString expandMacroEnv(const QString ¯oPrefix,
|
|
|
|
|
const QString &value,
|
|
|
|
|
const std::function<QString(const QString &)> &op)
|
|
|
|
|
{
|
|
|
|
|
const QString startToken = QString("$%1{").arg(macroPrefix);
|
|
|
|
|
const QString endToken = QString("}");
|
|
|
|
|
|
|
|
|
|
auto findMacro = [startToken,
|
|
|
|
|
endToken](const QString &str, qsizetype *pos, QString *ret) -> qsizetype {
|
|
|
|
|
forever {
|
|
|
|
|
qsizetype openPos = str.indexOf(startToken, *pos);
|
|
|
|
|
if (openPos < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
qsizetype varPos = openPos + startToken.length();
|
|
|
|
|
qsizetype endPos = str.indexOf(endToken, varPos + 1);
|
|
|
|
|
if (endPos < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
*ret = str.mid(varPos, endPos - varPos);
|
|
|
|
|
*pos = openPos;
|
|
|
|
|
|
|
|
|
|
return endPos - openPos + endToken.length();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QString result = value;
|
|
|
|
|
QString macroName;
|
|
|
|
|
|
|
|
|
|
bool done = true;
|
|
|
|
|
do {
|
|
|
|
|
done = true;
|
|
|
|
|
for (qsizetype pos = 0; int len = findMacro(result, &pos, ¯oName);) {
|
|
|
|
|
result.replace(pos, len, op(macroName));
|
|
|
|
|
pos += macroName.length();
|
|
|
|
|
done = false;
|
|
|
|
|
}
|
|
|
|
|
} while (!done);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
template<class PresetType>
|
|
|
|
|
void expand(const PresetType &preset,
|
2022-05-30 19:04:54 +02:00
|
|
|
Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory)
|
|
|
|
|
{
|
2022-09-05 20:09:12 +02:00
|
|
|
const QHash<QString, QString> presetEnv = preset.environment ? preset.environment.value()
|
|
|
|
|
: QHash<QString, QString>();
|
2022-05-30 19:04:54 +02:00
|
|
|
for (auto it = presetEnv.constKeyValueBegin(); it != presetEnv.constKeyValueEnd(); ++it) {
|
|
|
|
|
const QString key = it->first;
|
|
|
|
|
QString value = it->second;
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
expandAllButEnv(preset, sourceDirectory, value);
|
2022-09-30 15:01:58 +02:00
|
|
|
value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) {
|
|
|
|
|
return presetEnv.value(macroName);
|
|
|
|
|
});
|
2022-05-30 19:04:54 +02:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-30 15:01:58 +02:00
|
|
|
value = expandMacroEnv("penv", value, [env](const QString ¯oName) {
|
|
|
|
|
return env.value(macroName);
|
|
|
|
|
});
|
2022-05-30 19:04:54 +02:00
|
|
|
|
|
|
|
|
if (append)
|
|
|
|
|
env.appendOrSet(key, value, sep);
|
|
|
|
|
else
|
|
|
|
|
env.prependOrSet(key, value, sep);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
template<class PresetType>
|
|
|
|
|
void expand(const PresetType &preset,
|
2022-05-30 19:04:54 +02:00
|
|
|
Utils::EnvironmentItems &envItems,
|
|
|
|
|
const Utils::FilePath &sourceDirectory)
|
|
|
|
|
{
|
2022-09-05 20:09:12 +02:00
|
|
|
const QHash<QString, QString> presetEnv = preset.environment ? preset.environment.value()
|
|
|
|
|
: QHash<QString, QString>();
|
2022-05-30 19:04:54 +02:00
|
|
|
|
|
|
|
|
for (auto it = presetEnv.constKeyValueBegin(); it != presetEnv.constKeyValueEnd(); ++it) {
|
|
|
|
|
const QString key = it->first;
|
|
|
|
|
QString value = it->second;
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
expandAllButEnv(preset, sourceDirectory, value);
|
2022-09-30 15:01:58 +02:00
|
|
|
value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) {
|
|
|
|
|
return presetEnv.value(macroName);
|
|
|
|
|
});
|
2022-05-30 19:04:54 +02:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-30 15:01:58 +02:00
|
|
|
value = expandMacroEnv("penv", value, [](const QString ¯oName) {
|
|
|
|
|
return QString("${%1}").arg(macroName);
|
|
|
|
|
});
|
2022-05-30 19:04:54 +02:00
|
|
|
|
|
|
|
|
envItems.emplace_back(Utils::EnvironmentItem(key, value, operation));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
template<class PresetType>
|
|
|
|
|
void expand(const PresetType &preset,
|
2022-05-30 19:04:54 +02:00
|
|
|
const Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory,
|
|
|
|
|
QString &value)
|
|
|
|
|
{
|
2022-09-05 20:09:12 +02:00
|
|
|
expandAllButEnv(preset, sourceDirectory, value);
|
2022-05-30 19:04:54 +02:00
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
const QHash<QString, QString> presetEnv = preset.environment ? preset.environment.value()
|
|
|
|
|
: QHash<QString, QString>();
|
2022-05-30 19:04:54 +02:00
|
|
|
|
2022-09-30 15:01:58 +02:00
|
|
|
value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) {
|
|
|
|
|
return presetEnv.value(macroName);
|
|
|
|
|
});
|
2022-05-30 19:04:54 +02:00
|
|
|
|
2022-09-30 15:01:58 +02:00
|
|
|
value = expandMacroEnv("penv", value, [env](const QString ¯oName) {
|
|
|
|
|
return env.value(macroName);
|
|
|
|
|
});
|
2022-05-30 19:04:54 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-26 18:59:04 +02:00
|
|
|
void updateToolchainFile(
|
|
|
|
|
CMakeProjectManager::Internal::PresetsDetails::ConfigurePreset &configurePreset,
|
|
|
|
|
const Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory,
|
|
|
|
|
const Utils::FilePath &buildDirectory)
|
|
|
|
|
{
|
|
|
|
|
if (!configurePreset.toolchainFile)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QString toolchainFileName = configurePreset.toolchainFile.value();
|
|
|
|
|
CMakePresets::Macros::expand(configurePreset, env, sourceDirectory, toolchainFileName);
|
|
|
|
|
|
|
|
|
|
// Resolve the relative path first to source and afterwards to build directory
|
|
|
|
|
Utils::FilePath toolchainFile = Utils::FilePath::fromString(toolchainFileName);
|
|
|
|
|
if (toolchainFile.isRelativePath()) {
|
|
|
|
|
for (const auto &path : {sourceDirectory, buildDirectory}) {
|
|
|
|
|
Utils::FilePath probePath = toolchainFile.resolvePath(path);
|
|
|
|
|
if (probePath.exists() && probePath != path) {
|
|
|
|
|
toolchainFile = probePath;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!toolchainFile.exists())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// toolchainFile takes precedence to CMAKE_TOOLCHAIN_FILE
|
|
|
|
|
CMakeConfig cache = configurePreset.cacheVariables ? configurePreset.cacheVariables.value()
|
|
|
|
|
: CMakeConfig();
|
|
|
|
|
|
|
|
|
|
auto it = std::find_if(cache.begin(), cache.end(), [](const CMakeConfigItem &item) {
|
|
|
|
|
return item.key == "CMAKE_TOOLCHAIN_FILE";
|
|
|
|
|
});
|
|
|
|
|
if (it != cache.end())
|
|
|
|
|
it->value = toolchainFile.toString().toUtf8();
|
|
|
|
|
else
|
|
|
|
|
cache << CMakeConfigItem("CMAKE_TOOLCHAIN_FILE",
|
|
|
|
|
CMakeConfigItem::FILEPATH,
|
|
|
|
|
toolchainFile.toString().toUtf8());
|
|
|
|
|
|
|
|
|
|
configurePreset.cacheVariables = cache;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class PresetType>
|
|
|
|
|
void expandConditionValues(const PresetType &preset,
|
|
|
|
|
const Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory,
|
|
|
|
|
PresetsDetails::Condition &condition)
|
|
|
|
|
{
|
|
|
|
|
if (condition.isEquals() || condition.isNotEquals()) {
|
|
|
|
|
if (condition.lhs)
|
|
|
|
|
expand(preset, env, sourceDirectory, condition.lhs.value());
|
|
|
|
|
if (condition.rhs)
|
|
|
|
|
expand(preset, env, sourceDirectory, condition.rhs.value());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (condition.isInList() || condition.isNotInList()) {
|
|
|
|
|
if (condition.string)
|
|
|
|
|
expand(preset, env, sourceDirectory, condition.string.value());
|
|
|
|
|
if (condition.list)
|
|
|
|
|
for (QString &listValue : condition.list.value())
|
|
|
|
|
expand(preset, env, sourceDirectory, listValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (condition.isMatches() || condition.isNotMatches()) {
|
|
|
|
|
if (condition.string)
|
|
|
|
|
expand(preset, env, sourceDirectory, condition.string.value());
|
|
|
|
|
if (condition.regex)
|
|
|
|
|
expand(preset, env, sourceDirectory, condition.regex.value());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (condition.isAnyOf() || condition.isAllOf()) {
|
|
|
|
|
if (condition.conditions)
|
|
|
|
|
for (PresetsDetails::Condition::ConditionPtr &c : condition.conditions.value())
|
|
|
|
|
expandConditionValues(preset, env, sourceDirectory, *c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (condition.isNot()) {
|
|
|
|
|
if (condition.condition)
|
|
|
|
|
expandConditionValues(preset, env, sourceDirectory, *condition.condition.value());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class PresetType>
|
|
|
|
|
bool evaluatePresetCondition(const PresetType &preset, const Utils::FilePath &sourceDirectory)
|
|
|
|
|
{
|
|
|
|
|
if (!preset.condition)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
Utils::Environment env = Utils::Environment::systemEnvironment();
|
|
|
|
|
expand(preset, env, sourceDirectory);
|
|
|
|
|
|
|
|
|
|
PresetsDetails::Condition condition = preset.condition.value();
|
|
|
|
|
expandConditionValues(preset, env, sourceDirectory, condition);
|
|
|
|
|
|
|
|
|
|
return condition.evaluate();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
// Expand for PresetsDetails::ConfigurePreset
|
|
|
|
|
template void expand<PresetsDetails::ConfigurePreset>(const PresetsDetails::ConfigurePreset &preset,
|
|
|
|
|
Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory);
|
|
|
|
|
|
|
|
|
|
template void expand<PresetsDetails::ConfigurePreset>(const PresetsDetails::ConfigurePreset &preset,
|
|
|
|
|
Utils::EnvironmentItems &envItems,
|
|
|
|
|
const Utils::FilePath &sourceDirectory);
|
|
|
|
|
|
|
|
|
|
template void expand<PresetsDetails::ConfigurePreset>(const PresetsDetails::ConfigurePreset &preset,
|
|
|
|
|
const Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory,
|
|
|
|
|
QString &value);
|
|
|
|
|
|
2022-09-26 18:59:04 +02:00
|
|
|
template bool evaluatePresetCondition<PresetsDetails::ConfigurePreset>(
|
|
|
|
|
const PresetsDetails::ConfigurePreset &preset, const Utils::FilePath &sourceDirectory);
|
|
|
|
|
|
2022-09-05 20:09:12 +02:00
|
|
|
// Expand for PresetsDetails::BuildPreset
|
|
|
|
|
template void expand<PresetsDetails::BuildPreset>(const PresetsDetails::BuildPreset &preset,
|
|
|
|
|
Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory);
|
|
|
|
|
|
|
|
|
|
template void expand<PresetsDetails::BuildPreset>(const PresetsDetails::BuildPreset &preset,
|
|
|
|
|
Utils::EnvironmentItems &envItems,
|
|
|
|
|
const Utils::FilePath &sourceDirectory);
|
|
|
|
|
|
|
|
|
|
template void expand<PresetsDetails::BuildPreset>(const PresetsDetails::BuildPreset &preset,
|
|
|
|
|
const Utils::Environment &env,
|
|
|
|
|
const Utils::FilePath &sourceDirectory,
|
|
|
|
|
QString &value);
|
|
|
|
|
|
2022-09-26 18:59:04 +02:00
|
|
|
template bool evaluatePresetCondition<PresetsDetails::BuildPreset>(
|
|
|
|
|
const PresetsDetails::BuildPreset &preset, const Utils::FilePath &sourceDirectory);
|
|
|
|
|
|
2022-05-30 19:04:54 +02:00
|
|
|
} // namespace CMakeProjectManager::Internal::CMakePresets::Macros
|