From 89e7bb5fb1f4e3c2ccb79dce3312a3c520da9908 Mon Sep 17 00:00:00 2001 From: Daniel Brondani Date: Mon, 25 Sep 2023 09:42:12 +0200 Subject: [PATCH] [projmgr] External Generator PoC - Initial commit --- tools/projmgr/CMakeLists.txt | 4 +- tools/projmgr/include/ProjMgr.h | 1 + tools/projmgr/include/ProjMgrExtGenerator.h | 97 ++++++++ tools/projmgr/include/ProjMgrParser.h | 29 +++ tools/projmgr/include/ProjMgrWorker.h | 28 ++- tools/projmgr/include/ProjMgrYamlEmitter.h | 5 + tools/projmgr/include/ProjMgrYamlParser.h | 18 ++ tools/projmgr/src/ProjMgr.cpp | 27 ++- tools/projmgr/src/ProjMgrExtGenerator.cpp | 99 ++++++++ tools/projmgr/src/ProjMgrParser.cpp | 9 + tools/projmgr/src/ProjMgrWorker.cpp | 227 ++++++++++++++++-- tools/projmgr/src/ProjMgrYamlEmitter.cpp | 113 ++++++--- tools/projmgr/src/ProjMgrYamlParser.cpp | 38 +++ .../test/data/ExternalGenerator/bridge.sh | 4 + .../ExternalGenerator/extgen.csolution.yml | 30 +++ .../ExternalGenerator/global.generator.yml | 5 + .../multi_0/core0.cproject.yml | 6 + .../multi_1/core1.cproject.yml | 6 + .../core0.Debug+MultiCore.cbuild-gen.yml | 47 ++++ .../core1.Debug+MultiCore.cbuild-gen.yml | 47 ++++ .../ref/MultiCore/extgen.cbuild-gen-idx.yml | 15 ++ .../ref/SingleCore/extgen.cbuild-gen-idx.yml | 10 + .../single-core.Debug+CM0.cbuild-gen.yml | 42 ++++ .../single-core.Debug+CM0.cbuild.yml | 80 ++++++ .../ref/TrustZone/extgen.cbuild-gen-idx.yml | 15 ++ .../ref/TrustZone/ns.Debug+CM0.cbuild-gen.yml | 39 +++ .../ref/TrustZone/s.Debug+CM0.cbuild-gen.yml | 41 ++++ .../single/generated/generated.c | 1 + .../single/generated/single-core.cgen.yml | 14 ++ .../test/data/ExternalGenerator/single/main.c | 1 + .../single/single-core.cproject.yml | 16 ++ .../ExternalGenerator/tz_ns/ns.cproject.yml | 7 + .../ExternalGenerator/tz_s/s.cproject.yml | 7 + tools/projmgr/test/src/ProjMgrUnitTests.cpp | 61 +++++ .../test/src/ProjMgrWorkerUnitTests.cpp | 2 +- 35 files changed, 1113 insertions(+), 78 deletions(-) create mode 100644 tools/projmgr/include/ProjMgrExtGenerator.h create mode 100644 tools/projmgr/src/ProjMgrExtGenerator.cpp create mode 100755 tools/projmgr/test/data/ExternalGenerator/bridge.sh create mode 100644 tools/projmgr/test/data/ExternalGenerator/extgen.csolution.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/global.generator.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/multi_0/core0.cproject.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/multi_1/core1.cproject.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core0.Debug+MultiCore.cbuild-gen.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core1.Debug+MultiCore.cbuild-gen.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/extgen.cbuild-gen-idx.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/extgen.cbuild-gen-idx.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild-gen.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/extgen.cbuild-gen-idx.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/ns.Debug+CM0.cbuild-gen.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/s.Debug+CM0.cbuild-gen.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/single/generated/generated.c create mode 100644 tools/projmgr/test/data/ExternalGenerator/single/generated/single-core.cgen.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/single/main.c create mode 100644 tools/projmgr/test/data/ExternalGenerator/single/single-core.cproject.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/tz_ns/ns.cproject.yml create mode 100644 tools/projmgr/test/data/ExternalGenerator/tz_s/s.cproject.yml diff --git a/tools/projmgr/CMakeLists.txt b/tools/projmgr/CMakeLists.txt index fe54361fe..09604e9dc 100644 --- a/tools/projmgr/CMakeLists.txt +++ b/tools/projmgr/CMakeLists.txt @@ -13,12 +13,12 @@ set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT projmgr) SET(PROJMGR_SOURCE_FILES ProjMgr.cpp ProjMgrKernel.cpp ProjMgrCallback.cpp ProjMgrParser.cpp ProjMgrWorker.cpp ProjMgrGenerator.cpp ProjMgrXmlParser.cpp ProjMgrYamlParser.cpp ProjMgrLogger.cpp ProjMgrYamlSchemaChecker.cpp - ProjMgrYamlEmitter.cpp ProjMgrUtils.cpp + ProjMgrYamlEmitter.cpp ProjMgrUtils.cpp ProjMgrExtGenerator.cpp ) SET(PROJMGR_HEADER_FILES ProjMgr.h ProjMgrKernel.h ProjMgrCallback.h ProjMgrParser.h ProjMgrWorker.h ProjMgrGenerator.h ProjMgrXmlParser.h ProjMgrYamlParser.h ProjMgrLogger.h ProjMgrYamlSchemaChecker.h - ProjMgrYamlEmitter.h ProjMgrUtils.h + ProjMgrYamlEmitter.h ProjMgrUtils.h ProjMgrExtGenerator.h ) list(TRANSFORM PROJMGR_SOURCE_FILES PREPEND src/) diff --git a/tools/projmgr/include/ProjMgr.h b/tools/projmgr/include/ProjMgr.h index 705db5c53..fde7503c0 100644 --- a/tools/projmgr/include/ProjMgr.h +++ b/tools/projmgr/include/ProjMgr.h @@ -88,6 +88,7 @@ class ProjMgr { ProjMgrWorker m_worker; ProjMgrGenerator m_generator; ProjMgrYamlEmitter m_emitter; + ProjMgrExtGenerator m_extGenerator; std::string m_csolutionFile; std::string m_cdefaultFile; diff --git a/tools/projmgr/include/ProjMgrExtGenerator.h b/tools/projmgr/include/ProjMgrExtGenerator.h new file mode 100644 index 000000000..86f13ff28 --- /dev/null +++ b/tools/projmgr/include/ProjMgrExtGenerator.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020-2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef PROJMGREXTGENERATOR_H +#define PROJMGREXTGENERATOR_H + +#include "ProjMgrParser.h" +#include "ProjMgrUtils.h" + + /** + * @brief external generator item containing + * component identifier + * directory for generated files + * project type + */ +struct ExtGeneratorItem { + std::string componentId; + std::string genDir; + std::string projectType; +}; + + +struct CbuildGenItem { + StrVec forContext; + std::string device; + std::string board; + std::string projectPart; +}; + +/** + * @brief map of used generators, directories and contexts +*/ +typedef std::map GeneratorContextVecMap; + +/** + * @brief vector of external generator items +*/ +typedef std::vector ExtGeneratorVec; + +/** + * @brief map of vector of external generator items +*/ +typedef std::map ExtGeneratorVecMap; + +/** + * @brief solution/project types +*/ +static constexpr const char* TYPE_SINGLE_CORE = "single-core"; +static constexpr const char* TYPE_MULTI_CORE = "multi-core"; +static constexpr const char* TYPE_TRUSTZONE = "trustzone"; +static constexpr const char* PROCESSOR_CORE = "processor-core"; + +/** + * @brief projmgr external generator class responsible for handling global generators +*/ +class ProjMgrExtGenerator { +public: + /** + * @brief class constructor + */ + ProjMgrExtGenerator(ProjMgrParser* parser); + + + /** + * @brief class destructor + */ + ~ProjMgrExtGenerator(void); + + + bool RetrieveGlobalGenerators(void); + + bool IsGlobalGenerator(const std::string& generatorId); + bool CheckGeneratorId(const std::string& generatorId, const std::string& componentId); + const std::string& GetGlobalGenDir(const std::string& generatorId); + const std::string& GetGlobalGenRunCmd(const std::string& generatorId); + void AddUsedGenerator(const std::string& generatorId, const std::string& genDir, const std::string& contextId); + const GeneratorContextVecMap& GetUsedGenerators(void); + bool GetCgen(const std::string& contextId, ClayerItem& cgen); + +protected: + ProjMgrParser* m_parser = nullptr; + StrVec m_globalGeneratorFiles; + std::map m_globalGenerators; + GeneratorContextVecMap m_usedGenerators; + + bool m_checkSchema; + std::string m_compilerRoot; + + + + +}; + +#endif // PROJMGREXTGENERATOR_H diff --git a/tools/projmgr/include/ProjMgrParser.h b/tools/projmgr/include/ProjMgrParser.h index 08cf8bc9c..7553196cb 100644 --- a/tools/projmgr/include/ProjMgrParser.h +++ b/tools/projmgr/include/ProjMgrParser.h @@ -140,12 +140,14 @@ struct TargetType { * @brief directories item containing * intdir directory, * outdir directory, + * cbuild directory, * cprj directory, * rte directory, */ struct DirectoriesItem { std::string intdir; std::string outdir; + std::string cbuild; std::string cprj; std::string rte; }; @@ -402,6 +404,20 @@ struct ClayerItem { GeneratorsItem generators; }; +/** + * @brief global generator item containing + * generator id, + * download url, + * bridge program, + * output +*/ +struct GlobalGeneratorItem { + std::string id; + std::string downloadUrl; + std::string run; + std::string output; +}; + /** * @brief projmgr parser class for public interfacing */ @@ -448,6 +464,12 @@ class ProjMgrParser { */ bool ParseGenericClayer(const std::string& input, bool checkSchema); + /** + * @brief parse global generator + * @param input generator.yml file + */ + bool ParseGlobalGenerator(const std::string& input, bool checkSchema); + /** * @brief get cdefault * @return cdefault item @@ -478,12 +500,19 @@ class ProjMgrParser { */ std::map& GetGenericClayers(void); + /** + * @brief get global generators + * @return global generators map + */ + std::map& GetGlobalGenerators(void); + protected: CdefaultItem m_cdefault; CsolutionItem m_csolution; std::map m_cprojects; std::map m_clayers; std::map m_genericClayers; + std::map m_globalGenerators; }; #endif // PROJMGRPARSER_H diff --git a/tools/projmgr/include/ProjMgrWorker.h b/tools/projmgr/include/ProjMgrWorker.h index 0b0a287f7..fc44e46d0 100644 --- a/tools/projmgr/include/ProjMgrWorker.h +++ b/tools/projmgr/include/ProjMgrWorker.h @@ -7,6 +7,7 @@ #ifndef PROJMGRWORKER_H #define PROJMGRWORKER_H +#include "ProjMgrExtGenerator.h" #include "ProjMgrKernel.h" #include "ProjMgrParser.h" #include "ProjMgrUtils.h" @@ -252,6 +253,7 @@ struct ContextTypesItem { * output type, * device selection, * board selection, + * device item struct, * list of package requirements, * map of required pdsc files and optionally its local path * list of component requirements, @@ -269,6 +271,7 @@ struct ContextTypesItem { * valid connections, * linker options, * map of variables, + * external generator directory, * boolean processed precedences */ struct ContextItem { @@ -289,6 +292,7 @@ struct ContextItem { OutputTypes outputTypes; std::string device; std::string board; + DeviceItem deviceItem; std::vector packRequirements; std::map> pdscFiles; std::vectormissingPacks; @@ -310,6 +314,7 @@ struct ContextItem { std::vector validConnections; LinkerContextItem linker; std::map variables; + StrMap extGenDir; bool precedences; }; @@ -362,28 +367,22 @@ class ProjMgrWorker { /** * @brief class constructor */ - ProjMgrWorker(void); + ProjMgrWorker(ProjMgrParser* parser, ProjMgrExtGenerator* extGenerator); /** * @brief class destructor */ ~ProjMgrWorker(void); - /** - * @brief set parser - * @param pointer to parser - */ - void SetParser(ProjMgrParser* parser); - /** * @brief process context * @param reference to context - * @param loadGpdsc boolean automatically load gpdsc, default true + * @param loadGenFiles boolean automatically load generated files, default true * @param resolveDependencies boolean automatically resolve dependencies, default true * @param updateRteFiles boolean update RTE files, default true * @return true if executed successfully */ - bool ProcessContext(ContextItem& context, bool loadGpdsc = true, bool resolveDependencies = true, bool updateRteFiles = true); + bool ProcessContext(ContextItem& context, bool loadGenFiles = true, bool resolveDependencies = true, bool updateRteFiles = true); /** * @brief list available packs @@ -554,6 +553,8 @@ class ProjMgrWorker { */ bool ExecuteGenerator(std::string& generatorId); + bool ExecuteExtGenerator(std::string& generatorId); + /** * @brief initialize model * @return true if executed successfully @@ -605,10 +606,14 @@ class ProjMgrWorker { */ void PrintMissingFilters(void); + bool ProcessGlobalGenerators(ContextItem* selectedContext, const std::string& generatorId, + std::string& projectType, StrVec& siblings); + protected: ProjMgrParser* m_parser = nullptr; ProjMgrKernel* m_kernel = nullptr; RteGlobalModel* m_model = nullptr; + ProjMgrExtGenerator* m_extGenerator = nullptr; std::list m_loadedPacks; std::vector m_toolchains; StrVec m_toolchainConfigFiles; @@ -640,7 +645,7 @@ class ProjMgrWorker { bool GetProjectSetup(ContextItem& context); bool InitializeTarget(ContextItem& context); bool SetTargetAttributes(ContextItem& context, std::map& attributes); - bool ProcessPrecedences(ContextItem& context); + bool ProcessPrecedences(ContextItem& context, bool rerun = false); bool ProcessPrecedence(StringCollection& item); bool ProcessCompilerPrecedence(StringCollection& item, bool acceptRedefinition = false); bool ProcessDevice(ContextItem& context); @@ -722,10 +727,13 @@ class ProjMgrWorker { void UpdatePartialReferencedContext(ContextItem& context, std::string& contextName); void ExpandAccessSequence(const ContextItem& context, const ContextItem& refContext, const std::string& sequence, std::string& item, bool withHeadingDot); bool GetGeneratorDir(const RteGenerator* generator, ContextItem& context, const std::string& layer, std::string& genDir); + bool GetGeneratorDir(const std::string& generatorId, ContextItem& context, const std::string& layer, std::string& genDir); + bool GetExtGeneratorDir(const std::string& generatorId, ContextItem& context, const std::string& layer, std::string& genDir); bool ParseContextLayers(ContextItem& context); bool AddPackRequirements(ContextItem& context, const std::vector packRequirements); void CheckTypeFilterSpelling(const TypeFilter& typeFilter); void CheckCompilerFilterSpelling(const std::string& compiler); + bool ProcessGeneratedLayers(ContextItem& context); }; #endif // PROJMGRWORKER_H diff --git a/tools/projmgr/include/ProjMgrYamlEmitter.h b/tools/projmgr/include/ProjMgrYamlEmitter.h index a6ed79cb6..639773a96 100644 --- a/tools/projmgr/include/ProjMgrYamlEmitter.h +++ b/tools/projmgr/include/ProjMgrYamlEmitter.h @@ -33,12 +33,17 @@ class ProjMgrYamlEmitter { */ static bool GenerateCbuildIndex(ProjMgrParser& parser, const std::vector contexts, const std::string& outputDir); + static bool GenerateCbuildGenIndex(ProjMgrParser& parser, const std::vector siblings, + const std::string& type, const std::string& outputDir); + /** * @brief generate cbuild.yml file * @param context pointer to the context * @return true if executed successfully */ static bool GenerateCbuild(ContextItem* context); + + static bool GenerateCbuildGen(ContextItem* context, const std::string& output); }; #endif // PROJMGRYAMLEMITTER_H diff --git a/tools/projmgr/include/ProjMgrYamlParser.h b/tools/projmgr/include/ProjMgrYamlParser.h index a6b1662d6..1b3fb2e48 100644 --- a/tools/projmgr/include/ProjMgrYamlParser.h +++ b/tools/projmgr/include/ProjMgrYamlParser.h @@ -21,11 +21,15 @@ static constexpr const char* YAML_BASE_DIR = "base-dir"; static constexpr const char* YAML_BASE_NAME = "base-name"; static constexpr const char* YAML_BOARD = "board"; static constexpr const char* YAML_BUILD = "build"; +static constexpr const char* YAML_BUILD_GEN = "build-gen"; static constexpr const char* YAML_BUILD_IDX = "build-idx"; +static constexpr const char* YAML_BUILD_GEN_IDX = "build-gen-idx"; static constexpr const char* YAML_BUILDTYPES = "build-types"; static constexpr const char* YAML_CATEGORY = "category"; static constexpr const char* YAML_CBUILDS = "cbuilds"; static constexpr const char* YAML_CBUILD = "cbuild"; +static constexpr const char* YAML_CBUILD_GENS = "cbuild-gens"; +static constexpr const char* YAML_CBUILD_GEN = "cbuild-gen"; static constexpr const char* YAML_CDEFAULT = "cdefault"; static constexpr const char* YAML_CLAYERS = "clayers"; static constexpr const char* YAML_CLAYER = "clayer"; @@ -53,6 +57,7 @@ static constexpr const char* YAML_DEFINE = "define"; static constexpr const char* YAML_DELPATH = "del-path"; static constexpr const char* YAML_DESCRIPTION = "description"; static constexpr const char* YAML_DEVICE = "device"; +static constexpr const char* YAML_DOWNLOAD_URL = "download-url"; static constexpr const char* YAML_ENDIAN = "endian"; static constexpr const char* YAML_FILE = "file"; static constexpr const char* YAML_FILES = "files"; @@ -61,6 +66,7 @@ static constexpr const char* YAML_FORBOARD = "for-board"; static constexpr const char* YAML_FORCOMPILER = "for-compiler"; static constexpr const char* YAML_FORCONTEXT = "for-context"; static constexpr const char* YAML_FORDEVICE = "for-device"; +static constexpr const char* YAML_FORPROJECTPART = "for-project-part"; static constexpr const char* YAML_FPU = "fpu"; static constexpr const char* YAML_GENERATED_BY = "generated-by"; static constexpr const char* YAML_GENERATOR = "generator"; @@ -106,9 +112,11 @@ static constexpr const char* YAML_PATH = "path"; static constexpr const char* YAML_PROCESSOR = "processor"; static constexpr const char* YAML_PROJECT = "project"; static constexpr const char* YAML_PROJECTS = "projects"; +static constexpr const char* YAML_PROJECT_TYPE = "project-type"; static constexpr const char* YAML_PROVIDES = "provides"; static constexpr const char* YAML_REGIONS = "regions"; static constexpr const char* YAML_RTE = "rte"; +static constexpr const char* YAML_RUN = "run"; static constexpr const char* YAML_SCOPE = "scope"; static constexpr const char* YAML_SCRIPT = "script"; static constexpr const char* YAML_SOLUTION = "solution"; @@ -116,6 +124,7 @@ static constexpr const char* YAML_SELECTED_BY = "selected-by"; static constexpr const char* YAML_SETUPS = "setups"; static constexpr const char* YAML_SETUP = "setup"; static constexpr const char* YAML_SET = "set"; +static constexpr const char* YAML_SUB_DIR = "sub-dir"; static constexpr const char* YAML_SWITCH = "switch"; static constexpr const char* YAML_TARGETTYPES = "target-types"; static constexpr const char* YAML_TRUSTZONE = "trustzone"; @@ -177,6 +186,15 @@ class ProjMgrYamlParser { bool ParseClayer(const std::string& input, std::map& clayers, bool checkSchema); + /** + * @brief parse global generator + * @param input generator.yml file + * @param reference to store parsed generator item + * @param checkSchema false to skip schema validation + */ + bool ParseGlobalGenerator(const std::string& input, + std::map& generators, bool checkSchema); + protected: void ParseMisc(const YAML::Node& parent, std::vector& misc); void ParseDefine(const YAML::Node& parent, std::vector& define); diff --git a/tools/projmgr/src/ProjMgr.cpp b/tools/projmgr/src/ProjMgr.cpp index a887104b7..564bb51ad 100644 --- a/tools/projmgr/src/ProjMgr.cpp +++ b/tools/projmgr/src/ProjMgr.cpp @@ -56,8 +56,13 @@ Options:\n\ Use 'csolution -h' for more information about a command.\n\ "; -ProjMgr::ProjMgr(void) : m_checkSchema(false), m_updateRteFiles(true) { - m_worker.SetParser(&m_parser); +ProjMgr::ProjMgr(void) : + m_checkSchema(false), + m_updateRteFiles(true), + m_parser(), + m_extGenerator(&m_parser), + m_worker(&m_parser, &m_extGenerator) { + // Reserved } ProjMgr::~ProjMgr(void) { @@ -430,6 +435,11 @@ bool ProjMgr::PopulateContexts(void) { // Retrieve all context types m_worker.RetrieveAllContextTypes(); + // Retrieve global generators + if (!m_extGenerator.RetrieveGlobalGenerators()) { + return false; + } + return true; } @@ -725,9 +735,16 @@ bool ProjMgr::RunCodeGenerator(void) { if (!m_worker.ParseContextSelection(m_context, m_contextReplacement)) { return false; } - // Run code generator - if (!m_worker.ExecuteGenerator(m_codeGenerator)) { - return false; + if (m_extGenerator.IsGlobalGenerator(m_codeGenerator)) { + // Run global code generator + if (!m_worker.ExecuteExtGenerator(m_codeGenerator)) { + return false; + } + } else { + // Run legacy code generator + if (!m_worker.ExecuteGenerator(m_codeGenerator)) { + return false; + } } return true; } diff --git a/tools/projmgr/src/ProjMgrExtGenerator.cpp b/tools/projmgr/src/ProjMgrExtGenerator.cpp new file mode 100644 index 000000000..3b5e3bb0b --- /dev/null +++ b/tools/projmgr/src/ProjMgrExtGenerator.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020-2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ProjMgrExtGenerator.h" +#include "ProjMgrLogger.h" +#include "ProjMgrYamlEmitter.h" + +#include "RteFsUtils.h" + +using namespace std; + +ProjMgrExtGenerator::ProjMgrExtGenerator(ProjMgrParser* parser) : m_checkSchema(false) { + m_parser = parser; +} + +ProjMgrExtGenerator::~ProjMgrExtGenerator(void) { + // Reserved +} + +bool ProjMgrExtGenerator::RetrieveGlobalGenerators(void) { + if (m_globalGeneratorFiles.empty()) { + // get global generator files + ProjMgrUtils::GetCompilerRoot(m_compilerRoot); + StrVec toolchainConfigFiles; + error_code ec; + for (auto const& entry : fs::recursive_directory_iterator(m_compilerRoot, ec)) { + if (entry.path().filename().string().find(".generator.yml") == string::npos) { + continue; + } + m_globalGeneratorFiles.push_back(entry.path().generic_string()); + } + // parse global generator files + for (auto const& generatorFile : m_globalGeneratorFiles) { + if (!m_parser->ParseGlobalGenerator(generatorFile, m_checkSchema)) { + return false; + } + } + m_globalGenerators = m_parser->GetGlobalGenerators(); + } + return true; +} + +bool ProjMgrExtGenerator::IsGlobalGenerator(const string& generatorId) { + if (m_globalGenerators.find(generatorId) == m_globalGenerators.end()) { + return false; + } + return true; +} + +bool ProjMgrExtGenerator::CheckGeneratorId(const string& generatorId, const string& componentId) { + if (!IsGlobalGenerator(generatorId)) { + ProjMgrLogger::Error("generator '" + generatorId + "' required by component '" + + componentId + "' was not found in global register"); + return false; + } + return true; +} + +const string& ProjMgrExtGenerator::GetGlobalGenDir(const string& generatorId) { + return(m_globalGenerators[generatorId].output); +} + +const string& ProjMgrExtGenerator::GetGlobalGenRunCmd(const string& generatorId) { + return(m_globalGenerators[generatorId].run); +} + + +void ProjMgrExtGenerator::AddUsedGenerator(const string& generatorId, const string& genDir, const string& contextId) { + m_usedGenerators[generatorId][genDir].push_back(contextId); +} + +const GeneratorContextVecMap& ProjMgrExtGenerator::GetUsedGenerators(void) { + return m_usedGenerators; +} + +bool ProjMgrExtGenerator::GetCgen(const string& contextId, ClayerItem& cgen) { + ContextName context; + ProjMgrUtils::ParseContextEntry(contextId, context); + for (const auto& [generator, genDirs] : GetUsedGenerators()) { + for (const auto& [genDir, contexts] : genDirs) { + if (find(contexts.begin(), contexts.end(), contextId) != contexts.end()) { + const string cgenFile = fs::path(genDir).append(context.project + ".cgen.yml").generic_string(); + if (!RteFsUtils::Exists(cgenFile)) { + ProjMgrLogger::Error(cgenFile, "cgen file was not found, run generator '" + generator + "' for context '" + contextId + "'"); + return false; + } + if (!m_parser->ParseClayer(cgenFile, m_checkSchema)) { + return false; + } + cgen = m_parser->GetClayers().at(cgenFile); + return true; + } + } + } + return false; +} \ No newline at end of file diff --git a/tools/projmgr/src/ProjMgrParser.cpp b/tools/projmgr/src/ProjMgrParser.cpp index 3c58cb468..403f2539b 100644 --- a/tools/projmgr/src/ProjMgrParser.cpp +++ b/tools/projmgr/src/ProjMgrParser.cpp @@ -49,6 +49,11 @@ bool ProjMgrParser::ParseGenericClayer(const string& input, bool checkSchema) { return ProjMgrYamlParser().ParseClayer(input, m_genericClayers, checkSchema); } +bool ProjMgrParser::ParseGlobalGenerator(const string& input, bool checkSchema) { + // Parse generic layer file + return ProjMgrYamlParser().ParseGlobalGenerator(input, m_globalGenerators, checkSchema); +} + CdefaultItem& ProjMgrParser::GetCdefault(void) { return m_cdefault; } @@ -68,3 +73,7 @@ map& ProjMgrParser::GetClayers(void) { map& ProjMgrParser::GetGenericClayers(void) { return m_genericClayers; } + +map& ProjMgrParser::GetGlobalGenerators(void) { + return m_globalGenerators; +} diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index ae9daf02d..d0bb07a0f 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -37,12 +37,14 @@ static const map> { "IAR", {ProjMgrUtils::IAR_ELF_SUFFIX , ProjMgrUtils::IAR_LIB_PREFIX , ProjMgrUtils::IAR_LIB_SUFFIX }}, }; -ProjMgrWorker::ProjMgrWorker(void) : +ProjMgrWorker::ProjMgrWorker(ProjMgrParser* parser, ProjMgrExtGenerator* extGenerator) : m_loadPacksPolicy(LoadPacksPolicy::DEFAULT), m_checkSchema(false), m_verbose(false), m_debug(false), - m_dryRun(false) + m_dryRun(false), + m_parser(parser), + m_extGenerator(extGenerator) { RteCondition::SetVerboseFlags(0); } @@ -57,10 +59,6 @@ ProjMgrWorker::~ProjMgrWorker(void) { } } -void ProjMgrWorker::SetParser(ProjMgrParser* parser) { - m_parser = parser; -} - bool ProjMgrWorker::AddContexts(ProjMgrParser& parser, ContextDesc& descriptor, const string& cprojectFile) { error_code ec; ContextItem context; @@ -1260,6 +1258,7 @@ bool ProjMgrWorker::ProcessDevice(ContextItem& context) { } context.packages.insert({ matchedDevice->GetPackageID(true), matchedDevice->GetPackage() }); + GetDeviceItem(context.device, context.deviceItem); return true; } @@ -1431,6 +1430,22 @@ bool ProjMgrWorker::ProcessComponents(ContextItem& context) { error_code ec; const string& gpdsc = fs::weakly_canonical(generator->GetExpandedGpdsc(context.rteActiveTarget, genDir), ec).generic_string(); context.gpdscs.insert({ gpdsc, {componentId, generatorId, genDir} }); + } else { + // Get external generator id + const string extGenId = matchedComponent->GetGeneratorName(); + if (!extGenId.empty()) { + // check if required global generator is registered + if (!m_extGenerator->CheckGeneratorId(extGenId, componentId)) { + return false; + } + string genDir; + if (!GetExtGeneratorDir(extGenId, context, layer, genDir)) { + return false; + } + // keep track of used generators + m_extGenerator->AddUsedGenerator(extGenId, genDir, context.name); + context.extGenDir[extGenId] = genDir; + } } // Insert matched component into context list @@ -1945,17 +1960,20 @@ void ProjMgrWorker::MergeStringVector(StringVectorCollection& item) { } } -bool ProjMgrWorker::ProcessPrecedences(ContextItem& context) { +bool ProjMgrWorker::ProcessPrecedences(ContextItem& context, bool rerun) { // Notes: defines, includes and misc are additive. All other keywords overwrite previous settings. // The target-type and build-type definitions are additive, but an attempt to // redefine an already existing type results in an error. // The settings of the target-type are processed first; then the settings of the // build-type that potentially overwrite the target-type settings. - if (context.precedences) { + if (!rerun && context.precedences) { return true; } context.precedences = true; + context.components.clear(); + context.componentRequirements.clear(); + context.groups.clear(); // Get content of build and target types if (!GetTypeContent(context)) { @@ -2783,7 +2801,7 @@ void ProjMgrWorker::PrintMissingFilters(void) { } } -bool ProjMgrWorker::ProcessContext(ContextItem& context, bool loadGpdsc, bool resolveDependencies, bool updateRteFiles) { +bool ProjMgrWorker::ProcessContext(ContextItem& context, bool loadGenFiles, bool resolveDependencies, bool updateRteFiles) { if (!LoadPacks(context)) { return false; } @@ -2806,10 +2824,13 @@ bool ProjMgrWorker::ProcessContext(ContextItem& context, bool loadGpdsc, bool re if (!ProcessComponents(context)) { return false; } - if (loadGpdsc) { + if (loadGenFiles) { if (!ProcessGpdsc(context)) { return false; } + if (!ProcessGeneratedLayers(context)) { + return false; + } } if (!ProcessConfigFiles(context)) { return false; @@ -3193,6 +3214,9 @@ bool ProjMgrWorker::ListGenerators(vector& generators) { generatorsSet.insert(id + " (" + generator->GetDescription() + ")"); } } + for (const auto& [id, _] : m_extGenerator->GetUsedGenerators()) { + generatorsSet.insert(id + " (Global Registered Generator)"); + } generators.assign(generatorsSet.begin(), generatorsSet.end()); return true; } @@ -3849,6 +3873,46 @@ bool ProjMgrWorker::GetGeneratorDir(const RteGenerator* generator, ContextItem& const string generatorId = generator->GetID(); genDir.clear(); + // from 'generators' node + if (!GetGeneratorDir(generatorId, context, layer, genDir)) { + return false; + } + + if (!genDir.empty()) { + genDir = RteFsUtils::RelativePath(genDir, context.cproject->directory); + } else { + // original working dir from PDSC + if (!generator->GetWorkingDir().empty()) { + genDir = RteFsUtils::RelativePath(generator->GetExpandedWorkingDir(context.rteActiveTarget), context.cproject->directory); + if (!layer.empty()) { + // adjust genDir if component belongs to layer + genDir = RteFsUtils::RelativePath(fs::path(context.clayers.at(layer)->directory).append(genDir).generic_string(), context.cproject->directory); + } + } else { + // default: $ProjectDir()$/generated/ + genDir = fs::path("generated").append(generatorId).generic_string(); + } + } + return true; +} + +bool ProjMgrWorker::GetExtGeneratorDir(const string& generatorId, ContextItem& context, const string& layer, string& genDir) { + // from 'generators' node + if (!GetGeneratorDir(generatorId, context, layer, genDir)) { + return false; + } + if (genDir.empty()) { + // from global register + genDir = m_extGenerator->GetGlobalGenDir(generatorId); + if (!ProcessSequenceRelative(context, genDir, layer.empty() ? context.cproject->directory : context.clayers.at(layer)->directory)) { + return false; + } + RteFsUtils::NormalizePath(genDir, context.directories.cprj); + } + return true; +} + +bool ProjMgrWorker::GetGeneratorDir(const string& generatorId, ContextItem& context, const string& layer, string& genDir) { // map with GeneratorsItem and base reference (clayer, cproject or csolution directory) const vector> generatorsList = { layer.empty() ? pair() : make_pair(context.clayers.at(layer)->generators, context.clayers.at(layer)->directory), @@ -3864,7 +3928,7 @@ bool ProjMgrWorker::GetGeneratorDir(const RteGenerator* generator, ContextItem& if (!ProcessSequenceRelative(context, genDir, ref)) { return false; } - genDir = RteFsUtils::RelativePath(fs::path(context.directories.cprj).append(genDir).generic_string(), context.cproject->directory); + RteFsUtils::NormalizePath(genDir, context.directories.cprj); break; } } @@ -3877,24 +3941,12 @@ bool ProjMgrWorker::GetGeneratorDir(const RteGenerator* generator, ContextItem& if (!ProcessSequenceRelative(context, genDir, ref)) { return false; } - genDir = RteFsUtils::RelativePath(fs::path(context.directories.cprj).append(genDir).append(generatorId).generic_string(), context.cproject->directory); + genDir = fs::path(genDir).append(generatorId).generic_string(); + RteFsUtils::NormalizePath(genDir, context.directories.cprj); break; } } } - if (genDir.empty()) { - // original working dir from PDSC - if (!generator->GetWorkingDir().empty()) { - genDir = RteFsUtils::RelativePath(generator->GetExpandedWorkingDir(context.rteActiveTarget), context.cproject->directory); - if (!layer.empty()) { - // adjust genDir if component belongs to layer - genDir = RteFsUtils::RelativePath(fs::path(context.clayers.at(layer)->directory).append(genDir).generic_string(), context.cproject->directory); - } - } else { - // default: $ProjectDir()$/generated/ - genDir = fs::path("generated").append(generatorId).generic_string(); - } - } return true; } @@ -3923,3 +3975,128 @@ bool ProjMgrWorker::ListConfigFiles(vector& configFiles) { } return true; } + +bool ProjMgrWorker::ProcessGlobalGenerators(ContextItem* selectedContext, const string& generatorId, + string& projectType, StrVec& siblings) { + + // iterate over contexts with same build and target types + for (auto& [_, context] : m_contexts) { + if ((context.type.build != selectedContext->type.build) || + (context.type.target != selectedContext->type.target)) { + continue; + } + if (!ProcessContext(context, false, true, false)) { + return false; + } + } + const string& genDir = selectedContext->extGenDir[generatorId]; + if (genDir.empty()) { + ProjMgrLogger::Error("generator output directory was not set"); + return false; + } + const auto& contextVec = m_extGenerator->GetUsedGenerators().at(generatorId).at(genDir); + + // classify generator contexts according to device, processor and project name + map> classifiedMap; + for (const auto& contextId : contextVec) { + auto& context = m_contexts[contextId]; + DeviceItem deviceItem; + GetDeviceItem(context.device, deviceItem); + classifiedMap[deviceItem.name][deviceItem.pname][context.cproject->name] = contextId; + } + + // find project-type related contexts + StrVecMap projectTypeMap; + for (const auto& [device, processors] : classifiedMap) { + for (const auto& [processor, projects] : processors) { + for (const auto& [project, context] : projects) { + string type; + if (processors.size() >= 2) { + type = TYPE_MULTI_CORE; + } else { + const auto& trustzone = m_contexts[context].controls.processed.processor.trustzone; + type = trustzone.empty() ? TYPE_SINGLE_CORE : TYPE_TRUSTZONE; + } + projectTypeMap[type].push_back(context); + } + } + } + + // get selected context project-type and siblings + for (const auto& [type, contexts] : projectTypeMap) { + if (find(contexts.begin(), contexts.end(), selectedContext->name) != contexts.end()) { + projectType = type; + siblings = contexts; + return true; + } + } + return false; +} + +bool ProjMgrWorker::ExecuteExtGenerator(std::string& generatorId) { + if (m_selectedContexts.size() != 1) { + ProjMgrLogger::Error("a single context must be specified"); + return false; + } + const string& selectedContextId = m_selectedContexts.front(); + ContextItem* selectedContext = &m_contexts[selectedContextId]; + string projectType; + StrVec siblings; + if (!ProcessGlobalGenerators(selectedContext, generatorId, projectType, siblings)) { + return false; + } + const string& genDir = selectedContext->extGenDir[generatorId]; + vector siblingContexts; + for (const auto& sibling : siblings) { + siblingContexts.push_back(&m_contexts[sibling]); + } + + // Generate cbuild-gen files + if (!ProjMgrYamlEmitter::GenerateCbuildGenIndex(*m_parser, siblingContexts, projectType, genDir)) { + return false; + } + for (const auto& siblingContext : siblingContexts) { + if (!ProjMgrYamlEmitter::GenerateCbuildGen(siblingContext, genDir)) { + return false; + } + } + + // Execute generator command + string runCmd = m_extGenerator->GetGlobalGenRunCmd(generatorId); + RteFsUtils::NormalizePath(runCmd, m_compilerRoot); + runCmd += " " + m_parser->GetCsolution().name + ".cbuild-gen-idx.yml"; + error_code ec; + const auto& workingDir = fs::current_path(ec); + fs::current_path(genDir, ec); + ProjMgrUtils::Result result = ProjMgrUtils::ExecCommand(runCmd); + fs::current_path(workingDir, ec); + ProjMgrLogger::Info("generator '" + generatorId + "' for context '" + selectedContextId + "' reported:\n" + result.first); + if (result.second) { + ProjMgrLogger::Error("executing generator '" + generatorId + "' for context '" + selectedContextId + "' failed"); + return false; + } + return true; +} + +bool ProjMgrWorker::ProcessGeneratedLayers(ContextItem& context) { + ClayerItem cgen; + if (m_extGenerator->GetCgen(context.name, cgen)) { + context.clayers[cgen.path] = &cgen; + if (cgen.packs.size() > 0) { + AddPackRequirements(context, cgen.packs); + if (!LoadAllRelevantPacks() || !LoadPacks(context)) { + return false; + } + } + if (!ProcessPrecedences(context, true)) { + return false; + } + if (!ProcessGroups(context)) { + return false; + } + if (!ProcessComponents(context)) { + return false; + } + } + return true; +} diff --git a/tools/projmgr/src/ProjMgrYamlEmitter.cpp b/tools/projmgr/src/ProjMgrYamlEmitter.cpp index 0a8470a2c..2c8c0ac1c 100644 --- a/tools/projmgr/src/ProjMgrYamlEmitter.cpp +++ b/tools/projmgr/src/ProjMgrYamlEmitter.cpp @@ -30,6 +30,7 @@ class ProjMgrYamlCbuild { private: friend class ProjMgrYamlEmitter; ProjMgrYamlCbuild(YAML::Node node, const vector processedContexts, ProjMgrParser& parser, const string& directory); + ProjMgrYamlCbuild(YAML::Node node, const vector siblings, const string& type, const string& directory); ProjMgrYamlCbuild(YAML::Node node, const ContextItem* context); void SetContextNode(YAML::Node node, const ContextItem* context); void SetComponentsNode(YAML::Node node, const ContextItem* context); @@ -54,6 +55,7 @@ class ProjMgrYamlCbuild { const string FormatPath(const string& original, const string& directory); bool CompareFile(const string& filename, const YAML::Node& rootNode); bool CompareNodes(const YAML::Node& lhs, const YAML::Node& rhs); + bool WriteFile(const string& filename, const YAML::Node& rootNode); }; ProjMgrYamlCbuild::ProjMgrYamlCbuild(YAML::Node node, const vector processedContexts, ProjMgrParser& parser, const string& directory) { @@ -114,8 +116,8 @@ ProjMgrYamlCbuild::ProjMgrYamlCbuild(YAML::Node node, const ContextItem* context void ProjMgrYamlCbuild::SetContextNode(YAML::Node contextNode, const ContextItem* context) { SetNodeValue(contextNode[YAML_GENERATED_BY], ORIGINAL_FILENAME + string(" version ") + VERSION_STRING); - SetNodeValue(contextNode[YAML_SOLUTION], FormatPath(context->csolution->path, context->directories.cprj)); - SetNodeValue(contextNode[YAML_PROJECT], FormatPath(context->cproject->path, context->directories.cprj)); + SetNodeValue(contextNode[YAML_SOLUTION], FormatPath(context->csolution->path, context->directories.cbuild)); + SetNodeValue(contextNode[YAML_PROJECT], FormatPath(context->cproject->path, context->directories.cbuild)); SetNodeValue(contextNode[YAML_CONTEXT], context->name); SetNodeValue(contextNode[YAML_COMPILER], context->compiler); SetNodeValue(contextNode[YAML_BOARD], context->board); @@ -137,7 +139,7 @@ void ProjMgrYamlCbuild::SetContextNode(YAML::Node contextNode, const ContextItem }) { for (auto include : targetIncludes) { RteFsUtils::NormalizePath(include, context->cproject->directory); - ProjMgrUtils::PushBackUniquely(includes, FormatPath(include, context->directories.cprj)); + ProjMgrUtils::PushBackUniquely(includes, FormatPath(include, context->directories.cbuild)); } } SetNodeValue(contextNode[YAML_ADDPATH], includes); @@ -162,7 +164,7 @@ void ProjMgrYamlCbuild::SetComponentsNode(YAML::Node node, const ContextItem* co SetNodeValue(componentNode[YAML_SELECTED_BY], componentItem->component); const string& rteDir = rteComponent->GetAttribute("rtedir"); if (!rteDir.empty()) { - SetNodeValue(componentNode[YAML_OUTPUT_RTEDIR], FormatPath(context->cproject->directory + "/" + rteDir, context->directories.cprj)); + SetNodeValue(componentNode[YAML_OUTPUT_RTEDIR], FormatPath(context->cproject->directory + "/" + rteDir, context->directories.cbuild)); } SetControlsNode(componentNode, context, componentItem->build); SetComponentFilesNode(componentNode[YAML_FILES], context, componentId); @@ -176,7 +178,7 @@ void ProjMgrYamlCbuild::SetComponentFilesNode(YAML::Node node, const ContextItem if (context->componentFiles.find(componentId) != context->componentFiles.end()) { for (const auto& [file, attr, category, language, scope, version] : context->componentFiles.at(componentId)) { YAML::Node fileNode; - SetNodeValue(fileNode[YAML_FILE], FormatPath(file, context->directories.cprj)); + SetNodeValue(fileNode[YAML_FILE], FormatPath(file, context->directories.cbuild)); SetNodeValue(fileNode[YAML_CATEGORY], category); SetNodeValue(fileNode[YAML_ATTR], attr); SetNodeValue(fileNode[YAML_LANGUAGE], language); @@ -192,7 +194,7 @@ void ProjMgrYamlCbuild::SetGeneratorFiles(YAML::Node node, const ContextItem* co YAML::Node filesNode; for (const auto& [file, attr, category, language, scope, version] : context->generatorInputFiles.at(componentId)) { YAML::Node fileNode; - SetNodeValue(fileNode[YAML_FILE], FormatPath(file, context->directories.cprj)); + SetNodeValue(fileNode[YAML_FILE], FormatPath(file, context->directories.cbuild)); SetNodeValue(fileNode[YAML_CATEGORY], category); SetNodeValue(fileNode[YAML_ATTR], attr); SetNodeValue(fileNode[YAML_LANGUAGE], language); @@ -217,8 +219,8 @@ void ProjMgrYamlCbuild::SetGeneratorsNode(YAML::Node node, const ContextItem* co break; } } - SetNodeValue(genNode[YAML_PATH], FormatPath(workingDir, context->directories.cprj)); - SetNodeValue(genNode[YAML_GPDSC], FormatPath(gpdscFile, context->directories.cprj)); + SetNodeValue(genNode[YAML_PATH], FormatPath(workingDir, context->directories.cbuild)); + SetNodeValue(genNode[YAML_GPDSC], FormatPath(gpdscFile, context->directories.cbuild)); for (const string host : {"win", "linux", "mac", "other"}) { YAML::Node commandNode; @@ -227,7 +229,7 @@ void ProjMgrYamlCbuild::SetGeneratorsNode(YAML::Node node, const ContextItem* co const string exe = generator->GetExecutable(context->rteActiveTarget, host); if (exe.empty()) continue; - commandNode[YAML_FILE] = FormatPath(exe, context->directories.cprj); + commandNode[YAML_FILE] = FormatPath(exe, context->directories.cbuild); // Arguments YAML::Node argumentsNode; @@ -252,7 +254,7 @@ void ProjMgrYamlCbuild::SetPacksNode(YAML::Node node, const ContextItem* context for (const auto& [packId, package] : context->packages) { YAML::Node packNode; SetNodeValue(packNode[YAML_PACK], packId); - const string& pdscFilename = FormatPath(package->GetPackageFileName(), context->directories.cprj); + const string& pdscFilename = FormatPath(package->GetPackageFileName(), context->directories.cbuild); SetNodeValue(packNode[YAML_PATH], fs::path(pdscFilename).parent_path().generic_string()); node.push_back(packNode); } @@ -290,7 +292,7 @@ void ProjMgrYamlCbuild::SetConstructedFilesNode(YAML::Node node, const ContextIt const string& filename = context->rteActiveProject->GetProjectPath() + context->rteActiveProject->GetRteHeader(file, context->rteActiveTarget->GetName(), ""); YAML::Node fileNode; - SetNodeValue(fileNode[YAML_FILE], FormatPath(filename, context->directories.cprj)); + SetNodeValue(fileNode[YAML_FILE], FormatPath(filename, context->directories.cbuild)); SetNodeValue(fileNode[YAML_CATEGORY], "preIncludeGlobal"); node.push_back(fileNode); } @@ -301,7 +303,7 @@ void ProjMgrYamlCbuild::SetConstructedFilesNode(YAML::Node node, const ContextIt const auto& rteComponents = context->rteActiveProject->GetProjectPath() + context->rteActiveProject->GetRteComponentsH(context->rteActiveTarget->GetName(), ""); YAML::Node rteComponentsNode; - SetNodeValue(rteComponentsNode[YAML_FILE], FormatPath(rteComponents, context->directories.cprj)); + SetNodeValue(rteComponentsNode[YAML_FILE], FormatPath(rteComponents, context->directories.cbuild)); SetNodeValue(rteComponentsNode[YAML_CATEGORY], "header"); node.push_back(rteComponentsNode); } @@ -340,9 +342,9 @@ void ProjMgrYamlCbuild::SetOutputNode(YAML::Node node, const ContextItem* contex void ProjMgrYamlCbuild::SetLinkerNode(YAML::Node node, const ContextItem* context) { const string script = context->linker.script.empty() ? "" : fs::path(context->linker.script).is_absolute() ? FormatPath(context->linker.script, "") : - FormatPath(context->directories.cprj + "/" + context->linker.script, context->directories.cprj); + FormatPath(context->directories.cprj + "/" + context->linker.script, context->directories.cbuild); const string regions = context->linker.regions.empty() ? "" : - FormatPath(context->directories.cprj + "/" + context->linker.regions, context->directories.cprj); + FormatPath(context->directories.cprj + "/" + context->linker.regions, context->directories.cbuild); SetNodeValue(node[YAML_SCRIPT], script); SetNodeValue(node[YAML_REGIONS], regions); SetDefineNode(node[YAML_DEFINE], context->linker.defines); @@ -387,10 +389,10 @@ void ProjMgrYamlCbuild::SetControlsNode(YAML::Node node, const ContextItem* cont SetDefineNode(node[YAML_DEFINE], controls.defines); SetNodeValue(node[YAML_UNDEFINE], controls.undefines); for (const auto& addpath : controls.addpaths) { - node[YAML_ADDPATH].push_back(FormatPath(context->directories.cprj + "/" + addpath, context->directories.cprj)); + node[YAML_ADDPATH].push_back(FormatPath(context->directories.cprj + "/" + addpath, context->directories.cbuild)); } for (const auto& addpath : controls.delpaths) { - node[YAML_DELPATH].push_back(FormatPath(context->directories.cprj + "/" + addpath, context->directories.cprj)); + node[YAML_DELPATH].push_back(FormatPath(context->directories.cprj + "/" + addpath, context->directories.cbuild)); } } @@ -534,8 +536,14 @@ bool ProjMgrYamlEmitter::GenerateCbuildIndex(ProjMgrParser& parser, const vector YAML::Node rootNode; ProjMgrYamlCbuild cbuild(rootNode[YAML_BUILD_IDX], contexts, parser, directory); + if (!cbuild.WriteFile(filename, rootNode)) { + return false; + } + return true; +} - if (!cbuild.CompareFile(filename, rootNode)) { +bool ProjMgrYamlCbuild::WriteFile(const string& filename, const YAML::Node& rootNode) { + if (!CompareFile(filename, rootNode)) { ofstream fileStream(filename); if (!fileStream) { ProjMgrLogger::Error(filename, "file cannot be written"); @@ -548,8 +556,7 @@ bool ProjMgrYamlEmitter::GenerateCbuildIndex(ProjMgrParser& parser, const vector fileStream << flush; fileStream.close(); ProjMgrLogger::Info(filename, "file generated successfully"); - } - else { + } else { ProjMgrLogger::Info(filename, "file is already up-to-date"); } return true; @@ -564,25 +571,61 @@ bool ProjMgrYamlEmitter::GenerateCbuild(ContextItem* context) { context->rteActiveTarget->SetGeneratorInputFile(filename); YAML::Node rootNode; + context->directories.cbuild = context->directories.cprj; ProjMgrYamlCbuild cbuild(rootNode[YAML_BUILD], context); + if (!cbuild.WriteFile(filename, rootNode)) { + return false; + } + return true; +} - // Compare yaml contents - if (!cbuild.CompareFile(filename, rootNode)) { - ofstream fileStream(filename); - if (!fileStream) { - ProjMgrLogger::Error(filename, "file cannot be written"); - return false; - } - YAML::Emitter emitter; - emitter << rootNode; - fileStream << emitter.c_str(); - fileStream << endl; - fileStream << flush; - fileStream.close(); - ProjMgrLogger::Info(filename, "file generated successfully"); +bool ProjMgrYamlEmitter::GenerateCbuildGenIndex(ProjMgrParser& parser, const vector siblings, const string& type, const string& outputDir) { + // generate cbuild-idx.yml + RteFsUtils::CreateDirectories(outputDir); + const string& filename = outputDir + "/" + parser.GetCsolution().name + ".cbuild-gen-idx.yml"; + + YAML::Node rootNode; + ProjMgrYamlCbuild cbuild(rootNode[YAML_BUILD_GEN_IDX], siblings, type, outputDir); + if (!cbuild.WriteFile(filename, rootNode)) { + return false; } - else { - ProjMgrLogger::Info(filename, "file is already up-to-date"); + return true; +} + +ProjMgrYamlCbuild::ProjMgrYamlCbuild(YAML::Node node, const vector siblings, const string& type, const string& directory) { + error_code ec; + SetNodeValue(node[YAML_GENERATED_BY], ORIGINAL_FILENAME + string(" version ") + VERSION_STRING); + const auto& context = siblings.front(); + const auto& generator = context->extGenDir.begin(); + YAML::Node generatorNode; + SetNodeValue(generatorNode[YAML_ID], generator->first); + SetNodeValue(generatorNode[YAML_DEVICE], context->deviceItem.name); + SetNodeValue(generatorNode[YAML_BOARD], context->board); + SetNodeValue(generatorNode[YAML_PROJECT_TYPE], type); + for (const auto& sibling : siblings) { + YAML::Node cbuildGenNode; + SetNodeValue(cbuildGenNode[YAML_CBUILD_GEN], sibling->name + ".cbuild-gen.yml"); + SetNodeValue(cbuildGenNode[YAML_PROJECT], sibling->cproject->name); + SetNodeValue(cbuildGenNode[YAML_CONFIGURATION], (sibling->type.build.empty() ? "" : + ("." + sibling->type.build)) + "+" + sibling->type.target); + SetNodeValue(cbuildGenNode[YAML_FORPROJECTPART], + (type == TYPE_MULTI_CORE ? sibling->deviceItem.pname : + (type == TYPE_TRUSTZONE ? sibling->controls.processed.processor.trustzone : ""))); + generatorNode[YAML_CBUILD_GENS].push_back(cbuildGenNode); + } + node[YAML_GENERATORS].push_back(generatorNode); +} + +bool ProjMgrYamlEmitter::GenerateCbuildGen(ContextItem* context, const string& output) { + // generate cbuild-gen.yml for each context + RteFsUtils::CreateDirectories(output); + const string& filename = fs::path(output).append(context->name + ".cbuild-gen.yml").generic_string(); + + YAML::Node rootNode; + context->directories.cbuild = output; + ProjMgrYamlCbuild cbuild(rootNode[YAML_BUILD_GEN], context); + if (!cbuild.WriteFile(filename, rootNode)) { + return false; } return true; } diff --git a/tools/projmgr/src/ProjMgrYamlParser.cpp b/tools/projmgr/src/ProjMgrYamlParser.cpp index 488dd7984..7d367cd6b 100644 --- a/tools/projmgr/src/ProjMgrYamlParser.cpp +++ b/tools/projmgr/src/ProjMgrYamlParser.cpp @@ -225,6 +225,44 @@ bool ProjMgrYamlParser::ParseClayer(const string& input, return true; } +bool ProjMgrYamlParser::ParseGlobalGenerator(const string& input, + std::map& generators, bool checkSchema) { + + try { + // TODO: Validate file schema + //f (checkSchema && + // !ProjMgrYamlSchemaChecker().Validate( + // input, ProjMgrYamlSchemaChecker::FileType::GENERATOR)) { + // return false; + // + + const YAML::Node& root = YAML::LoadFile(input); + //if (!ValidateClayer(input, root)) { + // return false; + //} + + const YAML::Node& generatorNode = root[YAML_GENERATOR]; + for (const auto& generatorEntry : generatorNode) { + GlobalGeneratorItem generator; + map generatorChildren = { + {YAML_ID, generator.id}, + {YAML_DOWNLOAD_URL, generator.downloadUrl}, + {YAML_RUN, generator.run}, + }; + for (const auto& item : generatorChildren) { + ParseString(generatorEntry, item.first, item.second); + } + ParsePortablePath(generatorEntry, input, YAML_OUTPUT, generator.output, false); + generators[generator.id] = generator; + } + } + catch (YAML::Exception& e) { + ProjMgrLogger::Error(input, e.mark.line + 1, e.mark.column + 1, e.msg); + return false; + } + return true; +} + // EnsurePortability checks the presence of backslash, case inconsistency and absolute path // It clears the string 'value' when it is an absolute path void ProjMgrYamlParser::EnsurePortability(const string& file, const YAML::Mark& mark, const string& key, string& value, bool checkExist) { diff --git a/tools/projmgr/test/data/ExternalGenerator/bridge.sh b/tools/projmgr/test/data/ExternalGenerator/bridge.sh new file mode 100755 index 000000000..1289c7252 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/bridge.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "bridge tool argument: $1" +exit 0 diff --git a/tools/projmgr/test/data/ExternalGenerator/extgen.csolution.yml b/tools/projmgr/test/data/ExternalGenerator/extgen.csolution.yml new file mode 100644 index 000000000..915222a9e --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/extgen.csolution.yml @@ -0,0 +1,30 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + compiler: AC6 + + packs: + - pack: ARM::RteTestGenerator@0.1.0 + - pack: ARM::RteTest_DFP@0.2.0 + + target-types: + - type: CM0 + device: RteTestGen_ARMCM0 + - type: MultiCore + device: RteTest_ARMCM0_Dual + + build-types: + - type: Debug + - type: Release + + projects: + - project: single/single-core.cproject.yml + for-context: +CM0 + - project: tz_s/s.cproject.yml + for-context: +CM0 + - project: tz_ns/ns.cproject.yml + for-context: +CM0 + - project: multi_0/core0.cproject.yml + for-context: +MultiCore + - project: multi_1/core1.cproject.yml + for-context: +MultiCore diff --git a/tools/projmgr/test/data/ExternalGenerator/global.generator.yml b/tools/projmgr/test/data/ExternalGenerator/global.generator.yml new file mode 100644 index 000000000..0a0a3322c --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/global.generator.yml @@ -0,0 +1,5 @@ +generator: + - id: RteTestExternalGenerator + download-url: https://raw.githubusercontent.com/Open-CMSIS-Pack + run: ./bridge.sh + output: $SolutionDir()$/generated/$TargetType$ diff --git a/tools/projmgr/test/data/ExternalGenerator/multi_0/core0.cproject.yml b/tools/projmgr/test/data/ExternalGenerator/multi_0/core0.cproject.yml new file mode 100644 index 000000000..2cc80cc18 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/multi_0/core0.cproject.yml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + device: :cm0_core0 + components: + - component: RteTestGenerator:Check Global Generator diff --git a/tools/projmgr/test/data/ExternalGenerator/multi_1/core1.cproject.yml b/tools/projmgr/test/data/ExternalGenerator/multi_1/core1.cproject.yml new file mode 100644 index 000000000..db81801cb --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/multi_1/core1.cproject.yml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + device: :cm0_core1 + components: + - component: RteTestGenerator:Check Global Generator diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core0.Debug+MultiCore.cbuild-gen.yml b/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core0.Debug+MultiCore.cbuild-gen.yml new file mode 100644 index 000000000..18d808f65 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core0.Debug+MultiCore.cbuild-gen.yml @@ -0,0 +1,47 @@ +build-gen: + generated-by: csolution version 0.0.0+gf14e09a4 + solution: ../../extgen.csolution.yml + project: ../../multi_0/core0.cproject.yml + context: core0.Debug+MultiCore + compiler: AC6 + device: RteTest_ARMCM0_Dual:cm0_core0 + processor: + fpu: off + packs: + - pack: ARM::RteTestGenerator@0.1.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTestGenerator/0.1.0 + - pack: ARM::RteTest_DFP@0.2.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTest_DFP/0.2.0 + define: + - ARMCM0 + - _RTE_ + add-path: + - ../../multi_0/RTE/_Debug_MultiCore + - ${CMSIS_PACK_ROOT}/ARM/RteTest_DFP/0.2.0/Device/ARM/ARMCM0/Include + output-dirs: + intdir: ../tmp/core0/MultiCore/Debug + outdir: ../out/core0/MultiCore/Debug + rtedir: RTE + output: + - type: elf + file: core0.axf + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + from-pack: ARM::RteTestGenerator@0.1.0 + selected-by: RteTestGenerator:Check Global Generator + linker: + script: ${CMSIS_COMPILER_ROOT}/ac6_linker_script.sct + regions: ../../multi_0/RTE/Device/RteTest_ARMCM0_Dual_cm0_core0/regions_RteTest_ARMCM0_Dual_cm0_core0.h + constructed-files: + - file: ../../multi_0/RTE/_Debug_MultiCore/RTE_Components.h + category: header + licenses: + - license: + packs: + - pack: ARM::RteTestGenerator@0.1.0 + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + - license: + license-agreement: ${CMSIS_PACK_ROOT}/ARM/RteTest_DFP/0.2.0/Doc/license.txt + packs: + - pack: ARM::RteTest_DFP@0.2.0 diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core1.Debug+MultiCore.cbuild-gen.yml b/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core1.Debug+MultiCore.cbuild-gen.yml new file mode 100644 index 000000000..498a5edaa --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/core1.Debug+MultiCore.cbuild-gen.yml @@ -0,0 +1,47 @@ +build-gen: + generated-by: csolution version 0.0.0+gf14e09a4 + solution: ../../extgen.csolution.yml + project: ../../multi_1/core1.cproject.yml + context: core1.Debug+MultiCore + compiler: AC6 + device: RteTest_ARMCM0_Dual:cm0_core1 + processor: + fpu: off + packs: + - pack: ARM::RteTestGenerator@0.1.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTestGenerator/0.1.0 + - pack: ARM::RteTest_DFP@0.2.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTest_DFP/0.2.0 + define: + - ARMCM0 + - _RTE_ + add-path: + - ../../multi_1/RTE/_Debug_MultiCore + - ${CMSIS_PACK_ROOT}/ARM/RteTest_DFP/0.2.0/Device/ARM/ARMCM0/Include + output-dirs: + intdir: ../tmp/core1/MultiCore/Debug + outdir: ../out/core1/MultiCore/Debug + rtedir: RTE + output: + - type: elf + file: core1.axf + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + from-pack: ARM::RteTestGenerator@0.1.0 + selected-by: RteTestGenerator:Check Global Generator + linker: + script: ${CMSIS_COMPILER_ROOT}/ac6_linker_script.sct + regions: ../../multi_1/RTE/Device/RteTest_ARMCM0_Dual_cm0_core1/regions_RteTest_ARMCM0_Dual_cm0_core1.h + constructed-files: + - file: ../../multi_1/RTE/_Debug_MultiCore/RTE_Components.h + category: header + licenses: + - license: + packs: + - pack: ARM::RteTestGenerator@0.1.0 + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + - license: + license-agreement: ${CMSIS_PACK_ROOT}/ARM/RteTest_DFP/0.2.0/Doc/license.txt + packs: + - pack: ARM::RteTest_DFP@0.2.0 diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/extgen.cbuild-gen-idx.yml b/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/extgen.cbuild-gen-idx.yml new file mode 100644 index 000000000..a11378e93 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/MultiCore/extgen.cbuild-gen-idx.yml @@ -0,0 +1,15 @@ +build-gen-idx: + generated-by: csolution version 0.0.0+gf14e09a4 + generators: + - id: RteTestExternalGenerator + device: RteTest_ARMCM0_Dual + project-type: multi-core + cbuild-gens: + - cbuild-gen: core0.Debug+MultiCore.cbuild-gen.yml + project: core0 + configuration: .Debug+MultiCore + for-project-part: cm0_core0 + - cbuild-gen: core1.Debug+MultiCore.cbuild-gen.yml + project: core1 + configuration: .Debug+MultiCore + for-project-part: cm0_core1 diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/extgen.cbuild-gen-idx.yml b/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/extgen.cbuild-gen-idx.yml new file mode 100644 index 000000000..4c8d63ab5 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/extgen.cbuild-gen-idx.yml @@ -0,0 +1,10 @@ +build-gen-idx: + generated-by: csolution version 0.0.0+gf14e09a4 + generators: + - id: RteTestExternalGenerator + device: RteTestGen_ARMCM0 + project-type: single-core + cbuild-gens: + - cbuild-gen: single-core.Debug+CM0.cbuild-gen.yml + project: single-core + configuration: .Debug+CM0 diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild-gen.yml b/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild-gen.yml new file mode 100644 index 000000000..59cb28251 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild-gen.yml @@ -0,0 +1,42 @@ +build-gen: + generated-by: csolution version 0.0.0+gf14e09a4 + solution: ../../extgen.csolution.yml + project: ../single-core.cproject.yml + context: single-core.Debug+CM0 + compiler: AC6 + device: RteTestGen_ARMCM0 + packs: + - pack: ARM::RteTestGenerator@0.1.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTestGenerator/0.1.0 + define: + - _RTE_ + add-path: + - ../RTE/_Debug_CM0 + output-dirs: + intdir: ../tmp/single-core/CM0/Debug + outdir: ../out/single-core/CM0/Debug + rtedir: RTE + output: + - type: elf + file: single-core.axf + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + from-pack: ARM::RteTestGenerator@0.1.0 + selected-by: RteTestGenerator:Check Global Generator + linker: + script: ${CMSIS_COMPILER_ROOT}/ac6_linker_script.sct + regions: ../RTE/Device/RteTestGen_ARMCM0/regions_RteTestGen_ARMCM0.h + groups: + - group: sources + files: + - file: main.c + category: sourceC + constructed-files: + - file: ../RTE/_Debug_CM0/RTE_Components.h + category: header + licenses: + - license: + packs: + - pack: ARM::RteTestGenerator@0.1.0 + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild.yml b/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild.yml new file mode 100644 index 000000000..076e4bf48 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild.yml @@ -0,0 +1,80 @@ +build: + generated-by: csolution version 0.0.0+gf14e09a4 + solution: ../extgen.csolution.yml + project: single-core.cproject.yml + context: single-core.Debug+CM0 + compiler: AC6 + device: RteTestGen_ARMCM0 + packs: + - pack: ARM::RteTest@0.1.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTest/0.1.0 + - pack: ARM::RteTestGenerator@0.1.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTestGenerator/0.1.0 + define: + - _RTE_ + add-path: + - RTE/_Debug_CM0 + - generated/RTE/RteTest + - ${CMSIS_PACK_ROOT}/ARM/RteTest/0.1.0/GlobalLevel + - ${CMSIS_PACK_ROOT}/ARM/RteTest/0.1.0/Include + output-dirs: + intdir: ../../tmp/single-core/CM0/Debug + outdir: ../../out/single-core/CM0/Debug + rtedir: RTE + output: + - type: elf + file: single-core.axf + components: + - component: ARM::RteTest:GlobalLevel@0.0.2 + from-pack: ARM::RteTest@0.1.0 + selected-by: RteTest:GlobalLevel + files: + - file: ${CMSIS_PACK_ROOT}/ARM/RteTest/0.1.0/GlobalLevel/GlobalLevel.c + category: sourceC + - file: ${CMSIS_PACK_ROOT}/ARM/RteTest/0.1.0/GlobalLevel/GlobalLevel.h + category: preIncludeGlobal + version: 0.0.2 + - file: generated/RTE/RteTest/GlobalLevelConfig.h + category: preIncludeGlobal + attr: config + version: 0.0.2 + - file: generated/RTE/RteTest/Config/ConfigInclude.h + category: header + attr: config + version: 0.0.2 + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + from-pack: ARM::RteTestGenerator@0.1.0 + selected-by: RteTestGenerator:Check Global Generator + linker: + script: ${CMSIS_COMPILER_ROOT}/ac6_linker_script.sct + regions: RTE/Device/RteTestGen_ARMCM0/regions_RteTestGen_ARMCM0.h + groups: + - group: sources + files: + - file: main.c + category: sourceC + - group: generated sources + files: + - file: generated/generated.c + category: sourceC + constructed-files: + - file: RTE/_Debug_CM0/Pre_Include_Global.h + category: preIncludeGlobal + - file: RTE/_Debug_CM0/RTE_Components.h + category: header + licenses: + - license: + packs: + - pack: ARM::RteTestGenerator@0.1.0 + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + - license: BSD-3-Clause + packs: + - pack: ARM::RteTest@0.1.0 + components: + - component: ARM::RteTest:GlobalLevel@0.0.2 + - license: MIT + packs: + - pack: ARM::RteTest@0.1.0 + components: + - component: ARM::RteTest:GlobalLevel@0.0.2 diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/extgen.cbuild-gen-idx.yml b/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/extgen.cbuild-gen-idx.yml new file mode 100644 index 000000000..5c35e963f --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/extgen.cbuild-gen-idx.yml @@ -0,0 +1,15 @@ +build-gen-idx: + generated-by: csolution version 0.0.0+gf14e09a4 + generators: + - id: RteTestExternalGenerator + device: RteTestGen_ARMCM0 + project-type: trustzone + cbuild-gens: + - cbuild-gen: ns.Debug+CM0.cbuild-gen.yml + project: ns + configuration: .Debug+CM0 + for-project-part: non-secure + - cbuild-gen: s.Debug+CM0.cbuild-gen.yml + project: s + configuration: .Debug+CM0 + for-project-part: secure diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/ns.Debug+CM0.cbuild-gen.yml b/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/ns.Debug+CM0.cbuild-gen.yml new file mode 100644 index 000000000..db1d6ba92 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/ns.Debug+CM0.cbuild-gen.yml @@ -0,0 +1,39 @@ +build-gen: + generated-by: csolution version 0.0.0+gf14e09a4 + solution: ../../extgen.csolution.yml + project: ../../tz_ns/ns.cproject.yml + context: ns.Debug+CM0 + compiler: AC6 + device: RteTestGen_ARMCM0 + processor: + trustzone: non-secure + packs: + - pack: ARM::RteTestGenerator@0.1.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTestGenerator/0.1.0 + define: + - _RTE_ + add-path: + - ../../tz_ns/RTE/_Debug_CM0 + output-dirs: + intdir: ../tmp/ns/CM0/Debug + outdir: ../out/ns/CM0/Debug + rtedir: RTE + output: + - type: elf + file: ns.axf + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + from-pack: ARM::RteTestGenerator@0.1.0 + selected-by: RteTestGenerator:Check Global Generator + linker: + script: ${CMSIS_COMPILER_ROOT}/ac6_linker_script.sct + regions: ../../tz_ns/RTE/Device/RteTestGen_ARMCM0/regions_RteTestGen_ARMCM0.h + constructed-files: + - file: ../../tz_ns/RTE/_Debug_CM0/RTE_Components.h + category: header + licenses: + - license: + packs: + - pack: ARM::RteTestGenerator@0.1.0 + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 diff --git a/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/s.Debug+CM0.cbuild-gen.yml b/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/s.Debug+CM0.cbuild-gen.yml new file mode 100644 index 000000000..19d71b70b --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/ref/TrustZone/s.Debug+CM0.cbuild-gen.yml @@ -0,0 +1,41 @@ +build-gen: + generated-by: csolution version 0.0.0+gf14e09a4 + solution: ../../extgen.csolution.yml + project: ../../tz_s/s.cproject.yml + context: s.Debug+CM0 + compiler: AC6 + device: RteTestGen_ARMCM0 + processor: + trustzone: secure + packs: + - pack: ARM::RteTestGenerator@0.1.0 + path: ${CMSIS_PACK_ROOT}/ARM/RteTestGenerator/0.1.0 + define: + - _RTE_ + add-path: + - ../../tz_s/RTE/_Debug_CM0 + output-dirs: + intdir: ../tmp/s/CM0/Debug + outdir: ../out/s/CM0/Debug + rtedir: RTE + output: + - type: elf + file: s.axf + - type: cmse-lib + file: s_CMSE_Lib.o + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 + from-pack: ARM::RteTestGenerator@0.1.0 + selected-by: RteTestGenerator:Check Global Generator + linker: + script: ${CMSIS_COMPILER_ROOT}/ac6_linker_script.sct + regions: ../../tz_s/RTE/Device/RteTestGen_ARMCM0/regions_RteTestGen_ARMCM0.h + constructed-files: + - file: ../../tz_s/RTE/_Debug_CM0/RTE_Components.h + category: header + licenses: + - license: + packs: + - pack: ARM::RteTestGenerator@0.1.0 + components: + - component: ARM::RteTestGenerator:Check Global Generator@0.9.0 diff --git a/tools/projmgr/test/data/ExternalGenerator/single/generated/generated.c b/tools/projmgr/test/data/ExternalGenerator/single/generated/generated.c new file mode 100644 index 000000000..72aaaf4cc --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/single/generated/generated.c @@ -0,0 +1 @@ +// generated.c diff --git a/tools/projmgr/test/data/ExternalGenerator/single/generated/single-core.cgen.yml b/tools/projmgr/test/data/ExternalGenerator/single/generated/single-core.cgen.yml new file mode 100644 index 000000000..2dc44fa78 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/single/generated/single-core.cgen.yml @@ -0,0 +1,14 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/clayer.schema.json + +layer: + + packs: + - pack: ARM::RteTest@0.1.0 + + components: + - component: RteTest:GlobalLevel + + groups: + - group: generated sources + files: + - file: generated.c diff --git a/tools/projmgr/test/data/ExternalGenerator/single/main.c b/tools/projmgr/test/data/ExternalGenerator/single/main.c new file mode 100644 index 000000000..99b684458 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/single/main.c @@ -0,0 +1 @@ +// main.c diff --git a/tools/projmgr/test/data/ExternalGenerator/single/single-core.cproject.yml b/tools/projmgr/test/data/ExternalGenerator/single/single-core.cproject.yml new file mode 100644 index 000000000..012352290 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/single/single-core.cproject.yml @@ -0,0 +1,16 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + components: + - component: RteTestGenerator:Check Global Generator + + groups: + - group: sources + files: + - file: main.c + + generators: + options: + - generator: RteTestExternalGenerator + path: $ProjectDir()$/generated/ + diff --git a/tools/projmgr/test/data/ExternalGenerator/tz_ns/ns.cproject.yml b/tools/projmgr/test/data/ExternalGenerator/tz_ns/ns.cproject.yml new file mode 100644 index 000000000..bbf19781a --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/tz_ns/ns.cproject.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + processor: + trustzone: non-secure + components: + - component: RteTestGenerator:Check Global Generator diff --git a/tools/projmgr/test/data/ExternalGenerator/tz_s/s.cproject.yml b/tools/projmgr/test/data/ExternalGenerator/tz_s/s.cproject.yml new file mode 100644 index 000000000..241d3e162 --- /dev/null +++ b/tools/projmgr/test/data/ExternalGenerator/tz_s/s.cproject.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + processor: + trustzone: secure + components: + - component: RteTestGenerator:Check Global Generator diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 0021bb7c0..8ee6d1dcb 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -3851,3 +3851,64 @@ warning csolution: compiler 'Ac6' is not supported\n\ auto errStr = streamRedirect.GetErrorString(); EXPECT_TRUE(errStr.find(expected) != string::npos); } + +TEST_F(ProjMgrUnitTests, ExternalGenerator) { + const string& srcGlobalGenerator = testinput_folder + "/ExternalGenerator/global.generator.yml"; + const string& dstGlobalGenerator = testcmsiscompiler_folder + "/global.generator.yml"; + RteFsUtils::CopyCheckFile(srcGlobalGenerator, dstGlobalGenerator, false); + + const string& srcBridgeTool = testinput_folder + "/ExternalGenerator/bridge.sh"; + const string& dstBridgeTool = testcmsiscompiler_folder + "/bridge.sh"; + RteFsUtils::CopyCheckFile(srcBridgeTool, dstBridgeTool, false); + + char* argv[7]; + const string& csolution = testinput_folder + "/ExternalGenerator/extgen.csolution.yml"; + argv[1] = (char*)csolution.c_str(); + argv[2] = (char*)"list"; + argv[3] = (char*)"generators"; + EXPECT_EQ(0, RunProjMgr(4, argv, 0)); + + argv[1] = (char*)csolution.c_str(); + argv[2] = (char*)"run"; + argv[3] = (char*)"-g"; + argv[4] = (char*)"RteTestExternalGenerator"; + argv[5] = (char*)"-c"; + argv[6] = (char*)"core0.Debug+MultiCore"; + EXPECT_EQ(0, RunProjMgr(7, argv, 0)); + + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/generated/MultiCore/extgen.cbuild-gen-idx.yml", + testinput_folder + "/ExternalGenerator/ref/MultiCore/extgen.cbuild-gen-idx.yml"); + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/generated/MultiCore/core0.Debug+MultiCore.cbuild-gen.yml", + testinput_folder + "/ExternalGenerator/ref/MultiCore/core0.Debug+MultiCore.cbuild-gen.yml"); + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/generated/MultiCore/core1.Debug+MultiCore.cbuild-gen.yml", + testinput_folder + "/ExternalGenerator/ref/MultiCore/core1.Debug+MultiCore.cbuild-gen.yml"); + + argv[6] = (char*)"single-core.Debug+CM0"; + EXPECT_EQ(0, RunProjMgr(7, argv, 0)); + + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/single/generated/extgen.cbuild-gen-idx.yml", + testinput_folder + "/ExternalGenerator/ref/SingleCore/extgen.cbuild-gen-idx.yml"); + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/single/generated/single-core.Debug+CM0.cbuild-gen.yml", + testinput_folder + "/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild-gen.yml"); + + argv[6] = (char*)"ns.Debug+CM0"; + EXPECT_EQ(0, RunProjMgr(7, argv, 0)); + + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/generated/CM0/extgen.cbuild-gen-idx.yml", + testinput_folder + "/ExternalGenerator/ref/TrustZone/extgen.cbuild-gen-idx.yml"); + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/generated/CM0/ns.Debug+CM0.cbuild-gen.yml", + testinput_folder + "/ExternalGenerator/ref/TrustZone/ns.Debug+CM0.cbuild-gen.yml"); + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/generated/CM0/s.Debug+CM0.cbuild-gen.yml", + testinput_folder + "/ExternalGenerator/ref/TrustZone/s.Debug+CM0.cbuild-gen.yml"); + + argv[2] = (char*)"convert"; + argv[3] = (char*)"-c"; + argv[4] = (char*)"single-core.Debug+CM0"; + EXPECT_EQ(0, RunProjMgr(5, argv, 0)); + + ProjMgrTestEnv::CompareFile(testinput_folder + "/ExternalGenerator/single/single-core.Debug+CM0.cbuild.yml", + testinput_folder + "/ExternalGenerator/ref/SingleCore/single-core.Debug+CM0.cbuild.yml"); + + RteFsUtils::RemoveFile(dstGlobalGenerator); + RteFsUtils::RemoveFile(dstBridgeTool); +} diff --git a/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp b/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp index c023d04ba..69bb00195 100644 --- a/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp @@ -17,7 +17,7 @@ using namespace std; class ProjMgrWorkerUnitTests : public ProjMgrWorker, public ::testing::Test { protected: - ProjMgrWorkerUnitTests() {} + ProjMgrWorkerUnitTests() : ProjMgrWorker(nullptr, nullptr) {} virtual ~ProjMgrWorkerUnitTests() {} void SetCsolutionPacks(CsolutionItem* csolution, std::vector packs, std::string targetType);