diff --git a/src/plugins/cmakeprojectmanager/presetsmacros.cpp b/src/plugins/cmakeprojectmanager/presetsmacros.cpp index 37ef043c12e..2623a0cfed1 100644 --- a/src/plugins/cmakeprojectmanager/presetsmacros.cpp +++ b/src/plugins/cmakeprojectmanager/presetsmacros.cpp @@ -8,8 +8,6 @@ #include #include -#include - namespace CMakeProjectManager::Internal::CMakePresets::Macros { QString getHostSystemName() @@ -61,6 +59,48 @@ void expandAllButEnv(const PresetsDetails::BuildPreset &preset, value.replace("${presetName}", preset.name); } +QString expandMacroEnv(const QString ¯oPrefix, + const QString &value, + const std::function &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; +} + template void expand(const PresetType &preset, Utils::Environment &env, @@ -73,14 +113,9 @@ void expand(const PresetType &preset, QString value = it->second; expandAllButEnv(preset, 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), ""); - } + value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) { + return presetEnv.value(macroName); + }); QString sep; bool append = true; @@ -92,9 +127,9 @@ void expand(const PresetType &preset, 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))); + value = expandMacroEnv("penv", value, [env](const QString ¯oName) { + return env.value(macroName); + }); if (append) env.appendOrSet(key, value, sep); @@ -116,14 +151,9 @@ void expand(const PresetType &preset, QString value = it->second; expandAllButEnv(preset, 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), ""); - } + value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) { + return presetEnv.value(macroName); + }); auto operation = Utils::EnvironmentItem::Operation::SetEnabled; if (key.compare("PATH", Qt::CaseInsensitive) == 0) { @@ -134,9 +164,9 @@ void expand(const PresetType &preset, 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))); + value = expandMacroEnv("penv", value, [](const QString ¯oName) { + return QString("${%1}").arg(macroName); + }); envItems.emplace_back(Utils::EnvironmentItem(key, value, operation)); } @@ -153,13 +183,13 @@ void expand(const PresetType &preset, const QHash presetEnv = preset.environment ? preset.environment.value() : QHash(); - QRegularExpression envRegex(R"((\$env\{(\w+)\}))"); - for (const QRegularExpressionMatch &match : envRegex.globalMatch(value)) - value.replace(match.captured(1), presetEnv.value(match.captured(2))); + value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) { + return presetEnv.value(macroName); + }); - QRegularExpression penvRegex(R"((\$penv\{(\w+)\}))"); - for (const QRegularExpressionMatch &match : penvRegex.globalMatch(value)) - value.replace(match.captured(1), env.value(match.captured(2))); + value = expandMacroEnv("penv", value, [env](const QString ¯oName) { + return env.value(macroName); + }); } void updateToolchainFile( @@ -261,7 +291,6 @@ bool evaluatePresetCondition(const PresetType &preset, const Utils::FilePath &so return condition.evaluate(); } - // Expand for PresetsDetails::ConfigurePreset template void expand(const PresetsDetails::ConfigurePreset &preset, Utils::Environment &env, diff --git a/tests/manual/cmakepresets/CMakePresets.json b/tests/manual/cmakepresets/CMakePresets.json index 64e5a6bc965..5e9d149b8bb 100644 --- a/tests/manual/cmakepresets/CMakePresets.json +++ b/tests/manual/cmakepresets/CMakePresets.json @@ -54,6 +54,34 @@ "HOST_SYSTEM_NAME": "Windows" } }, + { + "name": "visualc-ninja", + "displayName": "Visual C++ 2019 x64 Ninja", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-${presetName}", + "toolchainFile" : "c:/Qt/6.3.2/msvc2019_64/lib/cmake/Qt6/qt.toolchain.cmake", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "environment" : { + "VCToolsVersion": "14.29.30133", + "WindowsSDKVersion" : "10.0.22000.0", + "VCArch": "x64", + "VCToolsInstallDir": "$penv{ProgramFiles(x86)}/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/$env{VCToolsVersion}", + "WindowsSdkDir" : "$penv{ProgramFiles(x86)}/Windows Kits/10", + "WindowsSdkIncVerDir": "$env{WindowsSdkDir}/Include/$env{WindowsSDKVersion}", + "WindowsSdkLibVerDir": "$env{WindowsSdkDir}/Lib/$env{WindowsSDKVersion}", + + "INCLUDE": "$env{VCToolsInstallDir}/ATLMFC/include;$env{VCToolsInstallDir}/include;$env{WindowsSdkIncVerDir}/ucrt;$env{WindowsSdkIncVerDir}/shared;$env{WindowsSdkIncVerDir}/um;$env{WindowsSdkIncVerDir}/winrt;$env{WindowsSdkIncVerDir}/cppwinrt", + "LIB": "$env{VCToolsInstallDir}/ATLMFC/lib/$env{VCArch};$env{VCToolsInstallDir}/lib/$env{VCArch};$env{WindowsSdkLibVerDir}/ucrt/$env{VCArch};$env{WindowsSdkLibVerDir}/um/$env{VCArch}", + "PATH": "$env{VCToolsInstallDir}/bin/HostX64/$env{VCArch};$env{WindowsSdkDir}/bin/$env{WindowsSDKVersion}/$env{VCArch};$penv{PATH}" + } + }, { "name": "linux-gcc", "displayName": "Linux GCC", @@ -95,6 +123,10 @@ "name": "visualc-relwithdebinfo", "inherits": "visualc-debug", "configuration": "RelWithDebInfo" + }, + { + "name": "visualc-ninja", + "configurePreset": "visualc-ninja" } ] } diff --git a/tests/manual/cmakepresets/mainwindow.ui b/tests/manual/cmakepresets/mainwindow.ui index b232854ba81..a736849d4e7 100644 --- a/tests/manual/cmakepresets/mainwindow.ui +++ b/tests/manual/cmakepresets/mainwindow.ui @@ -13,8 +13,36 @@ MainWindow - - + + + + + 140 + 200 + 441 + 81 + + + + + 22 + + + + CMakePresets are cool! + + + + + + + 0 + 0 + 800 + 22 + + +