diff --git a/libs/rtemodel/include/RteGenerator.h b/libs/rtemodel/include/RteGenerator.h index 8fc6f3291..75bcebc34 100644 --- a/libs/rtemodel/include/RteGenerator.h +++ b/libs/rtemodel/include/RteGenerator.h @@ -64,10 +64,11 @@ class RteGenerator : public RteItem /** * @brief get expanded generator executable command + * @param target pointer to RteTarget * @param hostType host type to match, empty to match current host * @return generator command for specified host type */ - virtual std::string GetExecutable(const std::string& hostType = EMPTY_STRING) const; + std::string GetExecutable(RteTarget* target, const std::string& hostType = EMPTY_STRING) const; /** * @brief get item containing command line arguments @@ -139,19 +140,21 @@ class RteGenerator : public RteItem /** * @brief get all arguments as vector for the given host type + * @param target pointer to RteTarget * @param hostType host type, empty to match current host * @param dryRun include dry-run arguments * @return vector of arguments consisting of switch and value in pairs */ - std::vector > GetExpandedArguments(const std::string& hostType = EMPTY_STRING, bool dryRun = false) const; + std::vector > GetExpandedArguments(RteTarget* target,const std::string& hostType = EMPTY_STRING, bool dryRun = false) const; /** * @brief get full command line with arguments and expanded key sequences for specified target + * @param target pointer to RteTarget * @param hostType host type, empty to match current host * @param dryRun include dry-run arguments * @return expanded command line with arguments, properly quoted */ - std::string GetExpandedCommandLine(const std::string& hostType = EMPTY_STRING, bool dryRun = false) const; + std::string GetExpandedCommandLine(RteTarget* target, const std::string& hostType = EMPTY_STRING, bool dryRun = false) const; /** * @brief get absolute path to gpdsc file for specified target diff --git a/libs/rtemodel/include/RteItem.h b/libs/rtemodel/include/RteItem.h index 9fc2ee753..21a00fcbd 100644 --- a/libs/rtemodel/include/RteItem.h +++ b/libs/rtemodel/include/RteItem.h @@ -593,11 +593,14 @@ class RteItem : public XmlTreeItem virtual int GetMaxInstances() const; /** - * @brief expands key sequences ("@L", "%L", etc.) in the supplied string. + * @brief expands key sequences ("@L", "%L", etc.) or access sequences in the supplied string. * @param str string to expand + * @param bUseAccessSequences expand access sequences instead of key sequences, default is false + * @param context pointer to RteItem representing expansion context (optional) * @return expanded string */ - virtual std::string ExpandString(const std::string& str) const; + virtual std::string ExpandString(const std::string& str, + bool bUseAccessSequences = false, RteItem* context = nullptr) const; /** * @brief get item's description diff --git a/libs/rtemodel/include/RteItemBuilder.h b/libs/rtemodel/include/RteItemBuilder.h index 0daac99bd..0a79237a3 100644 --- a/libs/rtemodel/include/RteItemBuilder.h +++ b/libs/rtemodel/include/RteItemBuilder.h @@ -66,7 +66,7 @@ class RteItemBuilder : public XmlTreeItemBuilder */ void SetPackageState(PackageState packState) { m_packState = packState; } -private: +protected: RteItem* m_rootParent; PackageState m_packState; diff --git a/libs/rtemodel/include/RteKernel.h b/libs/rtemodel/include/RteKernel.h index f5d424101..0c9827a6c 100644 --- a/libs/rtemodel/include/RteKernel.h +++ b/libs/rtemodel/include/RteKernel.h @@ -13,6 +13,7 @@ * SPDX-License-Identifier: Apache-2.0 */ /******************************************************************************/ +#include "RteItemBuilder.h" #include "RteModel.h" #include "RteProject.h" #include "RteTarget.h" @@ -260,18 +261,23 @@ class RteKernel std::string GetPdscFileFromPath(const XmlItem& attributes, const std::string& cprjPath, std::string& packId); /** - * @brief create a smart pointer holding an XMLTree pointer to parse XML files + * @brief create a smart pointer holding an XMLTree pointer to parse XML or YAML files * @param itemBuilder pointer to IXmlItemBuilder item factory + * @param ext file extension to define which parser is required: XML (default) or YAML (".yml" or ".yaml") * @return a std::unique_ptr object holding an XMLTree-derived pointer which is nullptr in the default implementation */ - virtual std::unique_ptr CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder = nullptr) const; + virtual std::unique_ptr CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder = nullptr, const std::string& ext= RteUtils::EMPTY_STRING) const; /** - * @brief create a smart pointer holding a YmlTree pointer to parse YAML files - * @param itemBuilder pointer to IXmlItemBuilder item factory - * @return a std::unique_ptr object holding a YmlTree-derived pointer which is nullptr in the default implementation + * @brief create a smart pointer holding an IXmlItemBuilder pointer to be used by XMLTree or YmlTree + * @param rootParent pointer to RteItem to be parent for root items (optional) + * @param packState PackageState value + * @param option pointer to RteItem with options to pass + * @return a std::unique_ptr object holding an RteItemBuilder-derived pointer */ - virtual std::unique_ptr CreateUniqueYmlTree(IXmlItemBuilder* itemBuilder = nullptr) const; + virtual std::unique_ptr CreateUniqueRteItemBuilder(RteItem* rootParent = nullptr, PackageState packState = PackageState::PS_UNKNOWN, + const RteItem& options = RteItem::EMPTY_RTE_ITEM) const; + /** * @brief save active project into cprj file diff --git a/libs/rtemodel/include/RteTarget.h b/libs/rtemodel/include/RteTarget.h index 6028de3c5..783e935dd 100644 --- a/libs/rtemodel/include/RteTarget.h +++ b/libs/rtemodel/include/RteTarget.h @@ -117,6 +117,24 @@ class RteTarget : public RteItem */ void SetTargetSupported(bool supported) { m_bTargetSupported = supported; } + + /** + * @brief expands key sequences ("@L", "%L", etc.) or access sequences in the supplied string. + * @param str string to expand + * @param bUseAccessSequences expand access sequences instead of key sequences, default is false + * @param context pointer to RteItem representing expansion context (optional) + * @return expanded string + */ + std::string ExpandString(const std::string& str, + bool bUseAccessSequences = false, RteItem* context = nullptr) const override; + + /** + * @brief expand string by replacing $keyword$ with corresponding values + * @param src source string to expand + * @return expanded string + */ + std::string ExpandAccessSequences(const std::string& src) const; + /** * @brief return pointer to a filter object of type RteConditionContext * @return pointer to a filter object of type RteConditionContext diff --git a/libs/rtemodel/src/RteGenerator.cpp b/libs/rtemodel/src/RteGenerator.cpp index 328d755d2..aba5ee0ea 100644 --- a/libs/rtemodel/src/RteGenerator.cpp +++ b/libs/rtemodel/src/RteGenerator.cpp @@ -132,7 +132,7 @@ const string RteGenerator::GetCommand(const std::string& hostType) const return GetItemValue("command"); } -string RteGenerator::GetExecutable(const std::string& hostType) const +string RteGenerator::GetExecutable(RteTarget* target, const std::string& hostType) const { string cmd = GetCommand(hostType); if (cmd.empty()) @@ -141,18 +141,29 @@ string RteGenerator::GetExecutable(const std::string& hostType) const if (cmd.find("http:") == 0 || cmd.find("https:") == 0) // a URL? return EMPTY_STRING; // return empty string here , GetExpandedWebLine() will return URL then - cmd = ExpandString(cmd); + if(target && IsExternal()) { + cmd = target->ExpandAccessSequences(cmd); + }else { + cmd = ExpandString(cmd); + } if (RteFsUtils::IsRelative(cmd)) { - cmd = GetAbsolutePackagePath() + cmd; + cmd = RteFsUtils::MakePathCanonical(GetAbsolutePackagePath() + cmd); } return cmd; } -vector > RteGenerator::GetExpandedArguments(const string& hostType, bool dryRun) const +vector > RteGenerator::GetExpandedArguments(RteTarget* target, const string& hostType, bool dryRun) const { vector > args; + if(IsExternal()) { + // add cbuild-gen-idx.yml + string idxFile = target->ExpandAccessSequences("$SolutionDir$/$Project$.$TargetType$.cbuild-gen-idx.yml"); + args.push_back({RteUtils::EMPTY_STRING, idxFile}); + return args; + } + RteItem* argsItem = GetArgumentsItem("exe"); if (argsItem) { for (auto arg : argsItem->GetChildren()) { @@ -166,10 +177,10 @@ vector > RteGenerator::GetExpandedArguments(const string& h return args; } -string RteGenerator::GetExpandedCommandLine(const string& hostType, bool dryRun) const +string RteGenerator::GetExpandedCommandLine(RteTarget* target, const string& hostType, bool dryRun) const { - const vector > args = GetExpandedArguments(hostType, dryRun); - string fullCmd = RteUtils::AddQuotesIfSpace(GetExecutable(hostType)); + string fullCmd = RteUtils::AddQuotesIfSpace(GetExecutable(target, hostType)); + const vector > args = GetExpandedArguments(target, hostType, dryRun); for (size_t i = 0; i < args.size(); i++) { fullCmd += ' ' + RteUtils::AddQuotesIfSpace(args[i].first + args[i].second); } @@ -215,11 +226,16 @@ string RteGenerator::GetExpandedWebLine(RteTarget* target) const string RteGenerator::GetExpandedGpdsc(RteTarget* target, const string& genDir) const { - string gpdsc = GetGpdsc(); - if (gpdsc.empty()) { - gpdsc = target->GetProject()->GetName() + ".gpdsc"; + string gpdsc; + if(IsExternal()) { + gpdsc = target->GetName() + ".cgen.yml"; } else { - gpdsc = ExpandString(gpdsc); + gpdsc = GetGpdsc(); + if(gpdsc.empty()) { + gpdsc = target->GetProject()->GetName() + ".gpdsc"; + } else { + gpdsc = ExpandString(gpdsc); + } } if (!genDir.empty() && fs::path(gpdsc).is_absolute()) { @@ -236,9 +252,9 @@ string RteGenerator::GetExpandedGpdsc(RteTarget* target, const string& genDir) c string RteGenerator::GetExpandedWorkingDir(RteTarget* target, const string& genDir) const { - string wd = genDir.empty() ? ExpandString(GetWorkingDir()) : genDir; + string wd = genDir.empty() ? ExpandString(GetWorkingDir(), IsExternal(), target) : genDir; fs::path path(wd); - if (wd.empty() || path.is_relative()) { + if (wd.empty() || (path.is_relative() && !IsExternal())) { // use project directory wd = target->GetProject()->GetProjectPath() + wd; } diff --git a/libs/rtemodel/src/RteItem.cpp b/libs/rtemodel/src/RteItem.cpp index d5966135f..de950bd95 100644 --- a/libs/rtemodel/src/RteItem.cpp +++ b/libs/rtemodel/src/RteItem.cpp @@ -821,11 +821,13 @@ string RteItem::GetOriginalAbsolutePath(const string& name) const return RteFsUtils::MakePathCanonical(absPath); } -string RteItem::ExpandString(const string& str) const +string RteItem::ExpandString(const string& str, bool bUseAccessSequences, RteItem* context) const { if (str.empty()) return str; - + if(context && context != this) { + return context->ExpandString(str, bUseAccessSequences, context); + } RteCallback* pCallback = GetCallback(); if (pCallback) return pCallback->ExpandString(str); diff --git a/libs/rtemodel/src/RteItemBuilder.cpp b/libs/rtemodel/src/RteItemBuilder.cpp index 5ed21f831..e92e97f8c 100644 --- a/libs/rtemodel/src/RteItemBuilder.cpp +++ b/libs/rtemodel/src/RteItemBuilder.cpp @@ -32,7 +32,7 @@ RteItemBuilder::RteItemBuilder(RteItem* rootParent, PackageState packState) : RteItem* RteItemBuilder::CreateRootItem(const string& tag) { RteItem* pRoot = nullptr; - if (tag == "package") { + if (tag == "package" || tag == "generator-import") { RtePackage* pack = new RtePackage(m_rootParent, m_packState); m_packs.push_back(pack); pRoot = pack; diff --git a/libs/rtemodel/src/RteKernel.cpp b/libs/rtemodel/src/RteKernel.cpp index 7ee86ca7c..595a82dcf 100644 --- a/libs/rtemodel/src/RteKernel.cpp +++ b/libs/rtemodel/src/RteKernel.cpp @@ -210,14 +210,14 @@ CprjFile* RteKernel::ParseCprj(const string& cprjFile) { string msg = "Loading '" + cprjFile + "'"; GetRteCallback()->OutputInfoMessage(msg); - RteItemBuilder rteItemBuilder; - unique_ptr xmlTree = CreateUniqueXmlTree(&rteItemBuilder); + auto rteItemBuilder = CreateUniqueRteItemBuilder(); + unique_ptr xmlTree = CreateUniqueXmlTree(rteItemBuilder.get()); if (!xmlTree->AddFileName(cprjFile, true)) { GetRteCallback()->Err("R811", R811, cprjFile); GetRteCallback()->OutputMessages(xmlTree->GetErrorStrings()); return nullptr; } - CprjFile* cprj = rteItemBuilder.GetCprjFile(); + CprjFile* cprj = rteItemBuilder->GetCprjFile(); if (!cprj || !cprj->Validate()) { GetRteCallback()->Err("R812", R812, cprjFile); @@ -254,14 +254,14 @@ void RteKernel::LoadExternalGenerators() list files; RteFsUtils::GetMatchingFiles(files, ".generator.yml", etcDir, 1, true); RteGlobalModel* globalModel = GetGlobalModel(); - RteItemBuilder rteBuilder(globalModel); - unique_ptr ymlTree = CreateUniqueYmlTree(&rteBuilder); + auto rteItemBuilder = CreateUniqueRteItemBuilder(globalModel); + unique_ptr ymlTree = CreateUniqueXmlTree(rteItemBuilder.get(), ".yml"); for(auto& f : files) { if(contains_key(m_externalGeneratorFiles, f)) { continue; } bool result = ymlTree->ParseFile(f); - RteItem* rootItem = rteBuilder.GetRoot(); + RteItem* rootItem = rteItemBuilder->GetRoot(); if(result && rootItem) { m_externalGeneratorFiles[f] = rootItem; for(auto item : rootItem->GetChildren()) { @@ -271,7 +271,7 @@ void RteKernel::LoadExternalGenerators() } } } - rteBuilder.Clear(false); + rteItemBuilder->Clear(false); } } @@ -295,10 +295,10 @@ RtePackage* RteKernel::LoadPack(const string& pdscFile, PackageState packState) return pack; } - RteItemBuilder rteItemBuilder(GetGlobalModel(), packState); - unique_ptr xmlTree = CreateUniqueXmlTree(&rteItemBuilder); + auto rteItemBuilder= CreateUniqueRteItemBuilder(GetGlobalModel(), packState); + unique_ptr xmlTree = CreateUniqueXmlTree(rteItemBuilder.get()); bool success = xmlTree->AddFileName(pdscFile, true); - pack = rteItemBuilder.GetPack(); + pack = rteItemBuilder->GetPack(); if (!success || !pack) { GetRteCallback()->Err("R802", R802, pdscFile); GetRteCallback()->OutputMessages(xmlTree->GetErrorStrings()); @@ -325,13 +325,13 @@ bool RteKernel::LoadPacks(const std::list& pdscFiles, std::list xmlTree = CreateUniqueXmlTree(); for(auto& pdscFile : pdscFiles) { - RteItemBuilder rteItemBuilder(model, model->GetPackageState()); - xmlTree->SetXmlItemBuilder(&rteItemBuilder); + auto rteItemBuilder = CreateUniqueRteItemBuilder(model, model->GetPackageState()); + xmlTree->SetXmlItemBuilder(rteItemBuilder.get()); if(bReplace) { packRegistry->ErasePack(pdscFile); } bool result = xmlTree->AddFileName(pdscFile, true); - RtePackage* pack = rteItemBuilder.GetPack(); + RtePackage* pack = rteItemBuilder->GetPack(); if(!result || !pack) { GetRteCallback()->Err("R802", R802, pdscFile); GetRteCallback()->OutputMessages(xmlTree->GetErrorStrings()); @@ -602,9 +602,11 @@ bool RteKernel::GetLocalPacksUrls(const string& rtePath, list& urls) con return true; } -unique_ptr RteKernel::CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder) const +unique_ptr RteKernel::CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder, const std::string& ext) const { - unique_ptr xmlTree(CreateXmlTree(itemBuilder)); + bool bYaml = !ext.empty() && (ext == ".yml" || ext == ".yaml"); + XMLTree* pXmlTree = bYaml ? CreateYmlTree(itemBuilder) : CreateXmlTree(itemBuilder); + unique_ptr xmlTree(pXmlTree); if (xmlTree.get() != nullptr) { xmlTree->SetCallback(GetRteCallback()); xmlTree->Init(); @@ -612,14 +614,13 @@ unique_ptr RteKernel::CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder) return xmlTree; } -unique_ptr RteKernel::CreateUniqueYmlTree(IXmlItemBuilder* itemBuilder) const +unique_ptr RteKernel::CreateUniqueRteItemBuilder(RteItem* rootParent, PackageState packState, const RteItem& options) const { - unique_ptr ymlTree(CreateYmlTree(itemBuilder)); - if (ymlTree.get() != nullptr) { - ymlTree->SetCallback(GetRteCallback()); - ymlTree->Init(); + unique_ptr builder( new RteItemBuilder(rootParent, packState)); + if(!options.IsEmpty()) { + builder->SetAttributes(options); } - return ymlTree; + return builder; } YmlTree* RteKernel::CreateYmlTree(IXmlItemBuilder* itemBuilder) const diff --git a/libs/rtemodel/src/RteTarget.cpp b/libs/rtemodel/src/RteTarget.cpp index 5f28c131f..1cba29d22 100644 --- a/libs/rtemodel/src/RteTarget.cpp +++ b/libs/rtemodel/src/RteTarget.cpp @@ -18,6 +18,7 @@ #include "RteInstance.h" #include "RteModel.h" #include "RteFsUtils.h" +#include "RteConstants.h" #include #include @@ -110,6 +111,51 @@ void RteTarget::Clear() } +string RteTarget::ExpandString(const string& str, bool bUseAccessSequences, RteItem* context) const +{ + if(bUseAccessSequences && context == this) { + return ExpandAccessSequences(str); + } + return RteItem::ExpandString(str, bUseAccessSequences, context); +} + +std::string RteTarget::ExpandAccessSequences(const std::string& src) const +{ + XmlItem attributes; + // device and board + attributes.AddAttribute(RteConstants::AS_DNAME, GetAttribute(RteConstants::AS_DNAME)); + attributes.AddAttribute(RteConstants::AS_BNAME, GetAttribute(RteConstants::AS_BNAME)); + attributes.AddAttribute(RteConstants::AS_PNAME, GetAttribute(RteConstants::AS_PNAME)); + // compiler + const string& compiler = GetAttribute("Tcompiler"); + attributes.AddAttribute(RteConstants::AS_COMPILER, (compiler == "ARMCC") ? "AC6" : compiler); + // target name as target type + attributes.AddAttribute(RteConstants::AS_TARGET_TYPE, GetName()); + attributes.AddAttribute(RteConstants::AS_BUILD_TYPE, RteUtils::EMPTY_STRING); + + // project and solution + RteProject* project = GetProject(); + string projectName = project->GetName(); + attributes.AddAttribute(RteConstants::AS_PROJECT, projectName); + string projectDir = RteUtils::RemoveTrailingBackslash(project->GetProjectPath()); + + RteModel* globalModel = GetModel(); + string solutionDir = globalModel->GetRootFilePath(false); // solution filename + if(solutionDir.empty()) { + solutionDir = projectDir; + projectDir = "."; + } else { + projectDir = RteFsUtils::RelativePath(projectDir, solutionDir); + } + + attributes.AddAttribute(RteConstants::AS_PROJECT_DIR, projectDir); + attributes.AddAttribute(RteConstants::AS_PROJECT_DIR_BR, projectDir); + attributes.AddAttribute(RteConstants::AS_SOLUTION_DIR, solutionDir); + attributes.AddAttribute(RteConstants::AS_SOLUTION_DIR_BR, solutionDir); + + return RteUtils::ExpandAccessSequences(src, attributes.GetAttributes()); +} + void RteTarget::ClearMissingPacks() { t_missingPackIds.clear(); diff --git a/libs/rtemodel/test/src/RteModelTest.cpp b/libs/rtemodel/test/src/RteModelTest.cpp index f3be733b5..e3bbab925 100644 --- a/libs/rtemodel/test/src/RteModelTest.cpp +++ b/libs/rtemodel/test/src/RteModelTest.cpp @@ -23,30 +23,6 @@ using namespace std; - -class ExtGenRteCallback : public RteCallback -{ - -public: - ExtGenRteCallback() :m_pExtGenerator(nullptr) { - m_pExtGenerator = new RteGenerator(nullptr); - m_pExtGenerator->SetTag("generator"); - m_pExtGenerator->AddAttribute("id", "RteTestExternalGenerator"); - m_pExtGenerator->Construct(); - } - ~ExtGenRteCallback() override{ - delete m_pExtGenerator; - } - RteGenerator* GetExternalGenerator(const std::string& id) const override { - if (m_pExtGenerator->GetID() == "RteTestExternalGenerator") { - return m_pExtGenerator; - } - return nullptr; - } - - RteGenerator* m_pExtGenerator; -}; - TEST(RteModelTest, PackRegistry) { // tests for pack registry @@ -237,17 +213,6 @@ TEST(RteModelTest, LoadPacks) { EXPECT_EQ(components.size(), 0); EXPECT_FALSE(c != nullptr); - item.SetAttributes({ {"Cclass","RteTestGenerator" }, - {"Cgroup", "Check Global Generator" }, - {"Cversion","0.9.0"}}); - packInfo.SetPackId("ARM::RteTestGenerator"); - item.SetPackageAttributes(packInfo); - components.clear(); - c = rteModel->FindComponents(item, components); - ASSERT_TRUE(c != nullptr); - RteGenerator* gen = c->GetGenerator(); - EXPECT_FALSE(gen != nullptr); - // get API const string& apiId = "::RteTest:CORE(API)"; RteApi* api = rteModel->GetLatestApi(apiId); @@ -265,12 +230,6 @@ TEST(RteModelTest, LoadPacks) { ASSERT_TRUE(api); EXPECT_EQ(api->GetID(), "::RteTest:CORE(API)@1.1.1"); EXPECT_EQ(api->GetPackageID(), "ARM::RteTest_DFP@0.1.1"); - - ExtGenRteCallback extGenRteCallback; - rteKernel.SetRteCallback(&extGenRteCallback); - gen = c->GetGenerator(); - EXPECT_TRUE(gen != nullptr); - EXPECT_TRUE(gen == extGenRteCallback.m_pExtGenerator); } class RteModelPrjTest : public RteModelTestConfig @@ -514,6 +473,65 @@ TEST_F(RteModelPrjTest, LoadCprj) { EXPECT_EQ(requiredPacks.size(), 3); } +TEST_F(RteModelPrjTest, ExtGenAndAccessSeq) { + + RteCallback callback; + RteKernelSlim rteKernel(&callback); + callback.SetRteKernel(&rteKernel); + rteKernel.SetCmsisPackRoot(RteModelTestConfig::CMSIS_PACK_ROOT); + rteKernel.SetCmsisToolboxDir(RteModelTestConfig::localRepoDir); + rteKernel.Init(); + + // load all installed packs + list files; + rteKernel.GetInstalledPacks(files, false); + RteModel* rteModel = rteKernel.GetGlobalModel(); + ASSERT_TRUE(rteModel); + rteModel->SetUseDeviceTree(true); + list packs; + EXPECT_TRUE(rteKernel.LoadPacks(files, packs)); + rteModel->InsertPacks(packs); + + RteCprjProject* loadedCprjProject = rteKernel.LoadCprj(RteTestM3_cprj); + ASSERT_TRUE(loadedCprjProject); + + RteTarget* activeTarget = rteKernel.GetActiveTarget(); + ASSERT_TRUE(activeTarget); + + RteComponentInstance item(nullptr); + item.SetAttributes({ {"Cclass","RteTestGenerator" }, + {"Cgroup", "Check Global Generator" }, + {"Cversion","0.9.0"}}); + RtePackageInstanceInfo packInfo(nullptr, "ARM::RteTestGenerator"); + item.SetPackageAttributes(packInfo); + list components; + RteComponent* c = rteModel->FindComponents(item, components); + ASSERT_TRUE(c); + RteGenerator* gen = c->GetGenerator(); + ASSERT_TRUE(gen); + + string absPath = RteFsUtils::AbsolutePath(RteModelTestConfig::localRepoDir).generic_string(); + + string path = gen->GetExpandedWorkingDir(activeTarget); + EXPECT_EQ(path, "RteModelTestProjects/RteTestM3/Target 1/RteTest_ARMCM3/"); + + + string cmd = gen->GetExpandedCommandLine(activeTarget); + cmd = RteUtils::ReplaceAll(cmd, absPath, "$(CMSIS_TOOLBOX)"); + const string expectedCmd = + "$(CMSIS_TOOLBOX)/bin/RunTestGen \"RteModelTestProjects/RteTestM3/RteTestM3.Target 1.cbuild-gen-idx.yml\""; + EXPECT_EQ(cmd, expectedCmd); + + // test additional expansions + const string src = "$SolutionDir()$/$ProjectDir()$/$Bname$/"; + string res = activeTarget->ExpandAccessSequences(src); + EXPECT_EQ(res, "RteModelTestProjects/RteTestM3/./RteTest Test board/"); + // set solution dir to RteModelTestProjects + rteModel->SetRootFileName("RteModelTestProjects/dummy.csolution.yml"); + res = activeTarget->ExpandAccessSequences(src); + EXPECT_EQ(res, "RteModelTestProjects/RteTestM3/RteTest Test board/"); +} + TEST_F(RteModelPrjTest, LoadCprjPacReq) { RteKernelSlim rteKernel; diff --git a/libs/rteutils/include/RteConstants.h b/libs/rteutils/include/RteConstants.h index dda9ff783..2a5b5e3ae 100644 --- a/libs/rteutils/include/RteConstants.h +++ b/libs/rteutils/include/RteConstants.h @@ -107,6 +107,8 @@ class RteConstants static constexpr const char* AS_SOLUTION_DIR = "SolutionDir"; static constexpr const char* AS_PROJECT_DIR = "ProjectDir"; + static constexpr const char* AS_SOLUTION_DIR_BR = "SolutionDir()"; + static constexpr const char* AS_PROJECT_DIR_BR = "ProjectDir()"; static constexpr const char* AS_OUT_DIR = "OutDir"; static constexpr const char* AS_BIN = OUTPUT_TYPE_BIN; static constexpr const char* AS_ELF = OUTPUT_TYPE_ELF; diff --git a/libs/rteutils/include/RteUtils.h b/libs/rteutils/include/RteUtils.h index 8ca9fbafe..90d85a39b 100644 --- a/libs/rteutils/include/RteUtils.h +++ b/libs/rteutils/include/RteUtils.h @@ -139,11 +139,11 @@ class RteUtils /** * @brief expand string by replacing $keyword$ with corresponding values - * @param source string to expand + * @param src source string to expand * @param variables string to string map with keyword values * @return expanded string */ - static std::string ExpandString(const std::string& src, const StrMap& variables); + static std::string ExpandAccessSequences(const std::string& src, const StrMap& variables); /** * @brief replace blank(s) with underscore(s) diff --git a/libs/rteutils/src/RteUtils.cpp b/libs/rteutils/src/RteUtils.cpp index 570cd5eb0..0aefef3e5 100644 --- a/libs/rteutils/src/RteUtils.cpp +++ b/libs/rteutils/src/RteUtils.cpp @@ -173,7 +173,7 @@ std::string& RteUtils::ReplaceAll(std::string& str, const string& toReplace, con return str; } -string RteUtils::ExpandString(const string& src, const StrMap& variables) { +string RteUtils::ExpandAccessSequences(const string& src, const StrMap& variables) { string ret = src; if (regex_match(ret, regex(".*\\$.*\\$.*"))) { for (const auto& [varName, replacement] : variables) { diff --git a/libs/rteutils/test/src/RteUtilsTest.cpp b/libs/rteutils/test/src/RteUtilsTest.cpp index b1b4b5c73..ec8a2d05d 100644 --- a/libs/rteutils/test/src/RteUtilsTest.cpp +++ b/libs/rteutils/test/src/RteUtilsTest.cpp @@ -453,18 +453,18 @@ TEST(RteUtils, CollectionUtils) EXPECT_EQ(*get_or_default(strToPtr, "four", sDefault), 'd'); } -TEST(RteUtils, ExpandString) { +TEST(RteUtils, ExpandAccessSequences) { StrMap variables = { {"Foo", "./foo"}, {"Bar", "./bar"}, {"Foo Bar", "./foo-bar"}, }; - EXPECT_EQ(RteUtils::ExpandString("path1: $Foo/bar", variables), "path1: $Foo/bar"); - EXPECT_EQ(RteUtils::ExpandString("path1: $Foo$/bar", variables), "path1: ./foo/bar"); - EXPECT_EQ(RteUtils::ExpandString("path2: $Bar$/foo", variables), "path2: ./bar/foo"); - EXPECT_EQ(RteUtils::ExpandString("$Foo$ $Bar$", variables), "./foo ./bar"); - EXPECT_EQ(RteUtils::ExpandString("$Foo Bar$", variables), "./foo-bar"); - EXPECT_EQ(RteUtils::ExpandString("$Foo$ $Foo$ $Foo$", variables), "./foo ./foo ./foo"); + EXPECT_EQ(RteUtils::ExpandAccessSequences("path1: $Foo/bar", variables), "path1: $Foo/bar"); + EXPECT_EQ(RteUtils::ExpandAccessSequences("path1: $Foo$/bar", variables), "path1: ./foo/bar"); + EXPECT_EQ(RteUtils::ExpandAccessSequences("path2: $Bar$/foo", variables), "path2: ./bar/foo"); + EXPECT_EQ(RteUtils::ExpandAccessSequences("$Foo$ $Bar$", variables), "./foo ./bar"); + EXPECT_EQ(RteUtils::ExpandAccessSequences("$Foo Bar$", variables), "./foo-bar"); + EXPECT_EQ(RteUtils::ExpandAccessSequences("$Foo$ $Foo$ $Foo$", variables), "./foo ./foo ./foo"); } TEST(RteUtils, GetAccessSequence) { diff --git a/libs/xmltree/include/IXmlItemBuilder.h b/libs/xmltree/include/IXmlItemBuilder.h index c7b747f25..bb5154016 100644 --- a/libs/xmltree/include/IXmlItemBuilder.h +++ b/libs/xmltree/include/IXmlItemBuilder.h @@ -8,17 +8,14 @@ */ /******************************************************************************/ +#include "XmlItem.h" #include /** * @brief abstract factory interface class to create XmlItem derived objects */ -class IXmlItemBuilder { +class IXmlItemBuilder : public XmlItem { public: - /** - * @brief destructor - */ - virtual ~IXmlItemBuilder(){}; /** * @brief clears and initializes builder diff --git a/libs/xmltree/include/XmlTreeItemBuilder.h b/libs/xmltree/include/XmlTreeItemBuilder.h index d67784bb7..e8225a747 100644 --- a/libs/xmltree/include/XmlTreeItemBuilder.h +++ b/libs/xmltree/include/XmlTreeItemBuilder.h @@ -178,7 +178,7 @@ class XmlTreeItemBuilder : public IXmlItemBuilder */ virtual T* CreateRootItem(const std::string& tag) = 0; -private: +protected: T* m_pRoot; T* m_pCurrent; T* m_pParent; diff --git a/test/local/etc/global.generator.yml b/test/local/etc/global.generator.yml new file mode 100644 index 000000000..fd07c74bf --- /dev/null +++ b/test/local/etc/global.generator.yml @@ -0,0 +1,6 @@ +generator: + - id: RteTestExternalGenerator + description: Global Registered Generator + download-url: https://raw.githubusercontent.com/Open-CMSIS-Pack + run: ../bin/RunTestGen + path: $SolutionDir()$/$TargetType$/$Dname$ diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index c60993461..364373c60 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -161,7 +161,7 @@ bool ProjMgrWorker::ParseContextLayers(ContextItem& context) { } if (CheckContextFilters(clayer.typeFilter, context)) { error_code ec; - string const& clayerRef = RteUtils::ExpandString(clayer.layer, context.variables); + string const& clayerRef = RteUtils::ExpandAccessSequences(clayer.layer, context.variables); string const& clayerFile = fs::canonical(fs::path(context.cproject->directory).append(clayerRef), ec).generic_string(); if (clayerFile.empty()) { if (regex_match(clayer.layer, regex(".*\\$.*\\$.*"))) { @@ -620,7 +620,7 @@ bool ProjMgrWorker::CollectLayersFromSearchPath(const string& clayerSearchPath, void ProjMgrWorker::GetRequiredLayerTypes(ContextItem& context, LayersDiscovering& discover) { for (const auto& clayer : context.cproject->clayers) { if (clayer.type.empty() || !CheckContextFilters(clayer.typeFilter, context) || - (RteUtils::ExpandString(clayer.layer, context.variables) != clayer.layer)) { + (RteUtils::ExpandAccessSequences(clayer.layer, context.variables) != clayer.layer)) { continue; } discover.requiredLayerTypes.push_back(clayer.type); @@ -2770,7 +2770,7 @@ bool ProjMgrWorker::ProcessSequenceRelative(ContextItem& context, string& item, size_t offset = 0; bool pathReplace = false; // expand variables (static access sequences) - const string input = item = RteUtils::ExpandString(item, context.variables); + const string input = item = RteUtils::ExpandAccessSequences(item, context.variables); // expand dynamic access sequences while (offset != string::npos) { string sequence; @@ -3670,7 +3670,7 @@ bool ProjMgrWorker::ExecuteGenerator(std::string& generatorId) { //const string generatorCommand = m_kernel->GetCmsisPackRoot() + "/" + generator->GetPackagePath() + generator->GetCommand(); // check if generator executable has execute permissions - const string generatorExe = generator->GetExecutable(); + const string generatorExe = generator->GetExecutable(context.rteActiveTarget); if (generatorExe.empty()) { ProjMgrLogger::Error("generator executable '" + generatorId + "' was not found"); return false; @@ -3688,7 +3688,7 @@ bool ProjMgrWorker::ExecuteGenerator(std::string& generatorId) { ProjMgrLogger::Error("generator '" + generatorId + "' is not dry-run capable"); return false; } - const string generatorCommand = generator->GetExpandedCommandLine(RteUtils::EMPTY_STRING, m_dryRun); + const string generatorCommand = generator->GetExpandedCommandLine(context.rteActiveTarget, RteUtils::EMPTY_STRING, m_dryRun); error_code ec; const auto& workingDir = fs::current_path(ec); @@ -4004,7 +4004,8 @@ StrSet ProjMgrWorker::GetValidSets(ContextItem& context, const string& clayer) { bool ProjMgrWorker::ProcessOutputFilenames(ContextItem& context) { // get base name and output types from project and project setups context.outputTypes = {}; - context.cproject->output.baseName = RteUtils::ExpandString(context.cproject->output.baseName, context.variables); + context.cproject->output.baseName = + RteUtils::ExpandAccessSequences(context.cproject->output.baseName, context.variables); string baseName; StringCollection baseNameCollection = { &baseName, @@ -4017,7 +4018,7 @@ bool ProjMgrWorker::ProcessOutputFilenames(ContextItem& context) { } for (auto& setup : context.cproject->setups) { if (CheckContextFilters(setup.type, context) && CheckCompiler(setup.forCompiler, context.compiler)) { - setup.output.baseName = RteUtils::ExpandString(setup.output.baseName, context.variables); + setup.output.baseName = RteUtils::ExpandAccessSequences(setup.output.baseName, context.variables); baseNameCollection.elements.push_back(&setup.output.baseName); for (const auto& type : setup.output.type) { ProjMgrUtils::SetOutputType(type, context.outputTypes); diff --git a/tools/projmgr/src/ProjMgrYamlEmitter.cpp b/tools/projmgr/src/ProjMgrYamlEmitter.cpp index 37a8e38a8..304d09383 100644 --- a/tools/projmgr/src/ProjMgrYamlEmitter.cpp +++ b/tools/projmgr/src/ProjMgrYamlEmitter.cpp @@ -421,14 +421,14 @@ void ProjMgrYamlCbuild::SetGeneratorsNode(YAML::Node node, const ContextItem* co YAML::Node commandNode; // Executable file - const string exe = generator->GetExecutable(host); + const string exe = generator->GetExecutable(context->rteActiveTarget, host); if (exe.empty()) continue; commandNode[YAML_FILE] = FormatPath(exe, context->directories.cbuild); // Arguments YAML::Node argumentsNode; - const vector >& args = generator->GetExpandedArguments(host); + const vector >& args = generator->GetExpandedArguments(context->rteActiveTarget, host); for (auto [swtch, value] : args) { // If the argument is recognized as an absolute path, make sure to reformat // it to use CMSIS_PACK_ROOT or to be relative the working directory