diff --git a/src/plugins/mcusupport/mcuabstractpackage.h b/src/plugins/mcusupport/mcuabstractpackage.h index eed4132fe8f..2a09cd45077 100644 --- a/src/plugins/mcusupport/mcuabstractpackage.h +++ b/src/plugins/mcusupport/mcuabstractpackage.h @@ -57,6 +57,7 @@ public: virtual Utils::FilePath basePath() const = 0; virtual Utils::FilePath path() const = 0; + virtual void setPath(const Utils::FilePath &) = 0; virtual Utils::FilePath defaultPath() const = 0; virtual Utils::FilePath detectionPath() const = 0; virtual QString settingsKey() const = 0; diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp index 5cc90925e1e..2ebf1283c9b 100644 --- a/src/plugins/mcusupport/mcupackage.cpp +++ b/src/plugins/mcusupport/mcupackage.cpp @@ -124,7 +124,7 @@ FilePath McuPackage::basePath() const FilePath McuPackage::path() const { - return (basePath() / m_relativePathModifier.path()).absoluteFilePath().cleanPath(); + return (basePath() / m_relativePathModifier.path()).cleanPath(); } FilePath McuPackage::defaultPath() const @@ -137,6 +137,13 @@ FilePath McuPackage::detectionPath() const return m_detectionPath; } +void McuPackage::setPath(const FilePath &newPath) +{ + m_path = newPath; + m_defaultPath = newPath; + updateStatus(); +} + void McuPackage::updatePath() { m_path = m_fileChooser->rawFilePath(); diff --git a/src/plugins/mcusupport/mcupackage.h b/src/plugins/mcusupport/mcupackage.h index accf478277b..8ccf71c74bf 100644 --- a/src/plugins/mcusupport/mcupackage.h +++ b/src/plugins/mcusupport/mcupackage.h @@ -90,6 +90,8 @@ public: QWidget *widget() override; const McuPackageVersionDetector *getVersionDetector() const override; + void setPath(const Utils::FilePath &); + private: void updatePath(); void updateStatusUi(); @@ -100,7 +102,7 @@ private: Utils::InfoLabel *m_infoLabel = nullptr; const QString m_label; - const Utils::FilePath m_defaultPath; + Utils::FilePath m_defaultPath; const Utils::FilePath m_detectionPath; const QString m_settingsKey; QScopedPointer m_versionDetector; diff --git a/src/plugins/mcusupport/mcutargetfactory.cpp b/src/plugins/mcusupport/mcutargetfactory.cpp index c0bb204620f..09c4583c2cd 100644 --- a/src/plugins/mcusupport/mcutargetfactory.cpp +++ b/src/plugins/mcusupport/mcutargetfactory.cpp @@ -78,6 +78,34 @@ McuPackageVersionDetector *createVersionDetection(const VersionDetection &versio versionDetection.isFile); } +static void evaluateVariables(McuTarget &target) +{ + const static QRegularExpression variableRegex{R"(\${*\w+}*)", + QRegularExpression::CaseInsensitiveOption}; + + for (const auto &package : target.packages()) { + const QRegularExpressionMatch match{variableRegex.match(package->path().toString())}; + if (!match.hasMatch()) + continue; + const QString variable{match.captured(0).remove(0, 1)}; + + McuPackagePtr packageDefiningVariable{ + Utils::findOrDefault(target.packages(), [variable](const McuPackagePtr &pkg) { + return pkg->cmakeVariableName() == variable; + // return pkg->cmakeVariableName() == variable || pkg->environmentVariableName() == variable; + })}; + + if (packageDefiningVariable == nullptr) // nothing provides the variable + continue; + + const auto evaluatedPath{Utils::FilePath::fromUserInput( + package->path().toString().replace(match.capturedStart(), + match.capturedLength(), + packageDefiningVariable->path().toString()))}; + package->setPath(evaluatedPath); + } +} + McuTargetFactory::McuTargetFactory(const SettingsHandler::Ptr &settingsHandler) : settingsHandler{settingsHandler} {} @@ -102,13 +130,17 @@ QPair McuTargetFactory::createTargets(const McuTargetDescript targetPackages.insert({toolchainPtr}); targetPackages.unite({toolchainFile}); packages.unite(targetPackages); - mcuTargets.append(McuTargetPtr{new McuTarget{QVersionNumber::fromString(desc.qulVersion), - platform, - deduceOperatingSystem(desc), - targetPackages, - toolchainPtr, - toolchainFile, - colorDepth}}); + + McuTargetPtr target{new McuTarget{QVersionNumber::fromString(desc.qulVersion), + platform, + deduceOperatingSystem(desc), + targetPackages, + toolchainPtr, + toolchainFile, + colorDepth}}; + + evaluateVariables(*target); + mcuTargets.append(target); } return {mcuTargets, packages}; } diff --git a/src/plugins/mcusupport/mcutargetfactorylegacy.cpp b/src/plugins/mcusupport/mcutargetfactorylegacy.cpp index 8bf8b297756..00eafee9337 100644 --- a/src/plugins/mcusupport/mcutargetfactorylegacy.cpp +++ b/src/plugins/mcusupport/mcutargetfactorylegacy.cpp @@ -76,7 +76,7 @@ QPair McuTargetFactory::createTargets(const McuTargetDescript boardSdkPkgs.insert(desc.boardSdk.envVar, boardSdkPkg); } McuPackagePtr boardSdkPkg{boardSdkPkgs.value(desc.boardSdk.envVar)}; - boardSdkDefaultPath = boardSdkPkg->defaultPath(); + boardSdkDefaultPath = boardSdkPkg->path(); required3rdPartyPkgs.insert(boardSdkPkg); } diff --git a/src/plugins/mcusupport/test/armgcc_stm32f769i_freertos_json.h b/src/plugins/mcusupport/test/armgcc_stm32f769i_freertos_json.h index ec4b1de0812..e67d40f00e7 100644 --- a/src/plugins/mcusupport/test/armgcc_stm32f769i_freertos_json.h +++ b/src/plugins/mcusupport/test/armgcc_stm32f769i_freertos_json.h @@ -53,6 +53,7 @@ constexpr auto armgcc_stm32f769i_freertos_json = R"({ "id": "Qul_DIR", "label": "Qt for MCUs SDK", "type": "path", + "setting": "QtForMCUsSdk", "cmakeVar": "Qul_ROOT", "optional": false } @@ -83,7 +84,7 @@ constexpr auto armgcc_stm32f769i_freertos_json = R"({ "label": "CMake Toolchain File", "cmakeVar": "CMAKE_TOOLCHAIN_FILE", "type": "file", - "defaultValue": "/opt/qtformcu/2.2//lib/cmake/Qul/toolchain/armgcc.cmake", + "defaultValue": "$Qul_ROOT//lib/cmake/Qul/toolchain/armgcc.cmake", "visible": false, "optional": false } diff --git a/src/plugins/mcusupport/test/packagemock.h b/src/plugins/mcusupport/test/packagemock.h index 0a3744d0697..39af0aa5c16 100644 --- a/src/plugins/mcusupport/test/packagemock.h +++ b/src/plugins/mcusupport/test/packagemock.h @@ -37,6 +37,7 @@ class PackageMock : public McuAbstractPackage public: MOCK_METHOD(Utils::FilePath, basePath, (), (const)); MOCK_METHOD(Utils::FilePath, path, (), (const)); + MOCK_METHOD(void, setPath, (const Utils::FilePath &) ); MOCK_METHOD(QString, label, (), (const)); MOCK_METHOD(Utils::FilePath, defaultPath, (), (const)); MOCK_METHOD(Utils::FilePath, detectionPath, (), (const)); diff --git a/src/plugins/mcusupport/test/unittest.cpp b/src/plugins/mcusupport/test/unittest.cpp index f761140daf0..3c7be253a5b 100644 --- a/src/plugins/mcusupport/test/unittest.cpp +++ b/src/plugins/mcusupport/test/unittest.cpp @@ -79,7 +79,10 @@ const char armGccDirectorySetting[]{"GNUArmEmbeddedToolchain"}; const char armGccEnvVar[]{"ARMGCC_DIR"}; const char armGccLabel[]{"GNU Arm Embedded Toolchain"}; const char armGccSuffix[]{"bin/arm-none-eabi-g++"}; -const char armGccToolchainFilePath[]{"/opt/qtformcu/2.2/lib/cmake/Qul/toolchain/armgcc.cmake"}; +const char armGccToolchainFilePath[]{"/opt/toolchain/armgcc.cmake"}; +const char armGccToolchainFileDefaultPath[]{ + "/opt/qtformcu/2.2/lib/cmake/Qul/toolchain/armgcc.cmake"}; +const char armGccToolchainFilePathWithVariable[]{"$Qul_ROOT/lib/cmake/Qul/toolchain/armgcc.cmake"}; const char armGccVersion[]{"9.3.1"}; const char armGccNewVersion[]{"10.3.1"}; const char msvcVersion[]{"14.29"}; @@ -92,7 +95,9 @@ const char freeRtosEnvVar[]{"EVK_MIMXRT1170_FREERTOS_PATH"}; const char freeRtosLabel[]{"FreeRTOS directory"}; const char freeRtosPath[]{"/opt/freertos/default"}; const char freeRtosSetting[]{"Freertos"}; -const char greenhillToolchainFilePath[]{"/opt/qtformcu/2.2/lib/cmake/Qul/toolchain/ghs.cmake"}; +const char greenhillToolchainFilePath[]{"/opt/toolchain/ghs.cmake"}; +const char greenhillToolchainFileDefaultPath[]{ + "/opt/qtformcu/2.2/lib/cmake/Qul/toolchain/ghs.cmake"}; const char greenhillCompilerDir[]{"/abs/ghs"}; const char greenhillSetting[]{"GHSToolchain"}; const QStringList greenhillVersions{{"2018.1.5"}}; @@ -100,7 +105,8 @@ const char iarDir[]{"/opt/iar/compiler"}; const char iarEnvVar[]{"IAR_ARM_COMPILER_DIR"}; const char iarLabel[]{"IAR ARM Compiler"}; const char iarSetting[]{"IARToolchain"}; -const char iarToolchainFilePath[]{"/opt/qtformcu/2.2/lib/cmake/Qul/toolchain/iar.cmake"}; +const char iarToolchainFilePath[]{"/opt/toolchain/iar.cmake"}; +const char iarToolchainFileDefaultPath[]{"/opt/qtformcu/2.2/lib/cmake/Qul/toolchain/iar.cmake"}; const char iarVersionDetectionRegex[]{R"(\bV(\d+\.\d+\.\d+)\.\d+\b)"}; const QStringList iarVersions{{"8.50.9"}}; const char iar[]{"iar"}; @@ -247,6 +253,7 @@ void verifyTargetToolchains(const Targets &targets, QCOMPARE(toolchainFile->cmakeVariableName(), Legacy::Constants::TOOLCHAIN_FILE_CMAKE_VARIABLE); QCOMPARE(toolchainFile->settingsKey(), empty); QCOMPARE(toolchainFile->path().toString(), toolchainFilePath); + QCOMPARE(toolchainFile->defaultPath().toString(), toolchainFilePath); const auto toolchainCompiler{target->toolChainPackage()}; QVERIFY(toolchainCompiler); @@ -393,26 +400,26 @@ void McuSupportTest::test_parseToolchainFromJSON_data() QTest::addColumn("json"); QTest::addColumn("environmentVariable"); QTest::addColumn("label"); - QTest::addColumn("toolchainFile"); + QTest::addColumn("toolchainFileDefaultPath"); QTest::addColumn("id"); //TODO(me): Add ghs nxp 1064 nxp 1070. - QTest::newRow("armgcc_nxp_1050_json") - << armgcc_nxp_1050_json << armGccEnvVar << armGccLabel << armGccToolchainFilePath << armGcc; + QTest::newRow("armgcc_nxp_1050_json") << armgcc_nxp_1050_json << armGccEnvVar << armGccLabel + << armGccToolchainFileDefaultPath << armGcc; QTest::newRow("armgcc_stm32f769i_freertos_json") - << armgcc_stm32f769i_freertos_json << armGccEnvVar << armGccLabel << armGccToolchainFilePath - << armGcc; + << armgcc_stm32f769i_freertos_json << armGccEnvVar << armGccLabel + << armGccToolchainFilePathWithVariable << armGcc; QTest::newRow("armgcc_stm32h750b_metal_json") - << armgcc_stm32h750b_metal_json << armGccEnvVar << armGccLabel << armGccToolchainFilePath - << armGcc; + << armgcc_stm32h750b_metal_json << armGccEnvVar << armGccLabel + << armGccToolchainFileDefaultPath << armGcc; QTest::newRow("armgcc_nxp_mimxrt1170_evk_freertos_json") << armgcc_nxp_mimxrt1170_evk_freertos_json << armGccEnvVar << armGccLabel - << armGccToolchainFilePath << armGcc; + << armGccToolchainFileDefaultPath << armGcc; QTest::newRow("iar_stm32f469i_metal_json") - << iar_stm32f469i_metal_json << iarEnvVar << iarLabel << iarToolchainFilePath << iar; + << iar_stm32f469i_metal_json << iarEnvVar << iarLabel << iarToolchainFileDefaultPath << iar; } void McuSupportTest::test_parseToolchainFromJSON() @@ -420,8 +427,9 @@ void McuSupportTest::test_parseToolchainFromJSON() QFETCH(QString, json); QFETCH(QString, environmentVariable); QFETCH(QString, label); - QFETCH(QString, toolchainFile); + QFETCH(QString, toolchainFileDefaultPath); QFETCH(QString, id); + McuTargetDescription description{parseDescriptionJson(json.toLocal8Bit())}; QCOMPARE(description.toolchain.id, id); @@ -433,7 +441,7 @@ void McuSupportTest::test_parseToolchainFromJSON() QCOMPARE(toolchainFilePackage.label, cmakeToolchainLabel); QCOMPARE(toolchainFilePackage.envVar, QString{}); QCOMPARE(toolchainFilePackage.cmakeVar, Legacy::Constants::TOOLCHAIN_FILE_CMAKE_VARIABLE); - QCOMPARE(toolchainFilePackage.defaultPath.cleanPath().toString(), toolchainFile); + QCOMPARE(toolchainFilePackage.defaultPath.cleanPath().toString(), toolchainFileDefaultPath); } void McuSupportTest::test_legacy_createIarToolchain() @@ -836,22 +844,22 @@ void McuSupportTest::test_legacy_createTargetWithToolchainPackages_data() QTest::addColumn("compilerSetting"); QTest::addColumn("versions"); - QTest::newRow("nxp1050") << armgcc_nxp_1050_json << armGccToolchainFilePath << armGccDir + QTest::newRow("nxp1050") << armgcc_nxp_1050_json << armGccToolchainFileDefaultPath << armGccDir << armGccDirectorySetting << QStringList{armGccVersion, armGccNewVersion}; - QTest::newRow("stm32h750b") << armgcc_stm32h750b_metal_json << armGccToolchainFilePath + QTest::newRow("stm32h750b") << armgcc_stm32h750b_metal_json << armGccToolchainFileDefaultPath << armGccDir << armGccDirectorySetting << QStringList{armGccVersion}; - QTest::newRow("stm32f769i") << armgcc_stm32f769i_freertos_json << armGccToolchainFilePath + QTest::newRow("stm32f769i") << armgcc_stm32f769i_freertos_json << armGccToolchainFileDefaultPath << armGccDir << armGccDirectorySetting << QStringList{armGccVersion, armGccNewVersion}; - QTest::newRow("stm32f469i") << iar_stm32f469i_metal_json << iarToolchainFilePath << iarDir - << iarSetting << iarVersions; + QTest::newRow("stm32f469i") << iar_stm32f469i_metal_json << iarToolchainFileDefaultPath + << iarDir << iarSetting << iarVersions; QTest::newRow("iar_nxp_1064_json") - << iar_nxp_1064_json << iarToolchainFilePath << iarDir << iarSetting << iarVersions; + << iar_nxp_1064_json << iarToolchainFileDefaultPath << iarDir << iarSetting << iarVersions; QTest::newRow("ghs_rh850_d1m1a_baremetal_json") - << ghs_rh850_d1m1a_baremetal_json << greenhillToolchainFilePath << greenhillCompilerDir - << greenhillSetting << greenhillVersions; + << ghs_rh850_d1m1a_baremetal_json << greenhillToolchainFileDefaultPath + << greenhillCompilerDir << greenhillSetting << greenhillVersions; } void McuSupportTest::test_legacy_createTargetWithToolchainPackages() @@ -893,8 +901,9 @@ void McuSupportTest::test_createTargetWithToolchainPackages() EXPECT_CALL(*settingsMockPtr, getPath(compilerSetting, _, _)) .WillRepeatedly(Return(FilePath::fromUserInput(compilerPath))); - EXPECT_CALL(*settingsMockPtr, getPath(compilerSetting, _, _)) - .WillRepeatedly(Return(FilePath::fromUserInput(compilerPath))); + EXPECT_CALL(*settingsMockPtr, + getPath(QString{Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK}, _, _)) + .WillRepeatedly(Return(FilePath::fromUserInput(qtForMcuSdkPath))); const McuTargetDescription description = parseDescriptionJson(json.toLocal8Bit()); const auto [targets, packages]{ @@ -1134,4 +1143,35 @@ void McuSupportTest::test_passDirectoryVersionDetectorToRenesasBoardSdkPackage() QCOMPARE(typeid(*versionDetector).name(), typeid(McuPackageDirectoryVersionDetector).name()); } +void McuSupportTest::test_resolveEnvironmentVariablesInDefaultPaths() +{ + QVERIFY(qputenv(qulEnvVar, qtForMcuSdkPath)); + QCOMPARE(qEnvironmentVariable(qulEnvVar), qtForMcuSdkPath); + + toochainFileDescription.defaultPath = "$Qul_ROOT/lib/cmake/Qul/toolchain/iar.cmake"; + targetDescription.toolchain.file = toochainFileDescription; + + auto [targets, packages] = targetFactory.createTargets(targetDescription, qtForMcuSdkPath); + auto qtForMCUPkg = findOrDefault(packages, [](const McuPackagePtr &pkg) { + return (pkg->cmakeVariableName() == Legacy::Constants::QUL_ENV_VAR); + }); + + QVERIFY(qtForMCUPkg); + QCOMPARE(qtForMCUPkg->path().toString(), qtForMcuSdkPath); + + auto toolchainFilePkg = findOrDefault(packages, [](const McuPackagePtr &pkg) { + return (pkg->cmakeVariableName() == Legacy::Constants::TOOLCHAIN_FILE_CMAKE_VARIABLE); + }); + + QVERIFY(toolchainFilePkg); + QVERIFY(targets.size() == 1); + + QString expectedPkgPath = QString{qtForMcuSdkPath} + "/lib/cmake/Qul/toolchain/iar.cmake"; + QCOMPARE(toolchainFilePkg->path().toString(), expectedPkgPath); + QVERIFY(toolchainFilePkg->path().toString().startsWith(qtForMcuSdkPath)); + QCOMPARE(toolchainFilePkg->defaultPath().toString(), expectedPkgPath); + + QVERIFY(qunsetenv(qulEnvVar)); +} + } // namespace McuSupport::Internal::Test diff --git a/src/plugins/mcusupport/test/unittest.h b/src/plugins/mcusupport/test/unittest.h index f810d9cb351..8edfda13874 100644 --- a/src/plugins/mcusupport/test/unittest.h +++ b/src/plugins/mcusupport/test/unittest.h @@ -106,6 +106,8 @@ private slots: void test_createBoardSdk_data(); void test_createBoardSdk(); + void test_resolveEnvironmentVariablesInDefaultPaths(); + private: QVersionNumber currentQulVersion{2, 0}; PackageMock *freeRtosPackage{new PackageMock};